[JUNE 25] Permanent failover to Flash model for OAuth users after persistent 429 errors (#1376)

Co-authored-by: Scott Densmore <scottdensmore@mac.com>
This commit is contained in:
Bryan Morgan
2025-06-24 18:48:55 -04:00
committed by GitHub
parent 4bf18da2b0
commit e356949d3f
16 changed files with 837 additions and 12 deletions

View File

@@ -38,6 +38,7 @@ import {
} from './contentGenerator.js';
import { ProxyAgent, setGlobalDispatcher } from 'undici';
import { DEFAULT_GEMINI_FLASH_MODEL } from '../config/models.js';
import { AuthType } from './contentGenerator.js';
function isThinkingSupported(model: string) {
if (model.startsWith('gemini-2.5')) return true;
@@ -276,7 +277,11 @@ export class GeminiClient {
contents,
});
const result = await retryWithBackoff(apiCall);
const result = await retryWithBackoff(apiCall, {
onPersistent429: async (authType?: string) =>
await this.handleFlashFallback(authType),
authType: this.config.getContentGeneratorConfig()?.authType,
});
const text = getResponseText(result);
if (!text) {
@@ -360,7 +365,11 @@ export class GeminiClient {
contents,
});
const result = await retryWithBackoff(apiCall);
const result = await retryWithBackoff(apiCall, {
onPersistent429: async (authType?: string) =>
await this.handleFlashFallback(authType),
authType: this.config.getContentGeneratorConfig()?.authType,
});
return result;
} catch (error: unknown) {
if (abortSignal.aborted) {
@@ -489,4 +498,43 @@ export class GeminiClient {
}
: null;
}
/**
* Handles fallback to Flash model when persistent 429 errors occur for OAuth users.
* Uses a fallback handler if provided by the config, otherwise returns null.
*/
private async handleFlashFallback(authType?: string): Promise<string | null> {
// Only handle fallback for OAuth users
if (
authType !== AuthType.LOGIN_WITH_GOOGLE_PERSONAL &&
authType !== AuthType.LOGIN_WITH_GOOGLE_ENTERPRISE
) {
return null;
}
const currentModel = this.model;
const fallbackModel = DEFAULT_GEMINI_FLASH_MODEL;
// Don't fallback if already using Flash model
if (currentModel === fallbackModel) {
return null;
}
// Check if config has a fallback handler (set by CLI package)
const fallbackHandler = this.config.flashFallbackHandler;
if (typeof fallbackHandler === 'function') {
try {
const accepted = await fallbackHandler(currentModel, fallbackModel);
if (accepted) {
this.config.setModel(fallbackModel);
this.model = fallbackModel;
return fallbackModel;
}
} catch (error) {
console.warn('Flash fallback handler failed:', error);
}
}
return null;
}
}