diff options
| author | Adam Weidman <[email protected]> | 2025-08-13 17:57:11 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-08-13 17:57:11 +0000 |
| commit | b61a63aef4bcce9cb56fe46f10f0dc90b8fd6597 (patch) | |
| tree | 278aa096f82fbad8f0b75cdfefdd108531ccc4a0 /packages/core/src/utils/errorParsing.ts | |
| parent | 9c7fb870c1a7c80741fafdfc6837d4b92e373b2d (diff) | |
move errorParsing.ts to core (#6159)
Diffstat (limited to 'packages/core/src/utils/errorParsing.ts')
| -rw-r--r-- | packages/core/src/utils/errorParsing.ts | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/packages/core/src/utils/errorParsing.ts b/packages/core/src/utils/errorParsing.ts new file mode 100644 index 00000000..aa15a652 --- /dev/null +++ b/packages/core/src/utils/errorParsing.ts @@ -0,0 +1,166 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + isProQuotaExceededError, + isGenericQuotaExceededError, + isApiError, + isStructuredError, +} from './quotaErrorDetection.js'; +import { + DEFAULT_GEMINI_MODEL, + DEFAULT_GEMINI_FLASH_MODEL, +} from '../config/models.js'; +import { UserTierId } from '../code_assist/types.js'; +import { AuthType } from '../core/contentGenerator.js'; + +// 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.]'; +} |
