summaryrefslogtreecommitdiff
path: root/packages/cli
diff options
context:
space:
mode:
Diffstat (limited to 'packages/cli')
-rw-r--r--packages/cli/src/nonInteractiveCli.ts2
-rw-r--r--packages/cli/src/ui/hooks/useGeminiStream.test.tsx7
-rw-r--r--packages/cli/src/ui/hooks/useGeminiStream.ts2
-rw-r--r--packages/cli/src/ui/utils/errorParsing.test.ts378
-rw-r--r--packages/cli/src/ui/utils/errorParsing.ts164
5 files changed, 4 insertions, 549 deletions
diff --git a/packages/cli/src/nonInteractiveCli.ts b/packages/cli/src/nonInteractiveCli.ts
index c237e56b..f2efe8fc 100644
--- a/packages/cli/src/nonInteractiveCli.ts
+++ b/packages/cli/src/nonInteractiveCli.ts
@@ -13,10 +13,10 @@ import {
isTelemetrySdkInitialized,
GeminiEventType,
ToolErrorType,
+ parseAndFormatApiError,
} from '@google/gemini-cli-core';
import { Content, Part, FunctionCall } from '@google/genai';
-import { parseAndFormatApiError } from './ui/utils/errorParsing.js';
import { ConsolePatcher } from './ui/utils/ConsolePatcher.js';
export async function runNonInteractive(
diff --git a/packages/cli/src/ui/hooks/useGeminiStream.test.tsx b/packages/cli/src/ui/hooks/useGeminiStream.test.tsx
index 37d63e9a..9eed0912 100644
--- a/packages/cli/src/ui/hooks/useGeminiStream.test.tsx
+++ b/packages/cli/src/ui/hooks/useGeminiStream.test.tsx
@@ -51,6 +51,7 @@ const MockedGeminiClientClass = vi.hoisted(() =>
const MockedUserPromptEvent = vi.hoisted(() =>
vi.fn().mockImplementation(() => {}),
);
+const mockParseAndFormatApiError = vi.hoisted(() => vi.fn());
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
const actualCoreModule = (await importOriginal()) as any;
@@ -59,6 +60,7 @@ vi.mock('@google/gemini-cli-core', async (importOriginal) => {
GitService: vi.fn(),
GeminiClient: MockedGeminiClientClass,
UserPromptEvent: MockedUserPromptEvent,
+ parseAndFormatApiError: mockParseAndFormatApiError,
};
});
@@ -127,11 +129,6 @@ vi.mock('./slashCommandProcessor.js', () => ({
handleSlashCommand: vi.fn().mockReturnValue(false),
}));
-const mockParseAndFormatApiError = vi.hoisted(() => vi.fn());
-vi.mock('../utils/errorParsing.js', () => ({
- parseAndFormatApiError: mockParseAndFormatApiError,
-}));
-
// --- END MOCKS ---
describe('mergePartListUnions', () => {
diff --git a/packages/cli/src/ui/hooks/useGeminiStream.ts b/packages/cli/src/ui/hooks/useGeminiStream.ts
index 6f3cb4fd..99b727b6 100644
--- a/packages/cli/src/ui/hooks/useGeminiStream.ts
+++ b/packages/cli/src/ui/hooks/useGeminiStream.ts
@@ -25,6 +25,7 @@ import {
UnauthorizedError,
UserPromptEvent,
DEFAULT_GEMINI_FLASH_MODEL,
+ parseAndFormatApiError,
} from '@google/gemini-cli-core';
import { type Part, type PartListUnion, FinishReason } from '@google/genai';
import {
@@ -37,7 +38,6 @@ import {
ToolCallStatus,
} from '../types.js';
import { isAtCommand } from '../utils/commandUtils.js';
-import { parseAndFormatApiError } from '../utils/errorParsing.js';
import { useShellCommandProcessor } from './shellCommandProcessor.js';
import { handleAtCommand } from './atCommandProcessor.js';
import { findLastSafeSplitPoint } from '../utils/markdownUtilities.js';
diff --git a/packages/cli/src/ui/utils/errorParsing.test.ts b/packages/cli/src/ui/utils/errorParsing.test.ts
deleted file mode 100644
index 770dffad..00000000
--- a/packages/cli/src/ui/utils/errorParsing.test.ts
+++ /dev/null
@@ -1,378 +0,0 @@
-/**
- * @license
- * Copyright 2025 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import { describe, it, expect } from 'vitest';
-import { parseAndFormatApiError } from './errorParsing.js';
-import {
- AuthType,
- UserTierId,
- DEFAULT_GEMINI_FLASH_MODEL,
- isProQuotaExceededError,
-} from '@google/gemini-cli-core';
-
-describe('parseAndFormatApiError', () => {
- const _enterpriseMessage =
- 'upgrade to a Gemini Code Assist Standard or Enterprise plan with higher limits';
- const vertexMessage = 'request a quota increase through Vertex';
- const geminiMessage = 'request a quota increase through AI Studio';
-
- it('should format a valid API error JSON', () => {
- const errorMessage =
- 'got status: 400 Bad Request. {"error":{"code":400,"message":"API key not valid. Please pass a valid API key.","status":"INVALID_ARGUMENT"}}';
- const expected =
- '[API Error: API key not valid. Please pass a valid API key. (Status: INVALID_ARGUMENT)]';
- expect(parseAndFormatApiError(errorMessage)).toBe(expected);
- });
-
- it('should format a 429 API error with the default message', () => {
- const errorMessage =
- 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Rate limit exceeded","status":"RESOURCE_EXHAUSTED"}}';
- const result = parseAndFormatApiError(
- errorMessage,
- undefined,
- undefined,
- 'gemini-2.5-pro',
- DEFAULT_GEMINI_FLASH_MODEL,
- );
- expect(result).toContain('[API Error: Rate limit exceeded');
- expect(result).toContain(
- 'Possible quota limitations in place or slow response times detected. Switching to the gemini-2.5-flash model',
- );
- });
-
- it('should format a 429 API error with the personal message', () => {
- const errorMessage =
- 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Rate limit exceeded","status":"RESOURCE_EXHAUSTED"}}';
- const result = parseAndFormatApiError(
- errorMessage,
- AuthType.LOGIN_WITH_GOOGLE,
- undefined,
- 'gemini-2.5-pro',
- DEFAULT_GEMINI_FLASH_MODEL,
- );
- expect(result).toContain('[API Error: Rate limit exceeded');
- expect(result).toContain(
- 'Possible quota limitations in place or slow response times detected. Switching to the gemini-2.5-flash model',
- );
- });
-
- it('should format a 429 API error with the vertex message', () => {
- const errorMessage =
- 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Rate limit exceeded","status":"RESOURCE_EXHAUSTED"}}';
- const result = parseAndFormatApiError(errorMessage, AuthType.USE_VERTEX_AI);
- expect(result).toContain('[API Error: Rate limit exceeded');
- expect(result).toContain(vertexMessage);
- });
-
- it('should return the original message if it is not a JSON error', () => {
- const errorMessage = 'This is a plain old error message';
- expect(parseAndFormatApiError(errorMessage)).toBe(
- `[API Error: ${errorMessage}]`,
- );
- });
-
- it('should return the original message for malformed JSON', () => {
- const errorMessage = '[Stream Error: {"error": "malformed}';
- expect(parseAndFormatApiError(errorMessage)).toBe(
- `[API Error: ${errorMessage}]`,
- );
- });
-
- it('should handle JSON that does not match the ApiError structure', () => {
- const errorMessage = '[Stream Error: {"not_an_error": "some other json"}]';
- expect(parseAndFormatApiError(errorMessage)).toBe(
- `[API Error: ${errorMessage}]`,
- );
- });
-
- it('should format a nested API error', () => {
- const nestedErrorMessage = JSON.stringify({
- error: {
- code: 429,
- message:
- "Gemini 2.5 Pro Preview doesn't have a free quota tier. For more information on this error, head to: https://ai.google.dev/gemini-api/docs/rate-limits.",
- status: 'RESOURCE_EXHAUSTED',
- },
- });
-
- const errorMessage = JSON.stringify({
- error: {
- code: 429,
- message: nestedErrorMessage,
- status: 'Too Many Requests',
- },
- });
-
- const result = parseAndFormatApiError(errorMessage, AuthType.USE_GEMINI);
- expect(result).toContain('Gemini 2.5 Pro Preview');
- expect(result).toContain(geminiMessage);
- });
-
- it('should format a StructuredError', () => {
- const error: StructuredError = {
- message: 'A structured error occurred',
- status: 500,
- };
- const expected = '[API Error: A structured error occurred]';
- expect(parseAndFormatApiError(error)).toBe(expected);
- });
-
- it('should format a 429 StructuredError with the vertex message', () => {
- const error: StructuredError = {
- message: 'Rate limit exceeded',
- status: 429,
- };
- const result = parseAndFormatApiError(error, AuthType.USE_VERTEX_AI);
- expect(result).toContain('[API Error: Rate limit exceeded]');
- expect(result).toContain(vertexMessage);
- });
-
- it('should handle an unknown error type', () => {
- const error = 12345;
- const expected = '[API Error: An unknown error occurred.]';
- expect(parseAndFormatApiError(error)).toBe(expected);
- });
-
- it('should format a 429 API error with Pro quota exceeded message for Google auth (Free tier)', () => {
- const errorMessage =
- 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Quota exceeded for quota metric \'Gemini 2.5 Pro Requests\' and limit \'RequestsPerDay\' of service \'generativelanguage.googleapis.com\' for consumer \'project_number:123456789\'.","status":"RESOURCE_EXHAUSTED"}}';
- const result = parseAndFormatApiError(
- errorMessage,
- AuthType.LOGIN_WITH_GOOGLE,
- undefined,
- 'gemini-2.5-pro',
- DEFAULT_GEMINI_FLASH_MODEL,
- );
- expect(result).toContain(
- "[API Error: Quota exceeded for quota metric 'Gemini 2.5 Pro Requests'",
- );
- expect(result).toContain(
- 'You have reached your daily gemini-2.5-pro quota limit',
- );
- expect(result).toContain(
- 'upgrade to a Gemini Code Assist Standard or Enterprise plan',
- );
- });
-
- it('should format a regular 429 API error with standard message for Google auth', () => {
- const errorMessage =
- 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Rate limit exceeded","status":"RESOURCE_EXHAUSTED"}}';
- const result = parseAndFormatApiError(
- errorMessage,
- AuthType.LOGIN_WITH_GOOGLE,
- undefined,
- 'gemini-2.5-pro',
- DEFAULT_GEMINI_FLASH_MODEL,
- );
- expect(result).toContain('[API Error: Rate limit exceeded');
- expect(result).toContain(
- 'Possible quota limitations in place or slow response times detected. Switching to the gemini-2.5-flash model',
- );
- expect(result).not.toContain(
- 'You have reached your daily gemini-2.5-pro quota limit',
- );
- });
-
- it('should format a 429 API error with generic quota exceeded message for Google auth', () => {
- const errorMessage =
- 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Quota exceeded for quota metric \'GenerationRequests\' and limit \'RequestsPerDay\' of service \'generativelanguage.googleapis.com\' for consumer \'project_number:123456789\'.","status":"RESOURCE_EXHAUSTED"}}';
- const result = parseAndFormatApiError(
- errorMessage,
- AuthType.LOGIN_WITH_GOOGLE,
- undefined,
- 'gemini-2.5-pro',
- DEFAULT_GEMINI_FLASH_MODEL,
- );
- expect(result).toContain(
- "[API Error: Quota exceeded for quota metric 'GenerationRequests'",
- );
- expect(result).toContain('You have reached your daily quota limit');
- expect(result).not.toContain(
- 'You have reached your daily Gemini 2.5 Pro quota limit',
- );
- });
-
- it('should prioritize Pro quota message over generic quota message for Google auth', () => {
- const errorMessage =
- 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Quota exceeded for quota metric \'Gemini 2.5 Pro Requests\' and limit \'RequestsPerDay\' of service \'generativelanguage.googleapis.com\' for consumer \'project_number:123456789\'.","status":"RESOURCE_EXHAUSTED"}}';
- const result = parseAndFormatApiError(
- errorMessage,
- AuthType.LOGIN_WITH_GOOGLE,
- undefined,
- 'gemini-2.5-pro',
- DEFAULT_GEMINI_FLASH_MODEL,
- );
- expect(result).toContain(
- "[API Error: Quota exceeded for quota metric 'Gemini 2.5 Pro Requests'",
- );
- expect(result).toContain(
- 'You have reached your daily gemini-2.5-pro quota limit',
- );
- expect(result).not.toContain('You have reached your daily quota limit');
- });
-
- it('should format a 429 API error with Pro quota exceeded message for Google auth (Standard tier)', () => {
- const errorMessage =
- 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Quota exceeded for quota metric \'Gemini 2.5 Pro Requests\' and limit \'RequestsPerDay\' of service \'generativelanguage.googleapis.com\' for consumer \'project_number:123456789\'.","status":"RESOURCE_EXHAUSTED"}}';
- const result = parseAndFormatApiError(
- errorMessage,
- AuthType.LOGIN_WITH_GOOGLE,
- UserTierId.STANDARD,
- 'gemini-2.5-pro',
- DEFAULT_GEMINI_FLASH_MODEL,
- );
- expect(result).toContain(
- "[API Error: Quota exceeded for quota metric 'Gemini 2.5 Pro Requests'",
- );
- expect(result).toContain(
- 'You have reached your daily gemini-2.5-pro quota limit',
- );
- expect(result).toContain(
- 'We appreciate you for choosing Gemini Code Assist and the Gemini CLI',
- );
- expect(result).not.toContain(
- 'upgrade to a Gemini Code Assist Standard or Enterprise plan',
- );
- });
-
- it('should format a 429 API error with Pro quota exceeded message for Google auth (Legacy tier)', () => {
- const errorMessage =
- 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Quota exceeded for quota metric \'Gemini 2.5 Pro Requests\' and limit \'RequestsPerDay\' of service \'generativelanguage.googleapis.com\' for consumer \'project_number:123456789\'.","status":"RESOURCE_EXHAUSTED"}}';
- const result = parseAndFormatApiError(
- errorMessage,
- AuthType.LOGIN_WITH_GOOGLE,
- UserTierId.LEGACY,
- 'gemini-2.5-pro',
- DEFAULT_GEMINI_FLASH_MODEL,
- );
- expect(result).toContain(
- "[API Error: Quota exceeded for quota metric 'Gemini 2.5 Pro Requests'",
- );
- expect(result).toContain(
- 'You have reached your daily gemini-2.5-pro quota limit',
- );
- expect(result).toContain(
- 'We appreciate you for choosing Gemini Code Assist and the Gemini CLI',
- );
- expect(result).not.toContain(
- 'upgrade to a Gemini Code Assist Standard or Enterprise plan',
- );
- });
-
- it('should handle different Gemini 2.5 version strings in Pro quota exceeded errors', () => {
- const errorMessage25 =
- 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Quota exceeded for quota metric \'Gemini 2.5 Pro Requests\' and limit \'RequestsPerDay\' of service \'generativelanguage.googleapis.com\' for consumer \'project_number:123456789\'.","status":"RESOURCE_EXHAUSTED"}}';
- const errorMessagePreview =
- 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Quota exceeded for quota metric \'Gemini 2.5-preview Pro Requests\' and limit \'RequestsPerDay\' of service \'generativelanguage.googleapis.com\' for consumer \'project_number:123456789\'.","status":"RESOURCE_EXHAUSTED"}}';
-
- const result25 = parseAndFormatApiError(
- errorMessage25,
- AuthType.LOGIN_WITH_GOOGLE,
- undefined,
- 'gemini-2.5-pro',
- DEFAULT_GEMINI_FLASH_MODEL,
- );
- const resultPreview = parseAndFormatApiError(
- errorMessagePreview,
- AuthType.LOGIN_WITH_GOOGLE,
- undefined,
- 'gemini-2.5-preview-pro',
- DEFAULT_GEMINI_FLASH_MODEL,
- );
-
- expect(result25).toContain(
- 'You have reached your daily gemini-2.5-pro quota limit',
- );
- expect(resultPreview).toContain(
- 'You have reached your daily gemini-2.5-preview-pro quota limit',
- );
- expect(result25).toContain(
- 'upgrade to a Gemini Code Assist Standard or Enterprise plan',
- );
- expect(resultPreview).toContain(
- 'upgrade to a Gemini Code Assist Standard or Enterprise plan',
- );
- });
-
- it('should not match non-Pro models with similar version strings', () => {
- // Test that Flash models with similar version strings don't match
- expect(
- isProQuotaExceededError(
- "Quota exceeded for quota metric 'Gemini 2.5 Flash Requests' and limit",
- ),
- ).toBe(false);
- expect(
- isProQuotaExceededError(
- "Quota exceeded for quota metric 'Gemini 2.5-preview Flash Requests' and limit",
- ),
- ).toBe(false);
-
- // Test other model types
- expect(
- isProQuotaExceededError(
- "Quota exceeded for quota metric 'Gemini 2.5 Ultra Requests' and limit",
- ),
- ).toBe(false);
- expect(
- isProQuotaExceededError(
- "Quota exceeded for quota metric 'Gemini 2.5 Standard Requests' and limit",
- ),
- ).toBe(false);
-
- // Test generic quota messages
- expect(
- isProQuotaExceededError(
- "Quota exceeded for quota metric 'GenerationRequests' and limit",
- ),
- ).toBe(false);
- expect(
- isProQuotaExceededError(
- "Quota exceeded for quota metric 'EmbeddingRequests' and limit",
- ),
- ).toBe(false);
- });
-
- it('should format a generic quota exceeded message for Google auth (Standard tier)', () => {
- const errorMessage =
- 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Quota exceeded for quota metric \'GenerationRequests\' and limit \'RequestsPerDay\' of service \'generativelanguage.googleapis.com\' for consumer \'project_number:123456789\'.","status":"RESOURCE_EXHAUSTED"}}';
- const result = parseAndFormatApiError(
- errorMessage,
- AuthType.LOGIN_WITH_GOOGLE,
- UserTierId.STANDARD,
- 'gemini-2.5-pro',
- DEFAULT_GEMINI_FLASH_MODEL,
- );
- expect(result).toContain(
- "[API Error: Quota exceeded for quota metric 'GenerationRequests'",
- );
- expect(result).toContain('You have reached your daily quota limit');
- expect(result).toContain(
- 'We appreciate you for choosing Gemini Code Assist and the Gemini CLI',
- );
- expect(result).not.toContain(
- 'upgrade to a Gemini Code Assist Standard or Enterprise plan',
- );
- });
-
- it('should format a regular 429 API error with standard message for Google auth (Standard tier)', () => {
- const errorMessage =
- 'got status: 429 Too Many Requests. {"error":{"code":429,"message":"Rate limit exceeded","status":"RESOURCE_EXHAUSTED"}}';
- const result = parseAndFormatApiError(
- errorMessage,
- AuthType.LOGIN_WITH_GOOGLE,
- UserTierId.STANDARD,
- 'gemini-2.5-pro',
- DEFAULT_GEMINI_FLASH_MODEL,
- );
- expect(result).toContain('[API Error: Rate limit exceeded');
- expect(result).toContain(
- 'We appreciate you for choosing Gemini Code Assist and the Gemini CLI',
- );
- expect(result).not.toContain(
- 'upgrade to a Gemini Code Assist Standard or Enterprise plan',
- );
- });
-});
diff --git a/packages/cli/src/ui/utils/errorParsing.ts b/packages/cli/src/ui/utils/errorParsing.ts
deleted file mode 100644
index 5031bc0a..00000000
--- a/packages/cli/src/ui/utils/errorParsing.ts
+++ /dev/null
@@ -1,164 +0,0 @@
-/**
- * @license
- * Copyright 2025 Google LLC
- * SPDX-License-Identifier: Apache-2.0
- */
-
-import {
- AuthType,
- UserTierId,
- DEFAULT_GEMINI_FLASH_MODEL,
- DEFAULT_GEMINI_MODEL,
- isProQuotaExceededError,
- isGenericQuotaExceededError,
- isApiError,
- isStructuredError,
-} from '@google/gemini-cli-core';
-
-// Free Tier message functions
-const getRateLimitErrorMessageGoogleFree = (
- fallbackModel: string = DEFAULT_GEMINI_FLASH_MODEL,
-) =>
- `\nPossible quota limitations in place or slow response times detected. Switching to the ${fallbackModel} model for the rest of this session.`;
-
-const getRateLimitErrorMessageGoogleProQuotaFree = (
- currentModel: string = DEFAULT_GEMINI_MODEL,
- fallbackModel: string = DEFAULT_GEMINI_FLASH_MODEL,
-) =>
- `\nYou have reached your daily ${currentModel} quota limit. You will be switched to the ${fallbackModel} model for the rest of this session. To increase your limits, upgrade to a Gemini Code Assist Standard or Enterprise plan with higher limits at https://goo.gle/set-up-gemini-code-assist, or use /auth to switch to using a paid API key from AI Studio at https://aistudio.google.com/apikey`;
-
-const getRateLimitErrorMessageGoogleGenericQuotaFree = () =>
- `\nYou have reached your daily quota limit. To increase your limits, upgrade to a Gemini Code Assist Standard or Enterprise plan with higher limits at https://goo.gle/set-up-gemini-code-assist, or use /auth to switch to using a paid API key from AI Studio at https://aistudio.google.com/apikey`;
-
-// Legacy/Standard Tier message functions
-const getRateLimitErrorMessageGooglePaid = (
- fallbackModel: string = DEFAULT_GEMINI_FLASH_MODEL,
-) =>
- `\nPossible quota limitations in place or slow response times detected. Switching to the ${fallbackModel} model for the rest of this session. We appreciate you for choosing Gemini Code Assist and the Gemini CLI.`;
-
-const getRateLimitErrorMessageGoogleProQuotaPaid = (
- currentModel: string = DEFAULT_GEMINI_MODEL,
- fallbackModel: string = DEFAULT_GEMINI_FLASH_MODEL,
-) =>
- `\nYou have reached your daily ${currentModel} quota limit. You will be switched to the ${fallbackModel} model for the rest of this session. We appreciate you for choosing Gemini Code Assist and the Gemini CLI. To continue accessing the ${currentModel} model today, consider using /auth to switch to using a paid API key from AI Studio at https://aistudio.google.com/apikey`;
-
-const getRateLimitErrorMessageGoogleGenericQuotaPaid = (
- currentModel: string = DEFAULT_GEMINI_MODEL,
-) =>
- `\nYou have reached your daily quota limit. We appreciate you for choosing Gemini Code Assist and the Gemini CLI. To continue accessing the ${currentModel} model today, consider using /auth to switch to using a paid API key from AI Studio at https://aistudio.google.com/apikey`;
-const RATE_LIMIT_ERROR_MESSAGE_USE_GEMINI =
- '\nPlease wait and try again later. To increase your limits, request a quota increase through AI Studio, or switch to another /auth method';
-const RATE_LIMIT_ERROR_MESSAGE_VERTEX =
- '\nPlease wait and try again later. To increase your limits, request a quota increase through Vertex, or switch to another /auth method';
-const getRateLimitErrorMessageDefault = (
- fallbackModel: string = DEFAULT_GEMINI_FLASH_MODEL,
-) =>
- `\nPossible quota limitations in place or slow response times detected. Switching to the ${fallbackModel} model for the rest of this session.`;
-
-function getRateLimitMessage(
- authType?: AuthType,
- error?: unknown,
- userTier?: UserTierId,
- currentModel?: string,
- fallbackModel?: string,
-): string {
- switch (authType) {
- case AuthType.LOGIN_WITH_GOOGLE: {
- // Determine if user is on a paid tier (Legacy or Standard) - default to FREE if not specified
- const isPaidTier =
- userTier === UserTierId.LEGACY || userTier === UserTierId.STANDARD;
-
- if (isProQuotaExceededError(error)) {
- return isPaidTier
- ? getRateLimitErrorMessageGoogleProQuotaPaid(
- currentModel || DEFAULT_GEMINI_MODEL,
- fallbackModel,
- )
- : getRateLimitErrorMessageGoogleProQuotaFree(
- currentModel || DEFAULT_GEMINI_MODEL,
- fallbackModel,
- );
- } else if (isGenericQuotaExceededError(error)) {
- return isPaidTier
- ? getRateLimitErrorMessageGoogleGenericQuotaPaid(
- currentModel || DEFAULT_GEMINI_MODEL,
- )
- : getRateLimitErrorMessageGoogleGenericQuotaFree();
- } else {
- return isPaidTier
- ? getRateLimitErrorMessageGooglePaid(fallbackModel)
- : getRateLimitErrorMessageGoogleFree(fallbackModel);
- }
- }
- case AuthType.USE_GEMINI:
- return RATE_LIMIT_ERROR_MESSAGE_USE_GEMINI;
- case AuthType.USE_VERTEX_AI:
- return RATE_LIMIT_ERROR_MESSAGE_VERTEX;
- default:
- return getRateLimitErrorMessageDefault(fallbackModel);
- }
-}
-
-export function parseAndFormatApiError(
- error: unknown,
- authType?: AuthType,
- userTier?: UserTierId,
- currentModel?: string,
- fallbackModel?: string,
-): string {
- if (isStructuredError(error)) {
- let text = `[API Error: ${error.message}]`;
- if (error.status === 429) {
- text += getRateLimitMessage(
- authType,
- error,
- userTier,
- currentModel,
- fallbackModel,
- );
- }
- return text;
- }
-
- // The error message might be a string containing a JSON object.
- if (typeof error === 'string') {
- const jsonStart = error.indexOf('{');
- if (jsonStart === -1) {
- return `[API Error: ${error}]`; // Not a JSON error, return as is.
- }
-
- const jsonString = error.substring(jsonStart);
-
- try {
- const parsedError = JSON.parse(jsonString) as unknown;
- if (isApiError(parsedError)) {
- let finalMessage = parsedError.error.message;
- try {
- // See if the message is a stringified JSON with another error
- const nestedError = JSON.parse(finalMessage) as unknown;
- if (isApiError(nestedError)) {
- finalMessage = nestedError.error.message;
- }
- } catch (_e) {
- // It's not a nested JSON error, so we just use the message as is.
- }
- let text = `[API Error: ${finalMessage} (Status: ${parsedError.error.status})]`;
- if (parsedError.error.code === 429) {
- text += getRateLimitMessage(
- authType,
- parsedError,
- userTier,
- currentModel,
- fallbackModel,
- );
- }
- return text;
- }
- } catch (_e) {
- // Not a valid JSON, fall through and return the original message.
- }
- return `[API Error: ${error}]`;
- }
-
- return '[API Error: An unknown error occurred.]';
-}