diff options
| author | Bryan Morgan <[email protected]> | 2025-07-09 13:55:56 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-07-09 17:55:56 +0000 |
| commit | 8a6509ffeba271a8e7ccb83066a9a31a5d72a647 (patch) | |
| tree | e67893a06d291f074e69f7f14d4f22ccbe3a6550 /packages/core/src/utils | |
| parent | 01e756481f359a28aca0d5220f853daec8d25ed4 (diff) | |
Remove auto-execution on Flash in the event of a 429/Quota failover (#3662)
Co-authored-by: Jenna Inouye <[email protected]>
Diffstat (limited to 'packages/core/src/utils')
| -rw-r--r-- | packages/core/src/utils/editCorrector.test.ts | 4 | ||||
| -rw-r--r-- | packages/core/src/utils/quotaErrorDetection.ts | 53 | ||||
| -rw-r--r-- | packages/core/src/utils/retry.ts | 17 |
3 files changed, 64 insertions, 10 deletions
diff --git a/packages/core/src/utils/editCorrector.test.ts b/packages/core/src/utils/editCorrector.test.ts index bcf75dfe..cf9008ef 100644 --- a/packages/core/src/utils/editCorrector.test.ts +++ b/packages/core/src/utils/editCorrector.test.ts @@ -214,6 +214,8 @@ describe('editCorrector', () => { setAlwaysSkipModificationConfirmation: vi.fn((skip: boolean) => { configParams.alwaysSkipModificationConfirmation = skip; }), + getQuotaErrorOccurred: vi.fn().mockReturnValue(false), + setQuotaErrorOccurred: vi.fn(), } as unknown as Config; callCount = 0; @@ -654,6 +656,8 @@ describe('editCorrector', () => { setAlwaysSkipModificationConfirmation: vi.fn((skip: boolean) => { configParams.alwaysSkipModificationConfirmation = skip; }), + getQuotaErrorOccurred: vi.fn().mockReturnValue(false), + setQuotaErrorOccurred: vi.fn(), } as unknown as Config; callCount = 0; diff --git a/packages/core/src/utils/quotaErrorDetection.ts b/packages/core/src/utils/quotaErrorDetection.ts index ec77f5ee..a8e87a5d 100644 --- a/packages/core/src/utils/quotaErrorDetection.ts +++ b/packages/core/src/utils/quotaErrorDetection.ts @@ -41,14 +41,23 @@ export function isProQuotaExceededError(error: unknown): boolean { // Check for Pro quota exceeded errors by looking for the specific pattern // This will match patterns like: // - "Quota exceeded for quota metric 'Gemini 2.5 Pro Requests'" - // - "Quota exceeded for quota metric 'Gemini 1.5-preview Pro Requests'" - // - "Quota exceeded for quota metric 'Gemini beta-3.0 Pro Requests'" - // - "Quota exceeded for quota metric 'Gemini experimental-v2 Pro Requests'" + // - "Quota exceeded for quota metric 'Gemini 2.5-preview Pro Requests'" // We use string methods instead of regex to avoid ReDoS vulnerabilities - const checkMessage = (message: string): boolean => - message.includes("Quota exceeded for quota metric 'Gemini") && - message.includes("Pro Requests'"); + const checkMessage = (message: string): boolean => { + console.log('[DEBUG] isProQuotaExceededError checking message:', message); + const result = + message.includes("Quota exceeded for quota metric 'Gemini") && + message.includes("Pro Requests'"); + console.log('[DEBUG] isProQuotaExceededError result:', result); + return result; + }; + + // Log the full error object to understand its structure + console.log( + '[DEBUG] isProQuotaExceededError - full error object:', + JSON.stringify(error, null, 2), + ); if (typeof error === 'string') { return checkMessage(error); @@ -62,6 +71,38 @@ export function isProQuotaExceededError(error: unknown): boolean { return checkMessage(error.error.message); } + // Check if it's a Gaxios error with response data + if (error && typeof error === 'object' && 'response' in error) { + const gaxiosError = error as { + response?: { + data?: unknown; + }; + }; + if (gaxiosError.response && gaxiosError.response.data) { + console.log( + '[DEBUG] isProQuotaExceededError - checking response data:', + gaxiosError.response.data, + ); + if (typeof gaxiosError.response.data === 'string') { + return checkMessage(gaxiosError.response.data); + } + if ( + typeof gaxiosError.response.data === 'object' && + gaxiosError.response.data !== null && + 'error' in gaxiosError.response.data + ) { + const errorData = gaxiosError.response.data as { + error?: { message?: string }; + }; + return checkMessage(errorData.error?.message || ''); + } + } + } + + console.log( + '[DEBUG] isProQuotaExceededError - no matching error format for:', + error, + ); return false; } diff --git a/packages/core/src/utils/retry.ts b/packages/core/src/utils/retry.ts index 01651950..e5d65751 100644 --- a/packages/core/src/utils/retry.ts +++ b/packages/core/src/utils/retry.ts @@ -18,7 +18,7 @@ export interface RetryOptions { onPersistent429?: ( authType?: string, error?: unknown, - ) => Promise<string | null>; + ) => Promise<string | boolean | null>; authType?: string; } @@ -102,13 +102,16 @@ export async function retryWithBackoff<T>( ) { try { const fallbackModel = await onPersistent429(authType, error); - if (fallbackModel) { + if (fallbackModel !== false && fallbackModel !== null) { // Reset attempt counter and try with new model attempt = 0; consecutive429Count = 0; currentDelay = initialDelayMs; // With the model updated, we continue to the next attempt continue; + } else { + // Fallback handler returned null/false, meaning don't continue - stop retry process + throw error; } } catch (fallbackError) { // If fallback fails, continue with original error @@ -126,13 +129,16 @@ export async function retryWithBackoff<T>( ) { try { const fallbackModel = await onPersistent429(authType, error); - if (fallbackModel) { + if (fallbackModel !== false && fallbackModel !== null) { // Reset attempt counter and try with new model attempt = 0; consecutive429Count = 0; currentDelay = initialDelayMs; // With the model updated, we continue to the next attempt continue; + } else { + // Fallback handler returned null/false, meaning don't continue - stop retry process + throw error; } } catch (fallbackError) { // If fallback fails, continue with original error @@ -155,13 +161,16 @@ export async function retryWithBackoff<T>( ) { try { const fallbackModel = await onPersistent429(authType, error); - if (fallbackModel) { + if (fallbackModel !== false && fallbackModel !== null) { // Reset attempt counter and try with new model attempt = 0; consecutive429Count = 0; currentDelay = initialDelayMs; // With the model updated, we continue to the next attempt continue; + } else { + // Fallback handler returned null/false, meaning don't continue - stop retry process + throw error; } } catch (fallbackError) { // If fallback fails, continue with original error |
