From e356949d3fb600abd1a993949300a6c3e0008621 Mon Sep 17 00:00:00 2001 From: Bryan Morgan Date: Tue, 24 Jun 2025 18:48:55 -0400 Subject: [PATCH] [JUNE 25] Permanent failover to Flash model for OAuth users after persistent 429 errors (#1376) Co-authored-by: Scott Densmore --- packages/cli/src/ui/App.test.tsx | 1 + packages/cli/src/ui/App.tsx | 39 +++- .../cli/src/ui/hooks/slashCommandProcessor.ts | 5 +- packages/core/src/config/config.ts | 59 +++++- .../core/src/config/flashFallback.test.ts | 139 ++++++++++++ packages/core/src/core/client.test.ts | 4 + packages/core/src/core/client.ts | 52 ++++- packages/core/src/core/contentGenerator.ts | 6 +- packages/core/src/core/geminiChat.test.ts | 9 + packages/core/src/core/geminiChat.ts | 44 +++- .../utils/flashFallback.integration.test.ts | 144 +++++++++++++ packages/core/src/utils/retry.test.ts | 199 ++++++++++++++++++ packages/core/src/utils/retry.ts | 50 ++++- packages/core/src/utils/testUtils.ts | 87 ++++++++ packages/core/test-setup.ts | 10 + packages/core/vitest.config.ts | 1 + 16 files changed, 837 insertions(+), 12 deletions(-) create mode 100644 packages/core/src/config/flashFallback.test.ts create mode 100644 packages/core/src/utils/flashFallback.integration.test.ts create mode 100644 packages/core/src/utils/testUtils.ts create mode 100644 packages/core/test-setup.ts diff --git a/packages/cli/src/ui/App.test.tsx b/packages/cli/src/ui/App.test.tsx index 1271c86a..75de2cf2 100644 --- a/packages/cli/src/ui/App.test.tsx +++ b/packages/cli/src/ui/App.test.tsx @@ -125,6 +125,7 @@ vi.mock('@gemini-cli/core', async (importOriginal) => { getGeminiClient: vi.fn(() => ({})), getCheckpointingEnabled: vi.fn(() => opts.checkpointing ?? true), getAllGeminiMdFilenames: vi.fn(() => ['GEMINI.md']), + setFlashFallbackHandler: vi.fn(), }; }); return { diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx index c25d74e2..7824f0f7 100644 --- a/packages/cli/src/ui/App.tsx +++ b/packages/cli/src/ui/App.tsx @@ -115,6 +115,7 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => { const [editorError, setEditorError] = useState(null); const [footerHeight, setFooterHeight] = useState(0); const [corgiMode, setCorgiMode] = useState(false); + const [currentModel, setCurrentModel] = useState(config.getModel()); const [shellModeActive, setShellModeActive] = useState(false); const [showErrorDetails, setShowErrorDetails] = useState(false); const [showToolDescriptions, setShowToolDescriptions] = @@ -214,6 +215,42 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => { } }, [config, addItem]); + // Watch for model changes (e.g., from Flash fallback) + useEffect(() => { + const checkModelChange = () => { + const configModel = config.getModel(); + if (configModel !== currentModel) { + setCurrentModel(configModel); + } + }; + + // Check immediately and then periodically + checkModelChange(); + const interval = setInterval(checkModelChange, 1000); // Check every second + + return () => clearInterval(interval); + }, [config, currentModel]); + + // Set up Flash fallback handler + useEffect(() => { + const flashFallbackHandler = async ( + currentModel: string, + fallbackModel: string, + ): Promise => { + // Add message to UI history + addItem( + { + type: MessageType.INFO, + text: `⚡ Rate limiting detected. Automatically switching from ${currentModel} to ${fallbackModel} for faster responses for the remainder of this session.`, + }, + Date.now(), + ); + return true; // Always accept the fallback + }; + + config.setFlashFallbackHandler(flashFallbackHandler); + }, [config, addItem]); + const { handleSlashCommand, slashCommands, @@ -787,7 +824,7 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => { )}