From c16b64aa3122c7450650696877b07c2e62e90b43 Mon Sep 17 00:00:00 2001 From: David Pierce Date: Tue, 22 Sep 2026 21:52:46 +0000 Subject: [PATCH] Feat/gemini 3.8 flash 3.5 flash lite (#29443) # Conflicts: # packages/core/src/config/models.test.ts # packages/core/src/config/models.ts # packages/core/src/core/geminiChat.test.ts --- docs/reference/configuration.md | 113 ++++++-- packages/cli/src/acp/acpUtils.ts | 8 +- packages/cli/src/config/settingsSchema.ts | 20 +- .../cli/src/ui/components/ModelDialog.tsx | 17 +- .../cli/src/ui/hooks/useGeminiStream.test.tsx | 5 +- .../src/ui/hooks/useQuotaAndFallback.test.ts | 2 +- .../autoRoutingFallback.integration.test.ts | 123 ++++++++- .../src/availability/policyCatalog.test.ts | 16 +- .../core/src/availability/policyCatalog.ts | 49 ++-- .../src/availability/policyHelpers.test.ts | 34 ++- .../core/src/availability/policyHelpers.ts | 30 ++- .../src/code_assist/experiments/flagNames.ts | 3 + packages/core/src/config/config.test.ts | 150 ++++++++++- packages/core/src/config/config.ts | 84 ++++-- .../core/src/config/defaultModelConfigs.ts | 122 +++++++-- packages/core/src/config/models.test.ts | 213 +++++++++++++-- packages/core/src/config/models.ts | 237 ++++++++++++---- .../context/chatCompressionService.test.ts | 15 ++ .../src/context/chatCompressionService.ts | 13 +- .../core/src/core/contentGenerator.test.ts | 21 +- packages/core/src/core/contentGenerator.ts | 11 +- packages/core/src/core/geminiChat.test.ts | 38 ++- .../src/core/geminiChat_network_retry.test.ts | 2 +- .../src/core/modelMappingContentGenerator.ts | 12 +- .../strategies/approvalModeStrategy.test.ts | 11 +- .../strategies/approvalModeStrategy.ts | 9 +- .../strategies/classifierStrategy.test.ts | 11 +- .../routing/strategies/classifierStrategy.ts | 6 +- .../src/routing/strategies/defaultStrategy.ts | 3 +- .../routing/strategies/fallbackStrategy.ts | 3 +- .../gemmaClassifierStrategy.test.ts | 11 +- .../strategies/gemmaClassifierStrategy.ts | 6 +- .../numericalClassifierStrategy.test.ts | 8 +- .../strategies/numericalClassifierStrategy.ts | 6 +- .../routing/strategies/overrideStrategy.ts | 3 +- .../core/src/services/modelConfigService.ts | 32 ++- .../resolved-aliases-retry.golden.json | 24 ++ .../test-data/resolved-aliases.golden.json | 24 ++ packages/core/src/utils/errorParsing.test.ts | 2 +- schemas/settings.schema.json | 253 ++++++++++++++---- 40 files changed, 1407 insertions(+), 343 deletions(-) diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md index 66785882cea..61d158ded90 100644 --- a/docs/reference/configuration.md +++ b/docs/reference/configuration.md @@ -672,12 +672,24 @@ their corresponding top-level category object in your `settings.json` file. "model": "gemini-3.1-flash-lite" } }, + "gemini-3.5-flash-lite": { + "extends": "chat-base-3", + "modelConfig": { + "model": "gemini-3.5-flash-lite" + } + }, "gemini-3.5-flash": { "extends": "chat-base-3", "modelConfig": { "model": "gemini-3.5-flash" } }, + "gemini-3.8-flash": { + "extends": "chat-base-3", + "modelConfig": { + "model": "gemini-3.8-flash" + } + }, "gemma-4-31b-it": { "extends": "chat-base-3", "modelConfig": { @@ -914,6 +926,16 @@ their corresponding top-level category object in your `settings.json` file. "multimodalToolUse": true } }, + "gemini-3.5-flash-lite": { + "tier": "flash-lite", + "family": "gemini-3", + "isPreview": false, + "isVisible": true, + "features": { + "thinking": false, + "multimodalToolUse": true + } + }, "gemini-3.1-pro-preview": { "tier": "pro", "family": "gemini-3", @@ -964,6 +986,16 @@ their corresponding top-level category object in your `settings.json` file. "multimodalToolUse": true } }, + "gemini-3.8-flash": { + "tier": "flash", + "family": "gemini-3", + "isPreview": false, + "isVisible": true, + "features": { + "thinking": false, + "multimodalToolUse": true + } + }, "gemini-2.5-pro": { "tier": "pro", "family": "gemini-2.5", @@ -1118,16 +1150,16 @@ their corresponding top-level category object in your `settings.json` file. { "condition": { "hasAccessToPreview": false, - "useGemini3_5Flash": true + "useLatestFlash": true }, - "target": "gemini-3.5-flash" + "target": "gemini-3.8-flash" }, { "condition": { "hasAccessToPreview": false, - "useGemini3_5Flash": false + "useLatestFlash": false }, - "target": "gemini-2.5-flash" + "target": "gemini-3.5-flash" } ] }, @@ -1136,16 +1168,20 @@ their corresponding top-level category object in your `settings.json` file. "contexts": [ { "condition": { - "useGemini3_5Flash": false, - "hasAccessToPreview": false + "useLatestFlash": true }, - "target": "gemini-2.5-flash" - }, + "target": "gemini-3.8-flash" + } + ] + }, + "gemini-3.8-flash": { + "default": "gemini-3.8-flash", + "contexts": [ { "condition": { - "useGemini3_5Flash": false + "useLatestFlash": false }, - "target": "gemini-3-flash-preview" + "target": "gemini-3.5-flash" } ] }, @@ -1154,9 +1190,9 @@ their corresponding top-level category object in your `settings.json` file. "contexts": [ { "condition": { - "useGemini3_5Flash": true + "useLatestFlash": true }, - "target": "gemini-3.5-flash" + "target": "gemini-3.8-flash" } ] }, @@ -1233,27 +1269,54 @@ their corresponding top-level category object in your `settings.json` file. ] }, "gemini-3.1-flash-lite": { - "default": "gemini-3.1-flash-lite" + "default": "gemini-3.1-flash-lite", + "contexts": [ + { + "condition": { + "useLatestFlashLite": true + }, + "target": "gemini-3.5-flash-lite" + } + ] + }, + "gemini-3.5-flash-lite": { + "default": "gemini-3.5-flash-lite", + "contexts": [ + { + "condition": { + "useLatestFlashLite": false + }, + "target": "gemini-3.1-flash-lite" + } + ] }, "flash": { "default": "gemini-3-flash-preview", "contexts": [ { "condition": { - "useGemini3_5Flash": true + "useLatestFlash": true }, - "target": "gemini-3.5-flash" + "target": "gemini-3.8-flash" }, { "condition": { "hasAccessToPreview": false }, - "target": "gemini-2.5-flash" + "target": "gemini-3.5-flash" } ] }, "flash-lite": { - "default": "gemini-3.1-flash-lite" + "default": "gemini-3.1-flash-lite", + "contexts": [ + { + "condition": { + "useLatestFlashLite": true + }, + "target": "gemini-3.5-flash-lite" + } + ] }, "auto-gemini-3": { "default": "gemini-3-pro-preview", @@ -1300,21 +1363,21 @@ their corresponding top-level category object in your `settings.json` file. "contexts": [ { "condition": { - "useGemini3_5Flash": true + "useLatestFlash": true }, - "target": "gemini-3.5-flash" + "target": "gemini-3.8-flash" }, { "condition": { "hasAccessToPreview": false }, - "target": "gemini-2.5-flash" + "target": "gemini-3.5-flash" }, { "condition": { "requestedModels": ["gemini-2.5-pro", "auto-gemini-2.5"] }, - "target": "gemini-2.5-flash" + "target": "gemini-3.5-flash" } ] }, @@ -1447,7 +1510,7 @@ their corresponding top-level category object in your `settings.json` file. } }, { - "model": "gemini-2.5-flash", + "model": "gemini-3.5-flash", "isLastResort": true, "maxAttempts": 10, "actions": { @@ -1482,7 +1545,7 @@ their corresponding top-level category object in your `settings.json` file. } }, { - "model": "gemini-2.5-flash", + "model": "gemini-3.5-flash", "isLastResort": true, "maxAttempts": 10, "actions": { @@ -1501,7 +1564,7 @@ their corresponding top-level category object in your `settings.json` file. ], "lite": [ { - "model": "flash-lite", + "model": "gemini-3.1-flash-lite", "actions": { "terminal": "silent", "transient": "silent", @@ -1516,7 +1579,7 @@ their corresponding top-level category object in your `settings.json` file. } }, { - "model": "gemini-2.5-flash", + "model": "gemini-3.5-flash", "actions": { "terminal": "silent", "transient": "silent", diff --git a/packages/cli/src/acp/acpUtils.ts b/packages/cli/src/acp/acpUtils.ts index ea5e160f54a..a0a4ae7a475 100644 --- a/packages/cli/src/acp/acpUtils.ts +++ b/packages/cli/src/acp/acpUtils.ts @@ -265,7 +265,8 @@ export function buildAvailableModels( const preferredModel = config.getModel() || GEMINI_MODEL_ALIAS_AUTO; const shouldShowPreviewModels = config.getHasAccessToPreviewModel(); const useGemini31 = config.getGemini31LaunchedSync?.() ?? false; - const useGemini3_5Flash = config.hasGemini35FlashGAAccess?.() ?? false; + const useLatestFlash = config.hasLatestFlashGAAccess?.() ?? false; + const useLatestFlashLite = config.hasLatestFlashLiteGAAccess?.() ?? false; const selectedAuthType = settings.merged.security.auth.selectedType; const useCustomToolModel = useGemini31 && selectedAuthType === AuthType.USE_GEMINI; @@ -277,7 +278,8 @@ export function buildAvailableModels( ) { const options = config.getModelConfigService().getAvailableModelOptions({ useGemini3_1: useGemini31, - useGemini3_5Flash, + useLatestFlash, + useLatestFlashLite, useCustomTools: useCustomToolModel, hasAccessToPreview: shouldShowPreviewModels, }); @@ -296,7 +298,7 @@ export function buildAvailableModels( description: getAutoModelDescription( shouldShowPreviewModels, useGemini31, - useGemini3_5Flash, + useLatestFlash, ), }, ]; diff --git a/packages/cli/src/config/settingsSchema.ts b/packages/cli/src/config/settingsSchema.ts index 3a87cba3ab6..0b480252240 100644 --- a/packages/cli/src/config/settingsSchema.ts +++ b/packages/cli/src/config/settingsSchema.ts @@ -3524,7 +3524,24 @@ export const SETTINGS_SCHEMA_DEFINITIONS: Record< type: 'object', properties: { useGemini3_1: { type: 'boolean' }, - useGemini3_1FlashLite: { type: 'boolean' }, + useLatestFlash: { + type: 'boolean', + description: + 'Whether the latest GA Flash model (Gemini 3.8 Flash) is launched and active.', + }, + useLatestFlashLite: { + type: 'boolean', + description: + 'Whether the latest GA Flash Lite model (Gemini 3.5 Flash Lite) is launched and active.', + }, + useGemini3_5Flash: { + type: 'boolean', + description: 'Deprecated alias for useLatestFlash.', + }, + useGemini3_1FlashLite: { + type: 'boolean', + description: 'Deprecated alias for useLatestFlashLite.', + }, useCustomTools: { type: 'boolean' }, hasAccessToPreview: { type: 'boolean' }, requestedModels: { @@ -3533,6 +3550,7 @@ export const SETTINGS_SCHEMA_DEFINITIONS: Record< }, }, }, + target: { type: 'string' }, }, }, diff --git a/packages/cli/src/ui/components/ModelDialog.tsx b/packages/cli/src/ui/components/ModelDialog.tsx index e5db594684b..ba2e019a862 100644 --- a/packages/cli/src/ui/components/ModelDialog.tsx +++ b/packages/cli/src/ui/components/ModelDialog.tsx @@ -67,7 +67,8 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element { const shouldShowPreviewModels = config?.getHasAccessToPreviewModel() ?? false; const useGemini31 = config?.getGemini31LaunchedSync?.() ?? false; - const useGemini3_5Flash = config?.hasGemini35FlashGAAccess?.() ?? false; + const useLatestFlash = config?.hasLatestFlashGAAccess?.() ?? false; + const useLatestFlashLite = config?.hasLatestFlashLiteGAAccess?.() ?? false; const selectedAuthType = settings.merged.security.auth.selectedType; const useCustomToolModel = useGemini31 && selectedAuthType === AuthType.USE_GEMINI; @@ -130,7 +131,8 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element { .getModelConfigService() .getAvailableModelOptions({ useGemini3_1: useGemini31, - useGemini3_5Flash, + useLatestFlash, + useLatestFlashLite, useCustomTools: useCustomToolModel, hasAccessToPreview: shouldShowPreviewModels, hasAccessToProModel, @@ -164,7 +166,7 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element { description: getAutoModelDescription( shouldShowPreviewModels, useGemini31, - useGemini3_5Flash, + useLatestFlash, ), key: GEMINI_MODEL_ALIAS_AUTO, }, @@ -184,7 +186,8 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element { shouldShowPreviewModels, manualModelSelected, useGemini31, - useGemini3_5Flash, + useLatestFlash, + useLatestFlashLite, useCustomToolModel, hasAccessToProModel, ]); @@ -199,7 +202,8 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element { .getModelConfigService() .getAvailableModelOptions({ useGemini3_1: useGemini31, - useGemini3_5Flash, + useLatestFlash, + useLatestFlashLite, useCustomTools: useCustomToolModel, hasAccessToPreview: shouldShowPreviewModels, hasAccessToProModel, @@ -292,7 +296,8 @@ export function ModelDialog({ onClose }: ModelDialogProps): React.JSX.Element { }, [ shouldShowPreviewModels, useGemini31, - useGemini3_5Flash, + useLatestFlash, + useLatestFlashLite, useCustomToolModel, hasAccessToProModel, config, diff --git a/packages/cli/src/ui/hooks/useGeminiStream.test.tsx b/packages/cli/src/ui/hooks/useGeminiStream.test.tsx index 082a7d35303..9ef69296813 100644 --- a/packages/cli/src/ui/hooks/useGeminiStream.test.tsx +++ b/packages/cli/src/ui/hooks/useGeminiStream.test.tsx @@ -55,6 +55,7 @@ import { getPlanModeExitMessage, UPDATE_TOPIC_TOOL_NAME, TRUE_EMPTY_RESPONSE_MESSAGE, + DEFAULT_GEMINI_FLASH_MODEL, } from '@google/gemini-cli-core'; import type { Part, PartListUnion } from '@google/genai'; import type { UseHistoryManagerReturn } from './useHistoryManager.js'; @@ -2645,7 +2646,7 @@ describe('useGeminiStream', () => { mockAuthType, undefined, 'gemini-2.5-pro', - 'gemini-2.5-flash', + DEFAULT_GEMINI_FLASH_MODEL, ); }); }); @@ -3882,7 +3883,7 @@ describe('useGeminiStream', () => { expect.any(String), undefined, 'gemini-2.5-pro', - 'gemini-2.5-flash', + DEFAULT_GEMINI_FLASH_MODEL, ); }); diff --git a/packages/cli/src/ui/hooks/useQuotaAndFallback.test.ts b/packages/cli/src/ui/hooks/useQuotaAndFallback.test.ts index 22de364e7b1..ba248e91cc6 100644 --- a/packages/cli/src/ui/hooks/useQuotaAndFallback.test.ts +++ b/packages/cli/src/ui/hooks/useQuotaAndFallback.test.ts @@ -1245,7 +1245,7 @@ describe('useQuotaAndFallback', () => { const lastCall = (mockHistoryManager.addItem as Mock).mock.calls[0][0]; expect(lastCall.type).toBe(MessageType.INFO); expect(lastCall.text).toContain( - `Switched to fallback model gemini-2.5-flash`, + `Switched to fallback model ${DEFAULT_GEMINI_FLASH_MODEL}`, ); }); }); diff --git a/packages/core/src/availability/autoRoutingFallback.integration.test.ts b/packages/core/src/availability/autoRoutingFallback.integration.test.ts index fad2eb0bbfc..c0db157b40b 100644 --- a/packages/core/src/availability/autoRoutingFallback.integration.test.ts +++ b/packages/core/src/availability/autoRoutingFallback.integration.test.ts @@ -13,12 +13,15 @@ import { PREVIEW_GEMINI_MODEL, PREVIEW_GEMINI_FLASH_MODEL, PREVIEW_GEMINI_MODEL_AUTO, + resetModelsForTesting, } from '../config/models.js'; import fs from 'node:fs'; import { AuthType } from '../core/contentGenerator.js'; import type { FallbackIntent } from '../fallback/types.js'; import { LlmRole } from '../telemetry/types.js'; import type { GenerateContentResponse } from '@google/genai'; +import { normalizeModelId } from '../utils/modelUtils.js'; +import { ExperimentFlags } from '../code_assist/experiments/flagNames.js'; vi.mock('node:fs'); @@ -28,6 +31,7 @@ describe('Auto Routing Fallback Integration', () => { let client: BaseLlmClient; beforeEach(() => { + resetModelsForTesting(); vi.useFakeTimers(); vi.spyOn(Config.prototype, 'getHasAccessToPreviewModel').mockReturnValue( true, @@ -68,6 +72,7 @@ describe('Auto Routing Fallback Integration', () => { afterEach(() => { vi.useRealTimers(); vi.restoreAllMocks(); + resetModelsForTesting(); }); it('should fallback to Flash after 3 tries and try 10 times for Flash in auto mode', async () => { @@ -101,14 +106,15 @@ describe('Auto Routing Fallback Integration', () => { // Spy on generateContent to simulate failures vi.spyOn(fakeGenerator, 'generateContent').mockImplementation( async (params) => { - if (params.model === PREVIEW_GEMINI_MODEL) { + const modelId = normalizeModelId(params.model ?? ''); + if (modelId === PREVIEW_GEMINI_MODEL) { attemptsPro++; throw new RetryableQuotaError( 'Quota exceeded for Pro', mockGoogleApiError, 0, ); - } else if (params.model === PREVIEW_GEMINI_FLASH_MODEL) { + } else if (modelId === PREVIEW_GEMINI_FLASH_MODEL) { attemptsFlash++; throw new RetryableQuotaError( 'Quota exceeded for Flash', @@ -123,7 +129,7 @@ describe('Auto Routing Fallback Integration', () => { // Set a fallback handler that approves the switch (simulating user or auto approval) config.setFallbackModelHandler( async (failed, _fallback, _error): Promise => { - if (failed === PREVIEW_GEMINI_FLASH_MODEL) { + if (normalizeModelId(failed) === PREVIEW_GEMINI_FLASH_MODEL) { return 'stop'; // Stop retrying after Flash fails } return 'retry_always'; // Trigger fallback to Flash @@ -179,7 +185,8 @@ describe('Auto Routing Fallback Integration', () => { // Spy on generateContent to simulate failures vi.spyOn(fakeGenerator, 'generateContent').mockImplementation( async (params) => { - if (params.model === PREVIEW_GEMINI_MODEL) { + const modelId = normalizeModelId(params.model ?? ''); + if (modelId === normalizeModelId(PREVIEW_GEMINI_MODEL)) { attemptsPro++; throw new RetryableQuotaError( 'Quota exceeded for Pro', @@ -218,12 +225,96 @@ describe('Auto Routing Fallback Integration', () => { // Verify handler was called once after 10 attempts to prompt user expect(handler).toHaveBeenCalledTimes(1); expect(handler).toHaveBeenCalledWith( - PREVIEW_GEMINI_MODEL, - PREVIEW_GEMINI_FLASH_MODEL, + 'gemini-3-pro-preview', + 'gemini-3-flash-preview', expect.any(RetryableQuotaError), ); }); + it('should fallback to gemini-3.8-flash when hasLatestFlashGAAccess is enabled', async () => { + config = new Config({ + sessionId: 'test-session-latest-flash', + targetDir: '/test', + debugMode: false, + cwd: '/test', + model: PREVIEW_GEMINI_MODEL_AUTO, + }); + + vi.spyOn(config, 'isInteractive').mockReturnValue(true); + config.setExperiments({ + flags: { + [ExperimentFlags.LATEST_FLASH_GA_LAUNCHED]: { + boolValue: true, + }, + }, + experimentIds: [], + }); + + client = new BaseLlmClient( + fakeGenerator, + config, + AuthType.LOGIN_WITH_GOOGLE, + ); + + let attemptsPro = 0; + let attemptsFlash = 0; + + const mockGoogleApiError = { + code: 429, + message: 'Quota exceeded', + details: [], + }; + + vi.spyOn(fakeGenerator, 'generateContent').mockImplementation( + async (params) => { + const modelId = normalizeModelId(params.model ?? ''); + if (modelId === PREVIEW_GEMINI_MODEL) { + attemptsPro++; + throw new RetryableQuotaError( + 'Quota exceeded for Pro', + mockGoogleApiError, + 0, + ); + } else if (modelId === 'gemini-3.8-flash') { + attemptsFlash++; + return { + candidates: [ + { + content: { + role: 'model', + parts: [{ text: 'Latest flash success' }], + }, + }, + ], + } as unknown as GenerateContentResponse; + } + throw new Error(`Unexpected model: ${params.model}`); + }, + ); + + config.setFallbackModelHandler( + async (_failed, _fallback, _error): Promise => + 'retry_always', + ); + + const promise = client.generateContent({ + modelConfigKey: { model: PREVIEW_GEMINI_MODEL, isChatModel: true }, + contents: [{ role: 'user', parts: [{ text: 'test query' }] }], + abortSignal: new AbortController().signal, + promptId: 'test-prompt', + role: LlmRole.UTILITY_TOOL, + }); + + await vi.runAllTimersAsync(); + const result = await promise; + + expect(result.candidates?.[0]?.content?.parts?.[0]?.text).toBe( + 'Latest flash success', + ); + expect(attemptsPro).toBe(3); + expect(attemptsFlash).toBe(1); + }); + it('should fallback to Flash after 3 tries in experimental dynamic mode', async () => { // Instantiate real Config in auto mode const configDynamic = new Config({ @@ -261,14 +352,15 @@ describe('Auto Routing Fallback Integration', () => { // Spy on generateContent to simulate failures vi.spyOn(fakeGenerator, 'generateContent').mockImplementation( async (params) => { - if (params.model === PREVIEW_GEMINI_MODEL) { + const modelId = normalizeModelId(params.model ?? ''); + if (modelId === PREVIEW_GEMINI_MODEL) { attemptsPro++; throw new RetryableQuotaError( 'Quota exceeded for Pro', mockGoogleApiError, 0, ); - } else if (params.model === PREVIEW_GEMINI_FLASH_MODEL) { + } else if (modelId === PREVIEW_GEMINI_FLASH_MODEL) { attemptsFlash++; throw new RetryableQuotaError( 'Quota exceeded for Flash', @@ -283,7 +375,7 @@ describe('Auto Routing Fallback Integration', () => { // Set a fallback handler that approves the switch configDynamic.setFallbackModelHandler( async (failed, _fallback, _error): Promise => { - if (failed === PREVIEW_GEMINI_FLASH_MODEL) { + if (normalizeModelId(failed) === PREVIEW_GEMINI_FLASH_MODEL) { return 'stop'; } return 'retry_always'; @@ -339,14 +431,15 @@ describe('Auto Routing Fallback Integration', () => { // Turn 1: Pro fails, Flash succeeds vi.spyOn(fakeGenerator, 'generateContent').mockImplementation( async (params) => { - if (params.model === PREVIEW_GEMINI_MODEL) { + const modelId = normalizeModelId(params.model ?? ''); + if (modelId === PREVIEW_GEMINI_MODEL) { attemptsPro++; throw new RetryableQuotaError( 'Quota exceeded for Pro', mockGoogleApiError, 0, ); - } else if (params.model === PREVIEW_GEMINI_FLASH_MODEL) { + } else if (modelId === PREVIEW_GEMINI_FLASH_MODEL) { attemptsFlash++; return { candidates: [ @@ -390,7 +483,8 @@ describe('Auto Routing Fallback Integration', () => { // Let's make it succeed this time to verify it works! vi.spyOn(fakeGenerator, 'generateContent').mockImplementation( async (params) => { - if (params.model === PREVIEW_GEMINI_MODEL) { + const modelId = normalizeModelId(params.model ?? ''); + if (modelId === PREVIEW_GEMINI_MODEL) { return { candidates: [ { content: { role: 'model', parts: [{ text: 'Pro success' }] } }, @@ -445,14 +539,15 @@ describe('Auto Routing Fallback Integration', () => { vi.spyOn(fakeGenerator, 'generateContent').mockImplementation( async (params) => { - if (params.model === PREVIEW_GEMINI_MODEL) { + const modelId = normalizeModelId(params.model ?? ''); + if (modelId === PREVIEW_GEMINI_MODEL) { attemptsPro++; throw new RetryableQuotaError( 'Quota exceeded for Pro', mockGoogleApiError, 0, ); - } else if (params.model === PREVIEW_GEMINI_FLASH_MODEL) { + } else if (modelId === PREVIEW_GEMINI_FLASH_MODEL) { attemptsFlash++; return { candidates: [ diff --git a/packages/core/src/availability/policyCatalog.test.ts b/packages/core/src/availability/policyCatalog.test.ts index 9aa605abd43..214a70c9328 100644 --- a/packages/core/src/availability/policyCatalog.test.ts +++ b/packages/core/src/availability/policyCatalog.test.ts @@ -4,10 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, afterEach } from 'vitest'; import { createDefaultPolicy, getModelPolicyChain, + getFlashLitePolicyChain, validateModelPolicyChain, } from './policyCatalog.js'; import { @@ -15,9 +16,16 @@ import { PREVIEW_GEMINI_3_1_CUSTOM_TOOLS_MODEL, PREVIEW_GEMINI_3_1_MODEL, PREVIEW_GEMINI_MODEL, + setFlashLiteModel, + resetModelsForTesting, + LATEST_GEMINI_FLASH_LITE_MODEL, } from '../config/models.js'; describe('policyCatalog', () => { + afterEach(() => { + resetModelsForTesting(); + }); + it('returns preview chain when preview enabled', () => { const chain = getModelPolicyChain({ previewEnabled: true }); expect(chain[0]?.model).toBe(PREVIEW_GEMINI_MODEL); @@ -74,6 +82,12 @@ describe('policyCatalog', () => { expect(secondCall[0].actions.terminal).toBe('prompt'); }); + it('updates getFlashLitePolicyChain head when setFlashLiteModel is called', () => { + setFlashLiteModel(LATEST_GEMINI_FLASH_LITE_MODEL); + const chain = getFlashLitePolicyChain(); + expect(chain[0]?.model).toBe(LATEST_GEMINI_FLASH_LITE_MODEL); + }); + it('passes when there is exactly one last-resort policy', () => { const validChain = [ createDefaultPolicy('test-model'), diff --git a/packages/core/src/availability/policyCatalog.ts b/packages/core/src/availability/policyCatalog.ts index e2d1df075ea..0d71d8a4e1d 100644 --- a/packages/core/src/availability/policyCatalog.ts +++ b/packages/core/src/availability/policyCatalog.ts @@ -31,8 +31,10 @@ export interface ModelPolicyOptions { isAutoSelection?: boolean; userTier?: UserTierId; useGemini31?: boolean; + useLatestFlashLite?: boolean; useGemini31FlashLite?: boolean; useCustomToolModel?: boolean; + useLatestFlash?: boolean; useGemini3_5Flash?: boolean; } @@ -66,22 +68,6 @@ const AUTO_ROUTING_OVERRIDES = { } as ModelPolicyStateMap, }; -const FLASH_LITE_CHAIN: ModelPolicyChain = [ - definePolicy({ - model: DEFAULT_GEMINI_FLASH_LITE_MODEL, - actions: SILENT_ACTIONS, - }), - definePolicy({ - model: DEFAULT_GEMINI_FLASH_MODEL, - actions: SILENT_ACTIONS, - }), - definePolicy({ - model: DEFAULT_GEMINI_MODEL, - isLastResort: true, - actions: SILENT_ACTIONS, - }), -]; - /** * Returns the default ordered model policy chain for the user. */ @@ -97,7 +83,8 @@ export function getModelPolicyChain( options.useCustomToolModel, true, undefined, - options.useGemini3_5Flash, + options.useLatestFlash, + options.useLatestFlashLite, ); return [ definePolicy({ @@ -136,7 +123,21 @@ export function createSingleModelChain(model: string): ModelPolicyChain { } export function getFlashLitePolicyChain(): ModelPolicyChain { - return cloneChain(FLASH_LITE_CHAIN); + return [ + definePolicy({ + model: DEFAULT_GEMINI_FLASH_LITE_MODEL, + actions: SILENT_ACTIONS, + }), + definePolicy({ + model: DEFAULT_GEMINI_FLASH_MODEL, + actions: SILENT_ACTIONS, + }), + definePolicy({ + model: DEFAULT_GEMINI_MODEL, + isLastResort: true, + actions: SILENT_ACTIONS, + }), + ]; } /** @@ -178,15 +179,3 @@ function definePolicy(config: PolicyConfig): ModelPolicy { }, }; } - -function clonePolicy(policy: ModelPolicy): ModelPolicy { - return { - ...policy, - actions: { ...policy.actions }, - stateTransitions: { ...policy.stateTransitions }, - }; -} - -function cloneChain(chain: ModelPolicyChain): ModelPolicyChain { - return chain.map(clonePolicy); -} diff --git a/packages/core/src/availability/policyHelpers.test.ts b/packages/core/src/availability/policyHelpers.test.ts index 0d4a25e8c49..5126bc228b8 100644 --- a/packages/core/src/availability/policyHelpers.test.ts +++ b/packages/core/src/availability/policyHelpers.test.ts @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { resolvePolicyChain, buildFallbackPolicyContext, @@ -16,9 +16,11 @@ import type { RetryAvailabilityContext } from './modelPolicy.js'; import type { Config } from '../config/config.js'; import { DEFAULT_GEMINI_FLASH_LITE_MODEL, + BASE_GEMINI_FLASH_MODEL, DEFAULT_GEMINI_MODEL_AUTO, PREVIEW_GEMINI_3_1_CUSTOM_TOOLS_MODEL, PREVIEW_GEMINI_3_1_MODEL, + resetModelsForTesting, } from '../config/models.js'; import { AuthType } from '../core/contentGenerator.js'; import { ModelConfigService } from '../services/modelConfigService.js'; @@ -47,6 +49,14 @@ const createMockConfig = (overrides: Partial = {}): Config => { }; describe('policyHelpers', () => { + beforeEach(() => { + resetModelsForTesting(); + }); + + afterEach(() => { + resetModelsForTesting(); + }); + describe('resolvePolicyChain', () => { it('returns a single-model chain for a custom model', () => { const config = createMockConfig({ @@ -74,7 +84,7 @@ describe('policyHelpers', () => { // Expect default chain [Pro, Flash] expect(chain).toHaveLength(2); expect(chain[0]?.model).toBe('gemini-2.5-pro'); - expect(chain[1]?.model).toBe('gemini-2.5-flash'); + expect(chain[1]?.model).toBe(BASE_GEMINI_FLASH_MODEL); }); it('uses auto chain when preferred model is auto', () => { @@ -84,7 +94,7 @@ describe('policyHelpers', () => { const chain = resolvePolicyChain(config, DEFAULT_GEMINI_MODEL_AUTO); expect(chain).toHaveLength(2); expect(chain[0]?.model).toBe('gemini-2.5-pro'); - expect(chain[1]?.model).toBe('gemini-2.5-flash'); + expect(chain[1]?.model).toBe(BASE_GEMINI_FLASH_MODEL); }); it('uses auto chain when configured model is auto even if preferred is concrete', () => { @@ -94,17 +104,17 @@ describe('policyHelpers', () => { const chain = resolvePolicyChain(config, 'gemini-2.5-pro'); expect(chain).toHaveLength(2); expect(chain[0]?.model).toBe('gemini-2.5-pro'); - expect(chain[1]?.model).toBe('gemini-2.5-flash'); + expect(chain[1]?.model).toBe(BASE_GEMINI_FLASH_MODEL); }); it('starts chain from preferredModel when model is "auto"', () => { const config = createMockConfig({ getModel: () => 'auto', }); - const chain = resolvePolicyChain(config, 'gemini-2.5-flash'); + const chain = resolvePolicyChain(config, BASE_GEMINI_FLASH_MODEL); // Due to Gemini 2.x wrapsAround, the chain will contain both flash and pro expect(chain.length).toBeGreaterThanOrEqual(1); - expect(chain[0]?.model).toBe('gemini-2.5-flash'); + expect(chain[0]?.model).toBe(BASE_GEMINI_FLASH_MODEL); }); it('returns flash-lite chain when preferred model is flash-lite', () => { @@ -114,7 +124,7 @@ describe('policyHelpers', () => { const chain = resolvePolicyChain(config, DEFAULT_GEMINI_FLASH_LITE_MODEL); expect(chain).toHaveLength(3); expect(chain[0]?.model).toBe('gemini-3.1-flash-lite'); - expect(chain[1]?.model).toBe('gemini-2.5-flash'); + expect(chain[1]?.model).toBe(BASE_GEMINI_FLASH_MODEL); expect(chain[2]?.model).toBe('gemini-2.5-pro'); }); @@ -125,7 +135,7 @@ describe('policyHelpers', () => { const chain = resolvePolicyChain(config); expect(chain).toHaveLength(3); expect(chain[0]?.model).toBe('gemini-3.1-flash-lite'); - expect(chain[1]?.model).toBe('gemini-2.5-flash'); + expect(chain[1]?.model).toBe(BASE_GEMINI_FLASH_MODEL); expect(chain[2]?.model).toBe('gemini-2.5-pro'); }); @@ -133,9 +143,9 @@ describe('policyHelpers', () => { const config = createMockConfig({ getModel: () => DEFAULT_GEMINI_MODEL_AUTO, }); - const chain = resolvePolicyChain(config, 'gemini-2.5-flash', true); + const chain = resolvePolicyChain(config, BASE_GEMINI_FLASH_MODEL, true); expect(chain).toHaveLength(2); - expect(chain[0]?.model).toBe('gemini-2.5-flash'); + expect(chain[0]?.model).toBe(BASE_GEMINI_FLASH_MODEL); expect(chain[1]?.model).toBe('gemini-2.5-pro'); }); @@ -146,10 +156,10 @@ describe('policyHelpers', () => { }); const chain = resolvePolicyChain(config); - // Should downgrade to [Pro 2.5, Flash 2.5] + // Should downgrade to [Pro 2.5, Flash 3.5] expect(chain).toHaveLength(2); expect(chain[0]?.model).toBe('gemini-2.5-pro'); - expect(chain[1]?.model).toBe('gemini-2.5-flash'); + expect(chain[1]?.model).toBe(BASE_GEMINI_FLASH_MODEL); }); it('returns Gemini 3.1 Pro chain when launched and auto-gemini-3 requested', () => { diff --git a/packages/core/src/availability/policyHelpers.ts b/packages/core/src/availability/policyHelpers.ts index 71b8240120d..474f5ff0041 100644 --- a/packages/core/src/availability/policyHelpers.ts +++ b/packages/core/src/availability/policyHelpers.ts @@ -23,6 +23,7 @@ import { import { DEFAULT_GEMINI_FLASH_LITE_MODEL, DEFAULT_GEMINI_MODEL, + DEFAULT_GEMINI_MODEL_AUTO, PREVIEW_GEMINI_MODEL_AUTO, isAutoModel, isGemini3Model, @@ -54,7 +55,8 @@ export function resolvePolicyChain( const useGemini31 = config.getGemini31LaunchedSync?.() ?? false; const useCustomToolModel = config.getUseCustomToolModelSync?.() ?? false; const hasAccessToPreview = config.getHasAccessToPreviewModel?.() ?? false; - const useGemini3_5Flash = config.hasGemini35FlashGAAccess?.() ?? false; + const useLatestFlash = config.hasLatestFlashGAAccess?.() ?? false; + const useLatestFlashLite = config.hasLatestFlashLiteGAAccess?.() ?? false; // Capture the original family intent before any normalization or early downgrade. const isOriginallyGemini3 = isGemini3Model(modelFromConfig, config); @@ -66,7 +68,8 @@ export function resolvePolicyChain( useCustomToolModel, hasAccessToPreview, config, - useGemini3_5Flash, + useLatestFlash, + useLatestFlashLite, ), ); const isAutoPreferred = normalizedPreferredModel @@ -84,7 +87,8 @@ export function resolvePolicyChain( const context = { useGemini3_1: useGemini31, useCustomTools: useCustomToolModel, - useGemini3_5Flash, + useLatestFlash, + useLatestFlashLite, }; if (resolvedModel === DEFAULT_GEMINI_FLASH_LITE_MODEL) { @@ -105,6 +109,7 @@ export function resolvePolicyChain( const isAutoSelection = isAutoPreferred || isAutoConfigured; const previewEnabled = hasAccessToPreview && + configuredModel !== DEFAULT_GEMINI_MODEL_AUTO && (isGemini3Model(resolvedModel, config) || normalizedPreferredModel === PREVIEW_GEMINI_MODEL_AUTO || configuredModel === PREVIEW_GEMINI_MODEL_AUTO); @@ -130,16 +135,18 @@ export function resolvePolicyChain( const isAutoSelection = isAutoPreferred || isAutoConfigured; if (hasAccessToPreview) { const previewEnabled = - isOriginallyGemini3 || - normalizedPreferredModel === PREVIEW_GEMINI_MODEL_AUTO || - configuredModel === PREVIEW_GEMINI_MODEL_AUTO; + configuredModel !== DEFAULT_GEMINI_MODEL_AUTO && + (isOriginallyGemini3 || + normalizedPreferredModel === PREVIEW_GEMINI_MODEL_AUTO || + configuredModel === PREVIEW_GEMINI_MODEL_AUTO); chain = getModelPolicyChain({ previewEnabled, isAutoSelection, userTier: config.getUserTier(), useGemini31, useCustomToolModel, - useGemini3_5Flash, + useLatestFlash, + useLatestFlashLite, }); } else { // User requested Gemini 3 but has no access. Proactively downgrade @@ -150,7 +157,8 @@ export function resolvePolicyChain( userTier: config.getUserTier(), useGemini31, useCustomToolModel, - useGemini3_5Flash, + useLatestFlash, + useLatestFlashLite, }); } } else { @@ -265,10 +273,10 @@ export function selectModelForAvailability( ): ModelSelectionResult { const chain = resolvePolicyChain(config, requestedModel); const selection = config - .getModelAvailabilityService() - .selectFirstAvailable(chain.map((p) => p.model)); + .getModelAvailabilityService?.() + ?.selectFirstAvailable(chain.map((p) => p.model)); - if (selection.selectedModel) return selection; + if (selection?.selectedModel) return selection; const backupModel = chain.find((p) => p.isLastResort)?.model ?? DEFAULT_GEMINI_MODEL; diff --git a/packages/core/src/code_assist/experiments/flagNames.ts b/packages/core/src/code_assist/experiments/flagNames.ts index ceb9b2e0f41..fdf74a19d2d 100644 --- a/packages/core/src/code_assist/experiments/flagNames.ts +++ b/packages/core/src/code_assist/experiments/flagNames.ts @@ -19,6 +19,9 @@ export const ExperimentFlags = { GEMINI_3_1_PRO_LAUNCHED: 45760185, PRO_MODEL_NO_ACCESS: 45768879, DEFAULT_REQUEST_TIMEOUT: 45773134, + LATEST_FLASH_GA_LAUNCHED: 45842815, + LATEST_FLASH_LITE_GA_LAUNCHED: 45827489, + /** @deprecated Use LATEST_FLASH_GA_LAUNCHED */ GEMINI_3_5_FLASH_GA_LAUNCHED: 45780819, } as const; diff --git a/packages/core/src/config/config.test.ts b/packages/core/src/config/config.test.ts index 2de08cb6841..97790f365b7 100644 --- a/packages/core/src/config/config.test.ts +++ b/packages/core/src/config/config.test.ts @@ -70,6 +70,8 @@ import { PREVIEW_GEMINI_MODEL_AUTO, PREVIEW_GEMINI_FLASH_MODEL, DEFAULT_GEMINI_FLASH_MODEL, + DEFAULT_GEMINI_FLASH_LITE_MODEL, + resetModelsForTesting, } from './models.js'; import { Storage } from './storage.js'; import type { AgentLoopContext } from './agent-loop-context.js'; @@ -279,6 +281,7 @@ vi.mock('../code_assist/experiments/experiments.js'); afterEach(() => { vi.clearAllMocks(); + resetModelsForTesting(); }); describe('Server Config (config.ts)', () => { @@ -3231,7 +3234,7 @@ describe('Config Quota & Preview Model Access', () => { remainingFraction: 0.2, }, { - modelId: 'gemini-2.5-flash', + modelId: 'gemini-3.5-flash', remainingAmount: '80', remainingFraction: 0.8, }, @@ -4376,7 +4379,7 @@ describe('ADKSettings', () => { }); }); -describe('hasGemini35FlashGAAccess model setting', () => { +describe('hasLatestFlashGAAccess model setting', () => { const baseParams: ConfigParameters = { sessionId: 'test', targetDir: '.', @@ -4385,47 +4388,170 @@ describe('hasGemini35FlashGAAccess model setting', () => { cwd: '.', }; - it('should set DEFAULT_GEMINI_FLASH_MODEL to gemini-3.5-flash and PREVIEW_GEMINI_FLASH_MODEL to gemini-3-flash-preview if hasGemini35FlashGAAccess returns true and authType is USE_GEMINI', () => { + it('should set DEFAULT_GEMINI_FLASH_MODEL to gemini-3.8-flash and PREVIEW_GEMINI_FLASH_MODEL to gemini-3-flash-preview if hasLatestFlashGAAccess returns true and authType is USE_GEMINI', () => { const config = new Config(baseParams); config['contentGeneratorConfig'] = { authType: AuthType.USE_GEMINI }; - // Set experiment to return true for GEMINI_3_5_FLASH_GA_LAUNCHED + // Set experiment to return true for LATEST_FLASH_GA_LAUNCHED config.setExperiments({ experimentIds: [], flags: { - [ExperimentFlags.GEMINI_3_5_FLASH_GA_LAUNCHED]: { + [ExperimentFlags.LATEST_FLASH_GA_LAUNCHED]: { boolValue: true, }, }, }); // Call the method - const result = config.hasGemini35FlashGAAccess(); + const result = config.hasLatestFlashGAAccess(); expect(result).toBe(true); - expect(DEFAULT_GEMINI_FLASH_MODEL).toBe('gemini-3.5-flash'); + expect(DEFAULT_GEMINI_FLASH_MODEL).toBe('gemini-3.8-flash'); expect(PREVIEW_GEMINI_FLASH_MODEL).toBe('gemini-3-flash-preview'); }); - it('should set DEFAULT_GEMINI_FLASH_MODEL and PREVIEW_GEMINI_FLASH_MODEL to gemini-3.5-flash if hasGemini35FlashGAAccess returns true and authType is not USE_GEMINI', () => { + it('should set DEFAULT_GEMINI_FLASH_MODEL and PREVIEW_GEMINI_FLASH_MODEL to gemini-3.8-flash if hasLatestFlashGAAccess returns true and authType is not USE_GEMINI', () => { const config = new Config(baseParams); config['contentGeneratorConfig'] = { authType: AuthType.LOGIN_WITH_GOOGLE }; - // Set experiment to return true for GEMINI_3_5_FLASH_GA_LAUNCHED + // Set experiment to return true for LATEST_FLASH_GA_LAUNCHED config.setExperiments({ experimentIds: [], flags: { - [ExperimentFlags.GEMINI_3_5_FLASH_GA_LAUNCHED]: { + [ExperimentFlags.LATEST_FLASH_GA_LAUNCHED]: { boolValue: true, }, }, }); // Call the method - const result = config.hasGemini35FlashGAAccess(); + const result = config.hasLatestFlashGAAccess(); expect(result).toBe(true); + expect(DEFAULT_GEMINI_FLASH_MODEL).toBe('gemini-3.8-flash'); + expect(PREVIEW_GEMINI_FLASH_MODEL).toBe('gemini-3.8-flash'); + }); + + it.each([AuthType.USE_GEMINI, AuthType.USE_VERTEX_AI, AuthType.GATEWAY])( + 'should return true even if experiment flag is false when authType is %s', + (authType) => { + const config = new Config(baseParams); + config['contentGeneratorConfig'] = { authType }; + + config.setExperiments({ + experimentIds: [], + flags: { + [ExperimentFlags.LATEST_FLASH_GA_LAUNCHED]: { + boolValue: false, + }, + }, + }); + + const result = config.hasLatestFlashGAAccess(); + expect(result).toBe(true); + + if (authType === AuthType.USE_GEMINI) { + expect(DEFAULT_GEMINI_FLASH_MODEL).toBe('gemini-3.8-flash'); + expect(PREVIEW_GEMINI_FLASH_MODEL).toBe('gemini-3-flash-preview'); + } else { + expect(DEFAULT_GEMINI_FLASH_MODEL).toBe('gemini-3.8-flash'); + expect(PREVIEW_GEMINI_FLASH_MODEL).toBe('gemini-3.8-flash'); + } + }, + ); + + it('should return false if experiment flag is false when authType is not in launch list (e.g. LOGIN_WITH_GOOGLE)', () => { + const config = new Config(baseParams); + config['contentGeneratorConfig'] = { authType: AuthType.LOGIN_WITH_GOOGLE }; + + config.setExperiments({ + experimentIds: [], + flags: { + [ExperimentFlags.LATEST_FLASH_GA_LAUNCHED]: { + boolValue: false, + }, + }, + }); + + const result = config.hasLatestFlashGAAccess(); + expect(result).toBe(false); + expect(DEFAULT_GEMINI_FLASH_MODEL).toBe('gemini-3.5-flash'); - expect(PREVIEW_GEMINI_FLASH_MODEL).toBe('gemini-3.5-flash'); + expect(PREVIEW_GEMINI_FLASH_MODEL).toBe('gemini-3-flash-preview'); + }); +}); + +describe('hasLatestFlashLiteGAAccess model setting', () => { + const baseParams: ConfigParameters = { + sessionId: 'test', + targetDir: '.', + debugMode: false, + model: 'test-model', + cwd: '.', + }; + + beforeEach(() => { + resetModelsForTesting(); + }); + + afterEach(() => { + resetModelsForTesting(); + }); + + it.each([AuthType.USE_GEMINI, AuthType.USE_VERTEX_AI, AuthType.GATEWAY])( + 'should return true and set DEFAULT_GEMINI_FLASH_LITE_MODEL even if experiment flag is false when authType is %s', + (authType) => { + const config = new Config(baseParams); + config['contentGeneratorConfig'] = { authType }; + + config.setExperiments({ + experimentIds: [], + flags: { + [ExperimentFlags.LATEST_FLASH_LITE_GA_LAUNCHED]: { + boolValue: false, + }, + }, + }); + + const result = config.hasLatestFlashLiteGAAccess(); + expect(result).toBe(true); + expect(DEFAULT_GEMINI_FLASH_LITE_MODEL).toBe('gemini-3.5-flash-lite'); + }, + ); + + it('should return true and set DEFAULT_GEMINI_FLASH_LITE_MODEL if experiment flag is true for other auth types', () => { + const config = new Config(baseParams); + config['contentGeneratorConfig'] = { authType: AuthType.LOGIN_WITH_GOOGLE }; + + config.setExperiments({ + experimentIds: [], + flags: { + [ExperimentFlags.LATEST_FLASH_LITE_GA_LAUNCHED]: { + boolValue: true, + }, + }, + }); + + const result = config.hasLatestFlashLiteGAAccess(); + expect(result).toBe(true); + expect(DEFAULT_GEMINI_FLASH_LITE_MODEL).toBe('gemini-3.5-flash-lite'); + }); + + it('should return false and keep base model if experiment flag is false for other auth types', () => { + const config = new Config(baseParams); + config['contentGeneratorConfig'] = { authType: AuthType.LOGIN_WITH_GOOGLE }; + + config.setExperiments({ + experimentIds: [], + flags: { + [ExperimentFlags.LATEST_FLASH_LITE_GA_LAUNCHED]: { + boolValue: false, + }, + }, + }); + + const result = config.hasLatestFlashLiteGAAccess(); + expect(result).toBe(false); + expect(DEFAULT_GEMINI_FLASH_LITE_MODEL).toBe('gemini-3.1-flash-lite'); }); }); diff --git a/packages/core/src/config/config.ts b/packages/core/src/config/config.ts index ec20f68c381..db7d51990aa 100644 --- a/packages/core/src/config/config.ts +++ b/packages/core/src/config/config.ts @@ -87,8 +87,12 @@ import { PREVIEW_GEMINI_FLASH_MODEL, resolveModel, setFlashModels, - DEFAULT_GEMINI_3_5_FLASH_MODEL, - SECONDARY_GEMINI_3_5_FLASH_MODEL, + BASE_GEMINI_FLASH_MODEL, + LATEST_GEMINI_FLASH_MODEL, + LEGACY_CCPA_FLASH_MODEL, + BASE_GEMINI_FLASH_LITE_MODEL, + LATEST_GEMINI_FLASH_LITE_MODEL, + setFlashLiteModel, } from './models.js'; import { shouldAttemptBrowserLaunch } from '../utils/browser.js'; import type { MCPOAuthConfig } from '../mcp/oauth-provider.js'; @@ -2068,7 +2072,8 @@ export class Config implements McpContext, AgentLoopContext { this.getUseCustomToolModelSync(), this.getHasAccessToPreviewModel(), this, - this.hasGemini35FlashGAAccess(), + this.hasLatestFlashGAAccess(), + this.hasLatestFlashLiteGAAccess(), ); const isPreview = isPreviewModel(primaryModel, this); @@ -2108,7 +2113,8 @@ export class Config implements McpContext, AgentLoopContext { this.getUseCustomToolModelSync(), this.getHasAccessToPreviewModel(), this, - this.hasGemini35FlashGAAccess(), + this.hasLatestFlashGAAccess(), + this.hasLatestFlashLiteGAAccess(), ); return this.modelQuotas.get(primaryModel)?.remaining; } @@ -2124,7 +2130,8 @@ export class Config implements McpContext, AgentLoopContext { this.getUseCustomToolModelSync(), this.getHasAccessToPreviewModel(), this, - this.hasGemini35FlashGAAccess(), + this.hasLatestFlashGAAccess(), + this.hasLatestFlashLiteGAAccess(), ); return this.modelQuotas.get(primaryModel)?.limit; } @@ -2140,7 +2147,8 @@ export class Config implements McpContext, AgentLoopContext { this.getUseCustomToolModelSync(), this.getHasAccessToPreviewModel(), this, - this.hasGemini35FlashGAAccess(), + this.hasLatestFlashGAAccess(), + this.hasLatestFlashLiteGAAccess(), ); return this.modelQuotas.get(primaryModel)?.resetTime; } @@ -2324,8 +2332,21 @@ export class Config implements McpContext, AgentLoopContext { } let modelId = bucket.modelId; - if (modelId === SECONDARY_GEMINI_3_5_FLASH_MODEL) { - modelId = DEFAULT_GEMINI_3_5_FLASH_MODEL; + if ( + modelId === LEGACY_CCPA_FLASH_MODEL || + modelId === BASE_GEMINI_FLASH_MODEL || + modelId === LATEST_GEMINI_FLASH_MODEL + ) { + modelId = this.hasLatestFlashGAAccess() + ? LATEST_GEMINI_FLASH_MODEL + : BASE_GEMINI_FLASH_MODEL; + } else if ( + modelId === BASE_GEMINI_FLASH_LITE_MODEL || + modelId === LATEST_GEMINI_FLASH_LITE_MODEL + ) { + modelId = this.hasLatestFlashLiteGAAccess() + ? LATEST_GEMINI_FLASH_LITE_MODEL + : BASE_GEMINI_FLASH_LITE_MODEL; } let remaining: number; @@ -3572,37 +3593,58 @@ export class Config implements McpContext, AgentLoopContext { } /** - * Returns whether Gemini 3.5 Flash GA has been launched. - * - * Note: This method should only be called after startup, once experiments have been loaded. + * Returns whether the latest Flash GA model (currently Gemini 3.8 Flash) has been launched. */ - hasGemini35FlashGAAccess(): boolean { + hasLatestFlashGAAccess(): boolean { const authType = this.contentGeneratorConfig?.authType; const hasAccess = (() => { if (this.isGemini31LaunchedForAuthType(authType)) { return true; } return ( - this.experiments?.flags[ExperimentFlags.GEMINI_3_5_FLASH_GA_LAUNCHED] + this.experiments?.flags[ExperimentFlags.LATEST_FLASH_GA_LAUNCHED] ?.boolValue ?? false ); })(); - // Used to set default flash models based on access - // TODO: Remove once the experiment for 3_5 flash rollut can be cleaned up. + if (hasAccess) { - // Gemini API key users should have the ability to manually select the - // old preview flash model. if (authType === AuthType.USE_GEMINI) { - setFlashModels('gemini-3-flash-preview', 'gemini-3.5-flash'); + setFlashModels('gemini-3-flash-preview', LATEST_GEMINI_FLASH_MODEL); } else { - setFlashModels('gemini-3.5-flash', 'gemini-3.5-flash'); + setFlashModels(LATEST_GEMINI_FLASH_MODEL, LATEST_GEMINI_FLASH_MODEL); } } else { - setFlashModels('gemini-3-flash-preview', 'gemini-2.5-flash'); + setFlashModels('gemini-3-flash-preview', BASE_GEMINI_FLASH_MODEL); } return hasAccess; } + /** @deprecated Use hasLatestFlashGAAccess() */ + hasGemini35FlashGAAccess(): boolean { + return this.hasLatestFlashGAAccess(); + } + + /** + * Returns whether the latest Flash Lite GA model (currently Gemini 3.5 Flash Lite) has been launched. + */ + hasLatestFlashLiteGAAccess(): boolean { + const authType = this.contentGeneratorConfig?.authType; + const hasAccess = (() => { + if (this.isGemini31LaunchedForAuthType(authType)) { + return true; + } + return ( + this.experiments?.flags[ExperimentFlags.LATEST_FLASH_LITE_GA_LAUNCHED] + ?.boolValue ?? false + ); + })(); + + setFlashLiteModel( + hasAccess ? LATEST_GEMINI_FLASH_LITE_MODEL : BASE_GEMINI_FLASH_LITE_MODEL, + ); + return hasAccess; + } + /** * Returns whether Gemini 3.1 has been launched. * @@ -4175,6 +4217,8 @@ export class Config implements McpContext, AgentLoopContext { compact: false, }); debugLogger.debug('Experiments loaded', summaryString); + this.hasLatestFlashGAAccess(); + this.hasLatestFlashLiteGAAccess(); } private onAgentsRefreshed = async () => { diff --git a/packages/core/src/config/defaultModelConfigs.ts b/packages/core/src/config/defaultModelConfigs.ts index 056b91b351d..b9e579d5cd0 100644 --- a/packages/core/src/config/defaultModelConfigs.ts +++ b/packages/core/src/config/defaultModelConfigs.ts @@ -6,7 +6,14 @@ import { ThinkingLevel } from '@google/genai'; import type { ModelConfigServiceConfig } from '../services/modelConfigService.js'; -import { DEFAULT_THINKING_MODE } from './models.js'; +import { + DEFAULT_THINKING_MODE, + BASE_GEMINI_FLASH_MODEL, + LATEST_GEMINI_FLASH_MODEL, + BASE_GEMINI_FLASH_LITE_MODEL, + LATEST_GEMINI_FLASH_LITE_MODEL, + DEFAULT_GEMINI_MODEL, +} from './models.js'; // The default model configs. We use `base` as the parent for all of our model // configs, while `chat-base`, a child of `base`, is the parent of the models @@ -113,12 +120,24 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { model: 'gemini-3.1-flash-lite', }, }, + 'gemini-3.5-flash-lite': { + extends: 'chat-base-3', + modelConfig: { + model: 'gemini-3.5-flash-lite', + }, + }, 'gemini-3.5-flash': { extends: 'chat-base-3', modelConfig: { model: 'gemini-3.5-flash', }, }, + 'gemini-3.8-flash': { + extends: 'chat-base-3', + modelConfig: { + model: 'gemini-3.8-flash', + }, + }, 'gemma-4-31b-it': { extends: 'chat-base-3', modelConfig: { @@ -330,6 +349,13 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { isVisible: true, features: { thinking: false, multimodalToolUse: true }, }, + 'gemini-3.5-flash-lite': { + tier: 'flash-lite', + family: 'gemini-3', + isPreview: false, + isVisible: true, + features: { thinking: false, multimodalToolUse: true }, + }, 'gemini-3.1-pro-preview': { tier: 'pro', family: 'gemini-3', @@ -365,6 +391,13 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { isVisible: true, features: { thinking: false, multimodalToolUse: true }, }, + 'gemini-3.8-flash': { + tier: 'flash', + family: 'gemini-3', + isPreview: false, + isVisible: true, + features: { thinking: false, multimodalToolUse: true }, + }, 'gemini-2.5-pro': { tier: 'pro', family: 'gemini-2.5', @@ -470,32 +503,40 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { default: 'gemini-3-flash-preview', contexts: [ { - condition: { hasAccessToPreview: false, useGemini3_5Flash: true }, - target: 'gemini-3.5-flash', + condition: { hasAccessToPreview: false, useLatestFlash: true }, + target: LATEST_GEMINI_FLASH_MODEL, }, { - condition: { hasAccessToPreview: false, useGemini3_5Flash: false }, - target: 'gemini-2.5-flash', + condition: { hasAccessToPreview: false, useLatestFlash: false }, + target: BASE_GEMINI_FLASH_MODEL, }, ], }, - 'gemini-3.5-flash': { - default: 'gemini-3.5-flash', + [BASE_GEMINI_FLASH_MODEL]: { + default: BASE_GEMINI_FLASH_MODEL, contexts: [ { - condition: { useGemini3_5Flash: false, hasAccessToPreview: false }, - target: 'gemini-2.5-flash', + condition: { useLatestFlash: true }, + target: LATEST_GEMINI_FLASH_MODEL, }, + ], + }, + [LATEST_GEMINI_FLASH_MODEL]: { + default: LATEST_GEMINI_FLASH_MODEL, + contexts: [ { - condition: { useGemini3_5Flash: false }, - target: 'gemini-3-flash-preview', + condition: { useLatestFlash: false }, + target: BASE_GEMINI_FLASH_MODEL, }, ], }, 'gemini-2.5-flash': { default: 'gemini-2.5-flash', contexts: [ - { condition: { useGemini3_5Flash: true }, target: 'gemini-3.5-flash' }, + { + condition: { useLatestFlash: true }, + target: LATEST_GEMINI_FLASH_MODEL, + }, ], }, 'gemini-3-pro-preview': { @@ -540,21 +581,45 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { }, ], }, - 'gemini-3.1-flash-lite': { - default: 'gemini-3.1-flash-lite', + [BASE_GEMINI_FLASH_LITE_MODEL]: { + default: BASE_GEMINI_FLASH_LITE_MODEL, + contexts: [ + { + condition: { useLatestFlashLite: true }, + target: LATEST_GEMINI_FLASH_LITE_MODEL, + }, + ], + }, + [LATEST_GEMINI_FLASH_LITE_MODEL]: { + default: LATEST_GEMINI_FLASH_LITE_MODEL, + contexts: [ + { + condition: { useLatestFlashLite: false }, + target: BASE_GEMINI_FLASH_LITE_MODEL, + }, + ], }, flash: { default: 'gemini-3-flash-preview', contexts: [ - { condition: { useGemini3_5Flash: true }, target: 'gemini-3.5-flash' }, + { + condition: { useLatestFlash: true }, + target: LATEST_GEMINI_FLASH_MODEL, + }, { condition: { hasAccessToPreview: false }, - target: 'gemini-2.5-flash', + target: BASE_GEMINI_FLASH_MODEL, }, ], }, 'flash-lite': { - default: 'gemini-3.1-flash-lite', + default: BASE_GEMINI_FLASH_LITE_MODEL, + contexts: [ + { + condition: { useLatestFlashLite: true }, + target: LATEST_GEMINI_FLASH_LITE_MODEL, + }, + ], }, 'auto-gemini-3': { default: 'gemini-3-pro-preview', @@ -578,14 +643,17 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { flash: { default: 'gemini-3-flash-preview', contexts: [ - { condition: { useGemini3_5Flash: true }, target: 'gemini-3.5-flash' }, + { + condition: { useLatestFlash: true }, + target: LATEST_GEMINI_FLASH_MODEL, + }, { condition: { hasAccessToPreview: false }, - target: 'gemini-2.5-flash', + target: BASE_GEMINI_FLASH_MODEL, }, { condition: { requestedModels: ['gemini-2.5-pro', 'auto-gemini-2.5'] }, - target: 'gemini-2.5-flash', + target: BASE_GEMINI_FLASH_MODEL, }, ], }, @@ -683,7 +751,7 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { ], default: [ { - model: 'gemini-2.5-pro', + model: DEFAULT_GEMINI_MODEL, actions: { terminal: 'prompt', transient: 'prompt', @@ -698,7 +766,7 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { }, }, { - model: 'gemini-2.5-flash', + model: BASE_GEMINI_FLASH_MODEL, isLastResort: true, maxAttempts: 10, actions: { @@ -717,7 +785,7 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { ], 'auto-default': [ { - model: 'gemini-2.5-pro', + model: DEFAULT_GEMINI_MODEL, maxAttempts: 3, actions: { terminal: 'prompt', @@ -733,7 +801,7 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { }, }, { - model: 'gemini-2.5-flash', + model: BASE_GEMINI_FLASH_MODEL, isLastResort: true, maxAttempts: 10, actions: { @@ -752,7 +820,7 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { ], lite: [ { - model: 'flash-lite', + model: BASE_GEMINI_FLASH_LITE_MODEL, actions: { terminal: 'silent', transient: 'silent', @@ -767,7 +835,7 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { }, }, { - model: 'gemini-2.5-flash', + model: BASE_GEMINI_FLASH_MODEL, actions: { terminal: 'silent', transient: 'silent', @@ -782,7 +850,7 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { }, }, { - model: 'gemini-2.5-pro', + model: DEFAULT_GEMINI_MODEL, isLastResort: true, actions: { terminal: 'silent', diff --git a/packages/core/src/config/models.test.ts b/packages/core/src/config/models.test.ts index 63185f77614..c4368199f6a 100644 --- a/packages/core/src/config/models.test.ts +++ b/packages/core/src/config/models.test.ts @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; import { resolveModel, resolveClassifierModel, @@ -17,8 +17,12 @@ import { DEFAULT_GEMINI_MODEL, PREVIEW_GEMINI_MODEL, DEFAULT_GEMINI_FLASH_MODEL, - DEFAULT_GEMINI_3_5_FLASH_MODEL, DEFAULT_GEMINI_FLASH_LITE_MODEL, + BASE_GEMINI_FLASH_MODEL, + BASE_GEMINI_FLASH_LITE_MODEL, + setFlashModels, + setFlashLiteModel, + resetModelsForTesting, supportsMultimodalFunctionResponse, GEMINI_MODEL_ALIAS_PRO, GEMINI_MODEL_ALIAS_FLASH, @@ -33,6 +37,8 @@ import { PREVIEW_GEMINI_3_1_CUSTOM_TOOLS_MODEL, isPreviewModel, isProModel, + LATEST_GEMINI_FLASH_MODEL, + LATEST_GEMINI_FLASH_LITE_MODEL, GEMMA_4_31B_IT_MODEL, GEMMA_4_26B_A4B_IT_MODEL, getAutoModelDescription, @@ -43,6 +49,10 @@ import { DEFAULT_MODEL_CONFIGS } from './defaultModelConfigs.js'; const modelConfigService = new ModelConfigService(DEFAULT_MODEL_CONFIGS); +afterEach(() => { + resetModelsForTesting(); +}); + const dynamicConfig = { getExperimentalDynamicModelConfiguration: () => true, modelConfigService, @@ -731,7 +741,7 @@ describe('getAutoModelDescription', () => { it('should return Gemini 2.5 description when hasAccessToPreview is false', () => { const desc = getAutoModelDescription(false, false); expect(desc).toContain('gemini-2.5-pro'); - expect(desc).toContain('gemini-2.5-flash'); + expect(desc).toContain('gemini-3.5-flash'); }); it('should return Gemini 3.0 description when hasAccessToPreview is true', () => { @@ -746,15 +756,19 @@ describe('getAutoModelDescription', () => { expect(desc).toContain('gemini-3-flash-preview'); }); - it('should return Gemini 3.5 Flash description when hasAccessToPreview and useGemini3_5Flash are true', () => { + it('should return latest Flash description when hasAccessToPreview and useLatestFlash are true', () => { const desc = getAutoModelDescription(true, true, true); expect(desc).toContain('gemini-3.1-pro-preview'); - expect(desc).toContain(DEFAULT_GEMINI_3_5_FLASH_MODEL); + expect(desc).toContain(LATEST_GEMINI_FLASH_MODEL); }); }); describe('resolveModel Gemini 3.5 Flash GA', () => { +<<<<<<< HEAD it('should resolve all but preview flash models to DEFAULT_GEMINI_FLASH_MODEL when useGemini3_5Flash is true (legacy)', () => { +======= + it('should resolve known non-preview flash models to LATEST_GEMINI_FLASH_MODEL when useGemini3_5Flash is true (legacy)', () => { +>>>>>>> 62364cb20 (Feat/gemini 3.8 flash 3.5 flash lite (#29443)) expect( resolveModel( GEMINI_MODEL_ALIAS_FLASH, @@ -764,7 +778,7 @@ describe('resolveModel Gemini 3.5 Flash GA', () => { undefined, true, ), - ).toBe(DEFAULT_GEMINI_FLASH_MODEL); + ).toBe(LATEST_GEMINI_FLASH_MODEL); expect( resolveModel( DEFAULT_GEMINI_FLASH_MODEL, @@ -774,7 +788,7 @@ describe('resolveModel Gemini 3.5 Flash GA', () => { undefined, true, ), - ).toBe(DEFAULT_GEMINI_FLASH_MODEL); + ).toBe(LATEST_GEMINI_FLASH_MODEL); expect( resolveModel( PREVIEW_GEMINI_FLASH_MODEL, @@ -787,7 +801,25 @@ describe('resolveModel Gemini 3.5 Flash GA', () => { ).toBe(PREVIEW_GEMINI_FLASH_MODEL); }); +<<<<<<< HEAD it('should resolve all but preview flash models to gemini-3.5-flash when useGemini3_5Flash is true (dynamic)', () => { +======= + it.each([ + 'gemini-3.6-flash', + 'gemini-3.7-flash', + 'gemini-3.9-flash', + 'gemini-9.9-flash', + ])( + 'should preserve the explicit versioned model %s when useGemini3_5Flash is true (legacy)', + (model) => { + expect(resolveModel(model, false, false, true, undefined, true)).toBe( + model, + ); + }, + ); + + it('should resolve known non-preview flash models to LATEST_GEMINI_FLASH_MODEL when useGemini3_5Flash is true (dynamic)', () => { +>>>>>>> 62364cb20 (Feat/gemini 3.8 flash 3.5 flash lite (#29443)) const mockDynamicConfig = { getExperimentalDynamicModelConfiguration: () => true, modelConfigService, @@ -802,7 +834,7 @@ describe('resolveModel Gemini 3.5 Flash GA', () => { mockDynamicConfig, true, ), - ).toBe('gemini-3.5-flash'); + ).toBe(LATEST_GEMINI_FLASH_MODEL); expect( resolveModel( DEFAULT_GEMINI_FLASH_MODEL, @@ -812,7 +844,7 @@ describe('resolveModel Gemini 3.5 Flash GA', () => { mockDynamicConfig, true, ), - ).toBe('gemini-3.5-flash'); + ).toBe(LATEST_GEMINI_FLASH_MODEL); expect( resolveModel( PREVIEW_GEMINI_FLASH_MODEL, @@ -873,10 +905,10 @@ describe('resolveModel Gemini 3.5 Flash GA', () => { mockDynamicConfig, false, // GA false ), - ).toBe('gemini-2.5-flash'); + ).toBe(DEFAULT_GEMINI_FLASH_MODEL); }); - it('should resolve auto to DEFAULT_GEMINI_FLASH_MODEL when useGemini3_5Flash is true and classifier selects flash', () => { + it('should resolve auto to LATEST_GEMINI_FLASH_MODEL when useGemini3_5Flash is true and classifier selects flash', () => { expect( resolveClassifierModel( GEMINI_MODEL_ALIAS_AUTO, @@ -887,10 +919,10 @@ describe('resolveModel Gemini 3.5 Flash GA', () => { undefined, true, ), - ).toBe(DEFAULT_GEMINI_FLASH_MODEL); + ).toBe(LATEST_GEMINI_FLASH_MODEL); }); - it('should resolve auto to gemini-3.5-flash when useGemini3_5Flash is true and classifier selects flash (dynamic)', () => { + it('should resolve auto to LATEST_GEMINI_FLASH_MODEL when useGemini3_5Flash is true and classifier selects flash (dynamic)', () => { const mockDynamicConfig = { getExperimentalDynamicModelConfiguration: () => true, modelConfigService, @@ -906,11 +938,11 @@ describe('resolveModel Gemini 3.5 Flash GA', () => { mockDynamicConfig, true, ), - ).toBe('gemini-3.5-flash'); + ).toBe(LATEST_GEMINI_FLASH_MODEL); }); describe('Flash model promotion and manual override routing logic', () => { - it('should resolve flash alias to DEFAULT_GEMINI_FLASH_MODEL when useGemini3_5Flash is true (static)', () => { + it('should resolve flash alias to LATEST_GEMINI_FLASH_MODEL when useGemini3_5Flash is true (static)', () => { expect( resolveModel( GEMINI_MODEL_ALIAS_FLASH, @@ -920,10 +952,10 @@ describe('resolveModel Gemini 3.5 Flash GA', () => { undefined, true, ), - ).toBe(DEFAULT_GEMINI_FLASH_MODEL); + ).toBe(LATEST_GEMINI_FLASH_MODEL); }); - it('should resolve flash alias to gemini-3.5-flash when useGemini3_5Flash is true (dynamic)', () => { + it('should resolve flash alias to LATEST_GEMINI_FLASH_MODEL when useGemini3_5Flash is true (dynamic)', () => { const mockDynamicConfig = { getExperimentalDynamicModelConfiguration: () => true, modelConfigService, @@ -938,7 +970,7 @@ describe('resolveModel Gemini 3.5 Flash GA', () => { mockDynamicConfig, true, ), - ).toBe('gemini-3.5-flash'); + ).toBe(LATEST_GEMINI_FLASH_MODEL); }); it('should resolve manual selection of gemini-3-flash-preview to gemini-3-flash-preview when useGemini3_5Flash is true and has preview access (static)', () => { @@ -972,7 +1004,7 @@ describe('resolveModel Gemini 3.5 Flash GA', () => { ).toBe('gemini-3-flash-preview'); }); - it('should resolve manual selection of gemini-3-flash-preview to DEFAULT_GEMINI_FLASH_MODEL when useGemini3_5Flash is true but lacks preview access (static)', () => { + it('should resolve manual selection of gemini-3-flash-preview to LATEST_GEMINI_FLASH_MODEL when useGemini3_5Flash is true but lacks preview access (static)', () => { expect( resolveModel( PREVIEW_GEMINI_FLASH_MODEL, @@ -982,10 +1014,10 @@ describe('resolveModel Gemini 3.5 Flash GA', () => { undefined, true, ), - ).toBe(DEFAULT_GEMINI_FLASH_MODEL); + ).toBe(LATEST_GEMINI_FLASH_MODEL); }); - it('should resolve manual selection of gemini-3-flash-preview to gemini-3.5-flash when useGemini3_5Flash is true but lacks preview access (dynamic)', () => { + it('should resolve manual selection of gemini-3-flash-preview to LATEST_GEMINI_FLASH_MODEL when useGemini3_5Flash is true but lacks preview access (dynamic)', () => { const mockDynamicConfig = { getExperimentalDynamicModelConfiguration: () => true, modelConfigService, @@ -1000,10 +1032,10 @@ describe('resolveModel Gemini 3.5 Flash GA', () => { mockDynamicConfig, true, ), - ).toBe('gemini-3.5-flash'); + ).toBe(LATEST_GEMINI_FLASH_MODEL); }); - it('should resolve classifier-selected flash alias to DEFAULT_GEMINI_FLASH_MODEL when useGemini3_5Flash is true (static)', () => { + it('should resolve classifier-selected flash alias to LATEST_GEMINI_FLASH_MODEL when useGemini3_5Flash is true (static)', () => { expect( resolveClassifierModel( GEMINI_MODEL_ALIAS_AUTO, @@ -1014,10 +1046,10 @@ describe('resolveModel Gemini 3.5 Flash GA', () => { undefined, true, ), - ).toBe(DEFAULT_GEMINI_FLASH_MODEL); + ).toBe(LATEST_GEMINI_FLASH_MODEL); }); - it('should resolve classifier-selected flash alias to gemini-3.5-flash when useGemini3_5Flash is true (dynamic)', () => { + it('should resolve classifier-selected flash alias to LATEST_GEMINI_FLASH_MODEL when useGemini3_5Flash is true (dynamic)', () => { const mockDynamicConfig = { getExperimentalDynamicModelConfiguration: () => true, modelConfigService, @@ -1033,7 +1065,7 @@ describe('resolveModel Gemini 3.5 Flash GA', () => { mockDynamicConfig, true, ), - ).toBe('gemini-3.5-flash'); + ).toBe(LATEST_GEMINI_FLASH_MODEL); }); it('should resolve auto to PREVIEW_GEMINI_MODEL when useGemini3_5Flash is true and has preview access', () => { @@ -1049,4 +1081,133 @@ describe('resolveModel Gemini 3.5 Flash GA', () => { ).toBe(PREVIEW_GEMINI_MODEL); }); }); + + describe('multi-session isolation and global state leakage prevention', () => { + beforeEach(() => { + resetModelsForTesting(); + }); + + afterEach(() => { + resetModelsForTesting(); + }); + + it('should NOT leak latest flash or flash lite models to sessions without access even if global models are mutated', () => { + // Simulate Session A (which has access) mutating global models via setFlashModels / setFlashLiteModel + setFlashModels('gemini-3-flash-preview', LATEST_GEMINI_FLASH_MODEL); + setFlashLiteModel(LATEST_GEMINI_FLASH_LITE_MODEL); + + // Verify global variables were indeed mutated to the latest models + expect(DEFAULT_GEMINI_FLASH_MODEL).toBe(LATEST_GEMINI_FLASH_MODEL); + expect(DEFAULT_GEMINI_FLASH_LITE_MODEL).toBe( + LATEST_GEMINI_FLASH_LITE_MODEL, + ); + + // Session B has NO access (experiment flags false / hasLatestFlashGAAccess returns false) + const sessionBConfig = { + getExperimentalDynamicModelConfiguration: () => false, + hasLatestFlashGAAccess: () => false, + hasLatestFlashLiteGAAccess: () => false, + getHasAccessToPreviewModel: () => true, + modelConfigService, + } as unknown as Config; + + // Session B resolving 'flash' should NOT get LATEST_GEMINI_FLASH_MODEL + expect( + resolveModel( + GEMINI_MODEL_ALIAS_FLASH, + false, + false, + true, + sessionBConfig, + false, + false, + ), + ).toBe(PREVIEW_GEMINI_FLASH_MODEL); + + // Session B resolving 'flash-lite' should NOT get LATEST_GEMINI_FLASH_LITE_MODEL + expect( + resolveModel( + GEMINI_MODEL_ALIAS_FLASH_LITE, + false, + false, + true, + sessionBConfig, + false, + false, + ), + ).toBe(BASE_GEMINI_FLASH_LITE_MODEL); + + // Session B resolving without preview access should get BASE models, NOT LATEST + expect( + resolveModel( + PREVIEW_GEMINI_FLASH_MODEL, + false, + false, + false, + sessionBConfig, + false, + false, + ), + ).toBe(BASE_GEMINI_FLASH_MODEL); + + // Session B classifier resolving flash should NOT get LATEST_GEMINI_FLASH_MODEL + expect( + resolveClassifierModel( + GEMINI_MODEL_ALIAS_AUTO, + GEMINI_MODEL_ALIAS_FLASH, + false, + false, + true, + sessionBConfig, + false, + false, + ), + ).toBe(PREVIEW_GEMINI_FLASH_MODEL); + + // Session B getDisplayString should NOT return latest models + expect(getDisplayString(BASE_GEMINI_FLASH_MODEL, sessionBConfig)).toBe( + BASE_GEMINI_FLASH_MODEL, + ); + expect( + getDisplayString(BASE_GEMINI_FLASH_LITE_MODEL, sessionBConfig), + ).toBe(BASE_GEMINI_FLASH_LITE_MODEL); + }); + + it('should NOT leak latest models in dynamic configuration mode when global models are mutated', () => { + setFlashModels('gemini-3-flash-preview', LATEST_GEMINI_FLASH_MODEL); + setFlashLiteModel(LATEST_GEMINI_FLASH_LITE_MODEL); + + const sessionBDynamicConfig = { + getExperimentalDynamicModelConfiguration: () => true, + hasLatestFlashGAAccess: () => false, + hasLatestFlashLiteGAAccess: () => false, + getHasAccessToPreviewModel: () => true, + modelConfigService, + } as unknown as Config; + + expect( + resolveModel( + GEMINI_MODEL_ALIAS_FLASH, + false, + false, + true, + sessionBDynamicConfig, + false, + false, + ), + ).toBe(PREVIEW_GEMINI_FLASH_MODEL); + + expect( + resolveModel( + GEMINI_MODEL_ALIAS_FLASH_LITE, + false, + false, + true, + sessionBDynamicConfig, + false, + false, + ), + ).toBe(BASE_GEMINI_FLASH_LITE_MODEL); + }); + }); }); diff --git a/packages/core/src/config/models.ts b/packages/core/src/config/models.ts index dd6506b837c..7f1d77e3812 100644 --- a/packages/core/src/config/models.ts +++ b/packages/core/src/config/models.ts @@ -6,6 +6,8 @@ export interface ModelResolutionContext { useGemini3_1?: boolean; + useLatestFlashLite?: boolean; + useLatestFlash?: boolean; useGemini3_5Flash?: boolean; useCustomTools?: boolean; hasAccessToPreview?: boolean; @@ -49,6 +51,9 @@ export interface IModelConfigService { export interface ModelCapabilityContext { readonly modelConfigService: IModelConfigService; getExperimentalDynamicModelConfiguration(): boolean; + hasLatestFlashGAAccess?(): boolean; + hasLatestFlashLiteGAAccess?(): boolean; + getHasAccessToPreviewModel?(): boolean; } export const PREVIEW_GEMINI_MODEL = 'gemini-3-pro-preview'; @@ -59,26 +64,43 @@ export const PREVIEW_GEMINI_3_1_CUSTOM_TOOLS_MODEL = // cleaned up. export let PREVIEW_GEMINI_FLASH_MODEL = 'gemini-3-flash-preview'; export const DEFAULT_GEMINI_MODEL = 'gemini-2.5-pro'; -// TODO: Set to const and update to 'gemini-3.5-flash' once the experiment for -// 3_5 flash rollut can be cleaned up. -// This is set to either the same as the DEFAULT_GEMINI_3_5_FLASH_MODEL const -// OR the SECONDARY_GEMINI_3_5_FLASH_MODEL depending on which is needed for -// the user's backend as determined by hasGemini35FlashGAAccess in -// packages/core/src/config/config.ts -export let DEFAULT_GEMINI_FLASH_MODEL = 'gemini-2.5-flash'; -export const DEFAULT_GEMINI_3_5_FLASH_MODEL = 'gemini-3.5-flash'; -// This is resolved to 3.5 flash in backends where it is used, -// however those backends do not expect to see the string gemini-3.5-flash -// so we need to provide this model as an alternative name in certain instances. -export const SECONDARY_GEMINI_3_5_FLASH_MODEL = 'gemini-3-flash'; - -// Used to set default flash models based on access -// TODO: Cleanup once the experiment for 3_5 flash rollut can be cleaned up. + +// Flash Tier: Base (stable GA) vs. Latest (experiment-gated GA) +export const BASE_GEMINI_FLASH_MODEL = 'gemini-3.5-flash'; +export const LATEST_GEMINI_FLASH_MODEL = 'gemini-3.8-flash'; +export const LEGACY_CCPA_FLASH_MODEL = 'gemini-3-flash'; + +// Backward-compatible aliases +export const DEFAULT_GEMINI_3_5_FLASH_MODEL = BASE_GEMINI_FLASH_MODEL; +export const SECONDARY_GEMINI_3_5_FLASH_MODEL = LEGACY_CCPA_FLASH_MODEL; + +// Flash Lite Tier: Base (stable GA) vs. Latest (experiment-gated GA) +export const BASE_GEMINI_FLASH_LITE_MODEL = 'gemini-3.1-flash-lite'; +export const LATEST_GEMINI_FLASH_LITE_MODEL = 'gemini-3.5-flash-lite'; + +// Runtime active defaults (mutated when experiment flags are evaluated) +export let DEFAULT_GEMINI_FLASH_MODEL = BASE_GEMINI_FLASH_MODEL; +export let DEFAULT_GEMINI_FLASH_LITE_MODEL = BASE_GEMINI_FLASH_LITE_MODEL; + export function setFlashModels(preview: string, defaultFlash: string) { PREVIEW_GEMINI_FLASH_MODEL = preview; DEFAULT_GEMINI_FLASH_MODEL = defaultFlash; } -export const DEFAULT_GEMINI_FLASH_LITE_MODEL = 'gemini-3.1-flash-lite'; + +export function setFlashLiteModel(defaultFlashLite: string) { + DEFAULT_GEMINI_FLASH_LITE_MODEL = defaultFlashLite; +} + +/** + * Resets the mutated model constants to their baseline defaults. + * For use in test cleanup to prevent cross-test state leakage. + */ +export function resetModelsForTesting() { + PREVIEW_GEMINI_FLASH_MODEL = 'gemini-3-flash-preview'; + DEFAULT_GEMINI_FLASH_MODEL = BASE_GEMINI_FLASH_MODEL; + DEFAULT_GEMINI_FLASH_LITE_MODEL = BASE_GEMINI_FLASH_LITE_MODEL; +} + /** @deprecated Gemini 3.1 Flash Lite is now GA. Use DEFAULT_GEMINI_FLASH_LITE_MODEL. */ export const PREVIEW_GEMINI_FLASH_LITE_MODEL = 'none'; @@ -96,11 +118,51 @@ export const VALID_GEMINI_MODELS = new Set([ DEFAULT_GEMINI_3_5_FLASH_MODEL, SECONDARY_GEMINI_3_5_FLASH_MODEL, DEFAULT_GEMINI_FLASH_LITE_MODEL, + BASE_GEMINI_FLASH_MODEL, + LATEST_GEMINI_FLASH_MODEL, + LEGACY_CCPA_FLASH_MODEL, + BASE_GEMINI_FLASH_LITE_MODEL, + LATEST_GEMINI_FLASH_LITE_MODEL, GEMMA_4_31B_IT_MODEL, GEMMA_4_26B_A4B_IT_MODEL, ]); +export interface BackendMappingContext { + hasLatestFlashGAAccess?: () => boolean; + hasLatestFlashLiteGAAccess?: () => boolean; +} + +/** + * Dynamically maps model IDs for outbound backend requests: + * - When LATEST_FLASH_GA_LAUNCHED is true: rewrites BASE_GEMINI_FLASH_MODEL ('gemini-3.5-flash') + * and LEGACY_CCPA_FLASH_MODEL ('gemini-3-flash') -> LATEST_GEMINI_FLASH_MODEL ('gemini-3.8-flash'). + * - When LATEST_FLASH_GA_LAUNCHED is false on Code Assist (CCPA): maps 'gemini-3.5-flash' -> 'gemini-3-flash'. + * - When LATEST_FLASH_LITE_GA_LAUNCHED is true: rewrites BASE_GEMINI_FLASH_LITE_MODEL ('gemini-3.1-flash-lite') + * -> LATEST_GEMINI_FLASH_LITE_MODEL ('gemini-3.5-flash-lite'). + */ +export function getBackendModelMappings( + context?: BackendMappingContext, + isCodeAssistBackend: boolean = true, +): Record { + const mappings: Record = {}; + const useLatestFlash = context?.hasLatestFlashGAAccess?.() ?? false; + const useLatestFlashLite = context?.hasLatestFlashLiteGAAccess?.() ?? false; + + if (useLatestFlash) { + mappings[BASE_GEMINI_FLASH_MODEL] = LATEST_GEMINI_FLASH_MODEL; + mappings[LEGACY_CCPA_FLASH_MODEL] = LATEST_GEMINI_FLASH_MODEL; + } else if (isCodeAssistBackend) { + mappings[BASE_GEMINI_FLASH_MODEL] = LEGACY_CCPA_FLASH_MODEL; + } + + if (useLatestFlashLite) { + mappings[BASE_GEMINI_FLASH_LITE_MODEL] = LATEST_GEMINI_FLASH_LITE_MODEL; + } + + return mappings; +} + /** @deprecated Use GEMINI_MODEL_ALIAS_AUTO instead. */ export const PREVIEW_GEMINI_MODEL_AUTO = 'auto-gemini-3'; /** @deprecated Use GEMINI_MODEL_ALIAS_AUTO instead. */ @@ -120,7 +182,7 @@ export const DEFAULT_THINKING_MODE = 8192; export function getAutoModelDescription( hasAccessToPreview: boolean, useGemini3_1: boolean = false, - useGemini3_5Flash: boolean = false, + useLatestFlash: boolean = false, ) { const proModel = hasAccessToPreview ? useGemini3_1 @@ -128,8 +190,8 @@ export function getAutoModelDescription( : PREVIEW_GEMINI_MODEL : DEFAULT_GEMINI_MODEL; const flashModel = hasAccessToPreview - ? useGemini3_5Flash - ? DEFAULT_GEMINI_3_5_FLASH_MODEL + ? useLatestFlash + ? LATEST_GEMINI_FLASH_MODEL : PREVIEW_GEMINI_FLASH_MODEL : DEFAULT_GEMINI_FLASH_MODEL; return `Let Gemini CLI decide the best model for the task: ${getDisplayString(proModel)}, ${getDisplayString(flashModel)}`; @@ -141,8 +203,11 @@ export function getAutoModelDescription( * * @param requestedModel The model alias or concrete model name requested by the user. * @param useGemini3_1 Whether to use Gemini 3.1 Pro Preview for auto/pro aliases. - * @param useGemini3_5Flash Whether to use Gemini 3.5 Flash GA. + * @param useCustomToolModel Whether to use the custom tool model. * @param hasAccessToPreview Whether the user has access to preview models. + * @param config Optional config object for dynamic model configuration. + * @param useLatestFlash Whether to use the latest Flash GA model. + * @param useLatestFlashLite Whether to use the latest Flash Lite GA model. * @returns The resolved concrete model name. */ export function resolveModel( @@ -151,7 +216,8 @@ export function resolveModel( useCustomToolModel: boolean = false, hasAccessToPreview: boolean = true, config?: ModelCapabilityContext, - useGemini3_5Flash: boolean = false, + useLatestFlash: boolean = false, + useLatestFlashLite: boolean = false, ): string { // Defensive check against non-string inputs at runtime const normalizedModel = Array.isArray(requestedModel) @@ -160,21 +226,31 @@ export function resolveModel( ? String(requestedModel ?? '').trim() || '' : requestedModel.trim() || ''; + const effectiveUseLatestFlash = + useLatestFlash || (config?.hasLatestFlashGAAccess?.() ?? false); + const effectiveUseLatestFlashLite = + useLatestFlashLite || (config?.hasLatestFlashLiteGAAccess?.() ?? false); + if (config?.getExperimentalDynamicModelConfiguration?.() === true) { const resolved = config.modelConfigService.resolveModelId(normalizedModel, { useGemini3_1, useCustomTools: useCustomToolModel, hasAccessToPreview, - useGemini3_5Flash, + useLatestFlash: effectiveUseLatestFlash, + useLatestFlashLite: effectiveUseLatestFlashLite, }); if (!hasAccessToPreview && isPreviewModel(resolved, config)) { // Fallback for unknown preview models. if (resolved.includes('flash-lite')) { - return DEFAULT_GEMINI_FLASH_LITE_MODEL; + return effectiveUseLatestFlashLite + ? LATEST_GEMINI_FLASH_LITE_MODEL + : BASE_GEMINI_FLASH_LITE_MODEL; } if (resolved.includes('flash')) { - return DEFAULT_GEMINI_FLASH_MODEL; + return effectiveUseLatestFlash + ? LATEST_GEMINI_FLASH_MODEL + : BASE_GEMINI_FLASH_MODEL; } return DEFAULT_GEMINI_MODEL; } @@ -208,13 +284,15 @@ export function resolveModel( break; } case GEMINI_MODEL_ALIAS_FLASH: { - resolved = useGemini3_5Flash - ? DEFAULT_GEMINI_FLASH_MODEL + resolved = effectiveUseLatestFlash + ? LATEST_GEMINI_FLASH_MODEL : PREVIEW_GEMINI_FLASH_MODEL; break; } case GEMINI_MODEL_ALIAS_FLASH_LITE: { - resolved = DEFAULT_GEMINI_FLASH_LITE_MODEL; + resolved = effectiveUseLatestFlashLite + ? LATEST_GEMINI_FLASH_LITE_MODEL + : BASE_GEMINI_FLASH_LITE_MODEL; break; } default: { @@ -224,22 +302,35 @@ export function resolveModel( } if (resolved === 'none') { - return DEFAULT_GEMINI_FLASH_LITE_MODEL; + return effectiveUseLatestFlashLite + ? LATEST_GEMINI_FLASH_LITE_MODEL + : BASE_GEMINI_FLASH_LITE_MODEL; } if ( +<<<<<<< HEAD useGemini3_5Flash && isFlashModel(resolved) && +======= + effectiveUseLatestFlash && + isPromotableFlashModel(resolved) && +>>>>>>> 62364cb20 (Feat/gemini 3.8 flash 3.5 flash lite (#29443)) normalizedModel !== PREVIEW_GEMINI_FLASH_MODEL ) { - return DEFAULT_GEMINI_FLASH_MODEL; + return LATEST_GEMINI_FLASH_MODEL; + } + + if (effectiveUseLatestFlashLite && isPromotableFlashLiteModel(resolved)) { + return LATEST_GEMINI_FLASH_LITE_MODEL; } if (!hasAccessToPreview && isPreviewModel(resolved)) { // Downgrade to stable models if user lacks preview access. switch (resolved) { case PREVIEW_GEMINI_FLASH_MODEL: - return DEFAULT_GEMINI_FLASH_MODEL; + return effectiveUseLatestFlash + ? LATEST_GEMINI_FLASH_MODEL + : BASE_GEMINI_FLASH_MODEL; case PREVIEW_GEMINI_MODEL: case PREVIEW_GEMINI_3_1_MODEL: case PREVIEW_GEMINI_3_1_CUSTOM_TOOLS_MODEL: @@ -247,10 +338,14 @@ export function resolveModel( default: // Fallback for unknown preview models, preserving original logic. if (resolved.includes('flash-lite')) { - return DEFAULT_GEMINI_FLASH_LITE_MODEL; + return effectiveUseLatestFlashLite + ? LATEST_GEMINI_FLASH_LITE_MODEL + : BASE_GEMINI_FLASH_LITE_MODEL; } if (resolved.includes('flash')) { - return DEFAULT_GEMINI_FLASH_MODEL; + return effectiveUseLatestFlash + ? LATEST_GEMINI_FLASH_MODEL + : BASE_GEMINI_FLASH_MODEL; } return DEFAULT_GEMINI_MODEL; } @@ -265,8 +360,22 @@ function isFlashModel(model: string): boolean { model === PREVIEW_GEMINI_FLASH_MODEL || model === DEFAULT_GEMINI_3_5_FLASH_MODEL || model === SECONDARY_GEMINI_3_5_FLASH_MODEL || +<<<<<<< HEAD model === 'flash' || model.endsWith('flash') +======= + model === GEMINI_MODEL_ALIAS_FLASH || + model === BASE_GEMINI_FLASH_MODEL || + model === LEGACY_CCPA_FLASH_MODEL + ); +} + +function isPromotableFlashLiteModel(model: string): boolean { + return ( + model === DEFAULT_GEMINI_FLASH_LITE_MODEL || + model === BASE_GEMINI_FLASH_LITE_MODEL || + model === GEMINI_MODEL_ALIAS_FLASH_LITE +>>>>>>> 62364cb20 (Feat/gemini 3.8 flash 3.5 flash lite (#29443)) ); } @@ -287,8 +396,16 @@ export function resolveClassifierModel( useCustomToolModel: boolean = false, hasAccessToPreview: boolean = true, config?: ModelCapabilityContext, - useGemini3_5Flash: boolean = false, + useLatestFlash: boolean = false, + useLatestFlashLite: boolean = false, ): string { + const effectiveUseLatestFlash = + useLatestFlash || (config?.hasLatestFlashGAAccess?.() ?? false); + const effectiveUseLatestFlashLite = + useLatestFlashLite || (config?.hasLatestFlashLiteGAAccess?.() ?? false); + const effectiveHasAccessToPreview = + hasAccessToPreview || (config?.getHasAccessToPreviewModel?.() ?? false); + if (config?.getExperimentalDynamicModelConfiguration?.() === true) { return config.modelConfigService.resolveClassifierModelId( modelAlias, @@ -296,8 +413,9 @@ export function resolveClassifierModel( { useGemini3_1, useCustomTools: useCustomToolModel, - hasAccessToPreview, - useGemini3_5Flash, + hasAccessToPreview: effectiveHasAccessToPreview, + useLatestFlash: effectiveUseLatestFlash, + useLatestFlashLite: effectiveUseLatestFlashLite, }, ); } @@ -307,36 +425,53 @@ export function resolveClassifierModel( requestedModel === DEFAULT_GEMINI_MODEL_AUTO || requestedModel === DEFAULT_GEMINI_MODEL ) { - return DEFAULT_GEMINI_FLASH_MODEL; + return effectiveUseLatestFlash + ? LATEST_GEMINI_FLASH_MODEL + : BASE_GEMINI_FLASH_MODEL; } if ( requestedModel === PREVIEW_GEMINI_MODEL_AUTO || requestedModel === PREVIEW_GEMINI_MODEL || requestedModel === GEMINI_MODEL_ALIAS_AUTO ) { - if (useGemini3_5Flash) { - return DEFAULT_GEMINI_FLASH_MODEL; + if (effectiveUseLatestFlash) { + return LATEST_GEMINI_FLASH_MODEL; } - return hasAccessToPreview + return effectiveHasAccessToPreview ? PREVIEW_GEMINI_FLASH_MODEL - : DEFAULT_GEMINI_FLASH_MODEL; + : BASE_GEMINI_FLASH_MODEL; } return resolveModel( GEMINI_MODEL_ALIAS_FLASH, false, false, - hasAccessToPreview, + effectiveHasAccessToPreview, + config, + effectiveUseLatestFlash, + effectiveUseLatestFlashLite, + ); + } + + if (modelAlias === GEMINI_MODEL_ALIAS_FLASH_LITE) { + return resolveModel( + GEMINI_MODEL_ALIAS_FLASH_LITE, + false, + false, + effectiveHasAccessToPreview, config, - useGemini3_5Flash, + effectiveUseLatestFlash, + effectiveUseLatestFlashLite, ); } + return resolveModel( requestedModel, useGemini3_1, useCustomToolModel, - hasAccessToPreview, + effectiveHasAccessToPreview, config, - useGemini3_5Flash, + effectiveUseLatestFlash, + effectiveUseLatestFlashLite, ); } @@ -351,9 +486,19 @@ export function getDisplayString( } } + const useLatestFlash = config?.hasLatestFlashGAAccess?.() ?? false; + const useLatestFlashLite = config?.hasLatestFlashLiteGAAccess?.() ?? false; + switch (model) { - case 'gemini-3-flash': - return DEFAULT_GEMINI_3_5_FLASH_MODEL; + case LEGACY_CCPA_FLASH_MODEL: + case BASE_GEMINI_FLASH_MODEL: + return useLatestFlash + ? LATEST_GEMINI_FLASH_MODEL + : BASE_GEMINI_FLASH_MODEL; + case BASE_GEMINI_FLASH_LITE_MODEL: + return useLatestFlashLite + ? LATEST_GEMINI_FLASH_LITE_MODEL + : BASE_GEMINI_FLASH_LITE_MODEL; case GEMINI_MODEL_ALIAS_AUTO: return 'Auto'; case PREVIEW_GEMINI_MODEL_AUTO: diff --git a/packages/core/src/context/chatCompressionService.test.ts b/packages/core/src/context/chatCompressionService.test.ts index ea21bb0225a..9918be760fd 100644 --- a/packages/core/src/context/chatCompressionService.test.ts +++ b/packages/core/src/context/chatCompressionService.test.ts @@ -129,6 +129,21 @@ describe('modelStringToModelConfigAlias', () => { expect(modelStringToModelConfigAlias('gemini-2.5-flash-lite')).toBe( 'chat-compression-2.5-flash-lite', ); + expect(modelStringToModelConfigAlias('gemini-3.5-flash')).toBe( + 'chat-compression-3-flash', + ); + expect(modelStringToModelConfigAlias('gemini-3.8-flash')).toBe( + 'chat-compression-3-flash', + ); + expect(modelStringToModelConfigAlias('gemini-3-flash')).toBe( + 'chat-compression-3-flash', + ); + expect(modelStringToModelConfigAlias('gemini-3.1-flash-lite')).toBe( + 'chat-compression-3.1-flash-lite', + ); + expect(modelStringToModelConfigAlias('gemini-3.5-flash-lite')).toBe( + 'chat-compression-3.1-flash-lite', + ); }); }); diff --git a/packages/core/src/context/chatCompressionService.ts b/packages/core/src/context/chatCompressionService.ts index 7eaa4df52aa..4e1228c8d46 100644 --- a/packages/core/src/context/chatCompressionService.ts +++ b/packages/core/src/context/chatCompressionService.ts @@ -25,12 +25,16 @@ import { } from '../utils/tokenCalculation.js'; import { DEFAULT_GEMINI_FLASH_LITE_MODEL, - DEFAULT_GEMINI_FLASH_MODEL, DEFAULT_GEMINI_MODEL, PREVIEW_GEMINI_MODEL, PREVIEW_GEMINI_FLASH_MODEL, PREVIEW_GEMINI_3_1_MODEL, PREVIEW_GEMINI_FLASH_LITE_MODEL, + BASE_GEMINI_FLASH_MODEL, + LATEST_GEMINI_FLASH_MODEL, + LEGACY_CCPA_FLASH_MODEL, + BASE_GEMINI_FLASH_LITE_MODEL, + LATEST_GEMINI_FLASH_LITE_MODEL, } from '../config/models.js'; import { PreCompressTrigger } from '../hooks/types.js'; @@ -105,16 +109,21 @@ export function modelStringToModelConfigAlias(model: string): string { case PREVIEW_GEMINI_3_1_MODEL: return 'chat-compression-3-pro'; case PREVIEW_GEMINI_FLASH_MODEL: + case BASE_GEMINI_FLASH_MODEL: + case LATEST_GEMINI_FLASH_MODEL: + case LEGACY_CCPA_FLASH_MODEL: return 'chat-compression-3-flash'; case PREVIEW_GEMINI_FLASH_LITE_MODEL: // fallthrough + case BASE_GEMINI_FLASH_LITE_MODEL: case DEFAULT_GEMINI_FLASH_LITE_MODEL: + case LATEST_GEMINI_FLASH_LITE_MODEL: return 'chat-compression-3.1-flash-lite'; case 'gemini-2.5-flash-lite': return 'chat-compression-2.5-flash-lite'; case DEFAULT_GEMINI_MODEL: return 'chat-compression-2.5-pro'; - case DEFAULT_GEMINI_FLASH_MODEL: + case 'gemini-2.5-flash': return 'chat-compression-2.5-flash'; default: return 'chat-compression-default'; diff --git a/packages/core/src/core/contentGenerator.test.ts b/packages/core/src/core/contentGenerator.test.ts index 50de05b89a2..a46ca413710 100644 --- a/packages/core/src/core/contentGenerator.test.ts +++ b/packages/core/src/core/contentGenerator.test.ts @@ -19,7 +19,6 @@ import { HttpsProxyAgent } from 'https-proxy-agent'; import type { Config } from '../config/config.js'; import { LoggingContentGenerator } from './loggingContentGenerator.js'; import { ModelMappingContentGenerator } from './modelMappingContentGenerator.js'; -import { CCPA_AI_MODEL_MAPPINGS } from '../config/models.js'; import { loadApiKey } from './apiKeyCredentialStorage.js'; import { FakeContentGenerator } from './fakeContentGenerator.js'; import { RecordingContentGenerator } from './recordingContentGenerator.js'; @@ -155,7 +154,7 @@ describe('createContentGenerator', () => { expect(createCodeAssistContentGenerator).toHaveBeenCalled(); expect(generator).toEqual( new LoggingContentGenerator( - new ModelMappingContentGenerator(mockGenerator, CCPA_AI_MODEL_MAPPINGS), + new ModelMappingContentGenerator(mockGenerator, expect.any(Function)), mockConfig, ), ); @@ -175,7 +174,7 @@ describe('createContentGenerator', () => { expect(createCodeAssistContentGenerator).toHaveBeenCalled(); expect(generator).toEqual( new LoggingContentGenerator( - new ModelMappingContentGenerator(mockGenerator, CCPA_AI_MODEL_MAPPINGS), + new ModelMappingContentGenerator(mockGenerator, expect.any(Function)), mockConfig, ), ); @@ -219,7 +218,13 @@ describe('createContentGenerator', () => { }), }); expect(generator).toEqual( - new LoggingContentGenerator(mockGenerator.models, mockConfig), + new LoggingContentGenerator( + new ModelMappingContentGenerator( + mockGenerator.models, + expect.any(Function), + ), + mockConfig, + ), ); }); @@ -832,7 +837,13 @@ describe('createContentGenerator', () => { }), }); expect(generator).toEqual( - new LoggingContentGenerator(mockGenerator.models, mockConfig), + new LoggingContentGenerator( + new ModelMappingContentGenerator( + mockGenerator.models, + expect.any(Function), + ), + mockConfig, + ), ); }); diff --git a/packages/core/src/core/contentGenerator.ts b/packages/core/src/core/contentGenerator.ts index e0b33d8c7b0..f44ec6d2458 100644 --- a/packages/core/src/core/contentGenerator.ts +++ b/packages/core/src/core/contentGenerator.ts @@ -31,7 +31,7 @@ import { RecordingContentGenerator } from './recordingContentGenerator.js'; import { getVersion, resolveModel } from '../../index.js'; import type { LlmRole } from '../telemetry/llmRole.js'; import { ModelMappingContentGenerator } from './modelMappingContentGenerator.js'; -import { CCPA_AI_MODEL_MAPPINGS } from '../config/models.js'; +import { getBackendModelMappings } from '../config/models.js'; /** * Interface abstracting the core functionalities for generating content and counting tokens. @@ -303,7 +303,7 @@ export async function createContentGenerator( gcConfig, sessionId, ), - CCPA_AI_MODEL_MAPPINGS, + () => getBackendModelMappings(gcConfig, true), ), gcConfig, ); @@ -407,7 +407,12 @@ export async function createContentGenerator( }, }), }); - return new LoggingContentGenerator(googleGenAI.models, gcConfig); + return new LoggingContentGenerator( + new ModelMappingContentGenerator(googleGenAI.models, () => + getBackendModelMappings(gcConfig, false), + ), + gcConfig, + ); } throw new Error( `Error creating contentGenerator: Unsupported authType: ${config.authType}`, diff --git a/packages/core/src/core/geminiChat.test.ts b/packages/core/src/core/geminiChat.test.ts index 80d37e7fbdf..f70b67f8e80 100644 --- a/packages/core/src/core/geminiChat.test.ts +++ b/packages/core/src/core/geminiChat.test.ts @@ -166,7 +166,7 @@ describe('GeminiChat', () => { getTelemetryLogPromptsEnabled: () => true, getTelemetryTracesEnabled: () => false, getUsageStatisticsEnabled: () => true, - hasGemini35FlashGAAccess: vi.fn().mockReturnValue(false), + hasLatestFlashGAAccess: vi.fn().mockReturnValue(false), getDebugMode: () => false, getContentGeneratorConfig: vi.fn().mockImplementation(() => ({ authType: 'oauth-personal', @@ -2305,6 +2305,42 @@ describe('GeminiChat', () => { ); }); +<<<<<<< HEAD +======= + it('should send an explicit versioned Flash model unchanged when Gemini 3.5 Flash GA is enabled', async () => { + vi.mocked(mockConfig.hasLatestFlashGAAccess).mockReturnValue(true); + vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue( + (async function* () { + yield { + candidates: [ + { + content: { parts: [{ text: 'response' }], role: 'model' }, + finishReason: 'STOP', + }, + ], + } as unknown as GenerateContentResponse; + })(), + ); + + const stream = await chat.sendMessageStream( + { model: 'gemini-3.8-flash' }, + 'hello', + 'prompt-id-explicit-flash', + new AbortController().signal, + LlmRole.MAIN, + ); + for await (const _ of stream) { + // consume stream + } + + expect(mockContentGenerator.generateContentStream).toHaveBeenCalledWith( + expect.objectContaining({ model: 'gemini-3.8-flash' }), + 'prompt-id-explicit-flash', + LlmRole.MAIN, + ); + }); + +>>>>>>> 62364cb20 (Feat/gemini 3.8 flash 3.5 flash lite (#29443)) it('should use thinkingLevel and remove thinkingBudget for gemini-3 models', async () => { const response = (async function* () { yield { diff --git a/packages/core/src/core/geminiChat_network_retry.test.ts b/packages/core/src/core/geminiChat_network_retry.test.ts index 5db803b2e3f..a170ed1a13b 100644 --- a/packages/core/src/core/geminiChat_network_retry.test.ts +++ b/packages/core/src/core/geminiChat_network_retry.test.ts @@ -98,7 +98,7 @@ describe('GeminiChat Network Retries', () => { getTelemetryLogPromptsEnabled: () => true, getTelemetryTracesEnabled: () => false, getUsageStatisticsEnabled: () => true, - hasGemini35FlashGAAccess: vi.fn().mockReturnValue(false), + hasLatestFlashGAAccess: vi.fn().mockReturnValue(false), getDebugMode: () => false, getContentGeneratorConfig: vi.fn().mockReturnValue({ authType: 'oauth-personal', diff --git a/packages/core/src/core/modelMappingContentGenerator.ts b/packages/core/src/core/modelMappingContentGenerator.ts index ef07f614ae8..b81dc2361c2 100644 --- a/packages/core/src/core/modelMappingContentGenerator.ts +++ b/packages/core/src/core/modelMappingContentGenerator.ts @@ -20,7 +20,9 @@ import { normalizeModelId } from '../utils/modelUtils.js'; export class ModelMappingContentGenerator implements ContentGenerator { constructor( private readonly wrapped: ContentGenerator, - private readonly mappings: Record, + private readonly mappings: + | Record + | (() => Record), ) {} getWrapped(): ContentGenerator { @@ -41,13 +43,15 @@ export class ModelMappingContentGenerator implements ContentGenerator { private mapModel(req: T): T { if (req.model) { + const activeMappings = + typeof this.mappings === 'function' ? this.mappings() : this.mappings; const normalizedModel = normalizeModelId(req.model); - if (this.mappings[normalizedModel]) { + if (activeMappings[normalizedModel]) { return { ...req, model: req.model.startsWith('models/') - ? `models/${this.mappings[normalizedModel]}` - : this.mappings[normalizedModel], + ? `models/${activeMappings[normalizedModel]}` + : activeMappings[normalizedModel], }; } } diff --git a/packages/core/src/routing/strategies/approvalModeStrategy.test.ts b/packages/core/src/routing/strategies/approvalModeStrategy.test.ts index a92c8332d33..53fc78a8b43 100644 --- a/packages/core/src/routing/strategies/approvalModeStrategy.test.ts +++ b/packages/core/src/routing/strategies/approvalModeStrategy.test.ts @@ -16,6 +16,8 @@ import { DEFAULT_GEMINI_MODEL_AUTO, PREVIEW_GEMINI_MODEL_AUTO, GEMINI_MODEL_ALIAS_AUTO, + LATEST_GEMINI_FLASH_MODEL, + resetModelsForTesting, } from '../../config/models.js'; import { AuthType } from '../../core/contentGenerator.js'; import { ApprovalMode } from '../../policy/types.js'; @@ -29,6 +31,7 @@ describe('ApprovalModeStrategy', () => { beforeEach(() => { vi.clearAllMocks(); + resetModelsForTesting(); strategy = new ApprovalModeStrategy(); mockContext = { @@ -52,6 +55,8 @@ describe('ApprovalModeStrategy', () => { getContentGeneratorConfig: vi.fn().mockReturnValue({ authType: AuthType.LOGIN_WITH_GOOGLE, }), + hasLatestFlashGAAccess: vi.fn().mockReturnValue(false), + hasLatestFlashLiteGAAccess: vi.fn().mockReturnValue(false), } as unknown as Config; mockBaseLlmClient = {} as BaseLlmClient; @@ -243,9 +248,9 @@ describe('ApprovalModeStrategy', () => { expect(decision?.model).toBe(PREVIEW_GEMINI_FLASH_MODEL); }); - it('should route to DEFAULT_GEMINI_FLASH_MODEL when hasGemini35FlashGAAccess is true and plan is approved', async () => { + it('should route to LATEST_GEMINI_FLASH_MODEL when hasLatestFlashGAAccess is true and plan is approved', async () => { vi.mocked(mockConfig.getModel).mockReturnValue(GEMINI_MODEL_ALIAS_AUTO); - mockConfig.hasGemini35FlashGAAccess = vi.fn().mockReturnValue(true); + vi.mocked(mockConfig.hasLatestFlashGAAccess).mockReturnValue(true); vi.mocked(mockConfig.getApprovalMode).mockReturnValue(ApprovalMode.DEFAULT); vi.mocked(mockConfig.getApprovedPlanPath).mockReturnValue( @@ -258,6 +263,6 @@ describe('ApprovalModeStrategy', () => { mockBaseLlmClient, ); - expect(decision?.model).toBe(DEFAULT_GEMINI_FLASH_MODEL); + expect(decision?.model).toBe(LATEST_GEMINI_FLASH_MODEL); }); }); diff --git a/packages/core/src/routing/strategies/approvalModeStrategy.ts b/packages/core/src/routing/strategies/approvalModeStrategy.ts index 0d1b14a9ac2..33180ea93ec 100644 --- a/packages/core/src/routing/strategies/approvalModeStrategy.ts +++ b/packages/core/src/routing/strategies/approvalModeStrategy.ts @@ -54,7 +54,8 @@ export class ApprovalModeStrategy implements RoutingStrategy { config.getUseCustomToolModel(), config.getHasAccessToPreviewModel(), ]); - const useGemini3_5Flash = config.hasGemini35FlashGAAccess?.() ?? false; + const useLatestFlash = config.hasLatestFlashGAAccess?.() ?? false; + const useLatestFlashLite = config.hasLatestFlashLiteGAAccess?.() ?? false; // 1. Planning Phase: If ApprovalMode === PLAN, explicitly route to the Pro model. if (approvalMode === ApprovalMode.PLAN) { @@ -65,7 +66,8 @@ export class ApprovalModeStrategy implements RoutingStrategy { useCustomToolModel, hasAccessToPreview, config, - useGemini3_5Flash, + useLatestFlash, + useLatestFlashLite, ); return { model: proModel, @@ -84,7 +86,8 @@ export class ApprovalModeStrategy implements RoutingStrategy { useCustomToolModel, hasAccessToPreview, config, - useGemini3_5Flash, + useLatestFlash, + useLatestFlashLite, ); return { model: flashModel, diff --git a/packages/core/src/routing/strategies/classifierStrategy.test.ts b/packages/core/src/routing/strategies/classifierStrategy.test.ts index bdfc19638e4..1e21e23fc0a 100644 --- a/packages/core/src/routing/strategies/classifierStrategy.test.ts +++ b/packages/core/src/routing/strategies/classifierStrategy.test.ts @@ -21,6 +21,8 @@ import { PREVIEW_GEMINI_MODEL_AUTO, PREVIEW_GEMINI_3_1_MODEL, PREVIEW_GEMINI_3_1_CUSTOM_TOOLS_MODEL, + LATEST_GEMINI_FLASH_MODEL, + resetModelsForTesting, } from '../../config/models.js'; import { promptIdContext } from '../../utils/promptIdContext.js'; import type { Content } from '@google/genai'; @@ -41,6 +43,7 @@ describe('ClassifierStrategy', () => { beforeEach(() => { vi.clearAllMocks(); + resetModelsForTesting(); strategy = new ClassifierStrategy(); mockContext = { @@ -71,6 +74,8 @@ describe('ClassifierStrategy', () => { getModelAvailabilityService: vi .fn() .mockReturnValue(new ModelAvailabilityService()), + hasLatestFlashGAAccess: vi.fn().mockReturnValue(false), + hasLatestFlashLiteGAAccess: vi.fn().mockReturnValue(false), } as unknown as Config; mockBaseLlmClient = { generateJson: vi.fn(), @@ -523,8 +528,8 @@ describe('ClassifierStrategy', () => { expect(decision?.model).toBe(PREVIEW_GEMINI_3_1_CUSTOM_TOOLS_MODEL); }); - it('should route to DEFAULT_GEMINI_FLASH_MODEL when hasGemini35FlashGAAccess is true', async () => { - mockConfig.hasGemini35FlashGAAccess = vi.fn().mockReturnValue(true); + it('should route to LATEST_GEMINI_FLASH_MODEL when hasLatestFlashGAAccess is true', async () => { + mockConfig.hasLatestFlashGAAccess = vi.fn().mockReturnValue(true); vi.mocked(mockConfig.getModel).mockReturnValue(PREVIEW_GEMINI_MODEL_AUTO); const mockApiResponse = { @@ -542,7 +547,7 @@ describe('ClassifierStrategy', () => { mockLocalLiteRtLmClient, ); - expect(decision?.model).toBe(DEFAULT_GEMINI_FLASH_MODEL); + expect(decision?.model).toBe(LATEST_GEMINI_FLASH_MODEL); }); }); }); diff --git a/packages/core/src/routing/strategies/classifierStrategy.ts b/packages/core/src/routing/strategies/classifierStrategy.ts index ae4bbe6b4ab..b025c3d5cd2 100644 --- a/packages/core/src/routing/strategies/classifierStrategy.ts +++ b/packages/core/src/routing/strategies/classifierStrategy.ts @@ -186,7 +186,8 @@ export class ClassifierStrategy implements RoutingStrategy { config.getGemini31Launched(), config.getUseCustomToolModel(), ]); - const useGemini3_5Flash = config.hasGemini35FlashGAAccess?.() ?? false; + const useLatestFlash = config.hasLatestFlashGAAccess?.() ?? false; + const useLatestFlashLite = config.hasLatestFlashLiteGAAccess?.() ?? false; const selectedModel = normalizeModelId( resolveClassifierModel( normalizeModelId(model), @@ -195,7 +196,8 @@ export class ClassifierStrategy implements RoutingStrategy { useCustomToolModel, config.getHasAccessToPreviewModel?.() ?? true, config, - useGemini3_5Flash, + useLatestFlash, + useLatestFlashLite, ), ); diff --git a/packages/core/src/routing/strategies/defaultStrategy.ts b/packages/core/src/routing/strategies/defaultStrategy.ts index 2eccedba262..605a754b1aa 100644 --- a/packages/core/src/routing/strategies/defaultStrategy.ts +++ b/packages/core/src/routing/strategies/defaultStrategy.ts @@ -29,7 +29,8 @@ export class DefaultStrategy implements TerminalStrategy { false, config.getHasAccessToPreviewModel?.() ?? true, config, - config.hasGemini35FlashGAAccess?.() ?? false, + config.hasLatestFlashGAAccess?.() ?? false, + config.hasLatestFlashLiteGAAccess?.() ?? false, ); return { model: defaultModel, diff --git a/packages/core/src/routing/strategies/fallbackStrategy.ts b/packages/core/src/routing/strategies/fallbackStrategy.ts index 5b152ec409a..1f9934b80a7 100644 --- a/packages/core/src/routing/strategies/fallbackStrategy.ts +++ b/packages/core/src/routing/strategies/fallbackStrategy.ts @@ -31,7 +31,8 @@ export class FallbackStrategy implements RoutingStrategy { false, config.getHasAccessToPreviewModel?.() ?? true, config, - config.hasGemini35FlashGAAccess?.() ?? false, + config.hasLatestFlashGAAccess?.() ?? false, + config.hasLatestFlashLiteGAAccess?.() ?? false, ); const service = config.getModelAvailabilityService(); const snapshot = service.snapshot(resolvedModel); diff --git a/packages/core/src/routing/strategies/gemmaClassifierStrategy.test.ts b/packages/core/src/routing/strategies/gemmaClassifierStrategy.test.ts index c07b2188d25..965e03a4cdf 100644 --- a/packages/core/src/routing/strategies/gemmaClassifierStrategy.test.ts +++ b/packages/core/src/routing/strategies/gemmaClassifierStrategy.test.ts @@ -13,6 +13,8 @@ import { DEFAULT_GEMINI_FLASH_MODEL, DEFAULT_GEMINI_MODEL, PREVIEW_GEMINI_MODEL_AUTO, + LATEST_GEMINI_FLASH_MODEL, + resetModelsForTesting, } from '../../config/models.js'; import type { Content } from '@google/genai'; import { debugLogger } from '../../utils/debugLogger.js'; @@ -30,6 +32,7 @@ describe('GemmaClassifierStrategy', () => { beforeEach(() => { vi.clearAllMocks(); + resetModelsForTesting(); mockGenerateJson = vi.fn(); mockConfig = { @@ -42,6 +45,8 @@ describe('GemmaClassifierStrategy', () => { getGemini31Launched: vi.fn().mockResolvedValue(false), getUseCustomToolModel: vi.fn().mockResolvedValue(false), getHasAccessToPreviewModel: vi.fn().mockReturnValue(true), + hasLatestFlashGAAccess: vi.fn().mockReturnValue(false), + hasLatestFlashLiteGAAccess: vi.fn().mockReturnValue(false), } as unknown as Config; strategy = new GemmaClassifierStrategy(); @@ -325,8 +330,8 @@ second message expect(lastTurn!.parts!.at(0)!.text).toEqual(expectedLastTurn); }); - it('should route to DEFAULT_GEMINI_FLASH_MODEL when hasGemini35FlashGAAccess is true', async () => { - mockConfig.hasGemini35FlashGAAccess = vi.fn().mockReturnValue(true); + it('should route to LATEST_GEMINI_FLASH_MODEL when hasLatestFlashGAAccess is true', async () => { + mockConfig.hasLatestFlashGAAccess = vi.fn().mockReturnValue(true); mockConfig.getModel = () => PREVIEW_GEMINI_MODEL_AUTO; const mockApiResponse = { @@ -342,6 +347,6 @@ second message mockLocalLiteRtLmClient, ); - expect(decision?.model).toBe(DEFAULT_GEMINI_FLASH_MODEL); + expect(decision?.model).toBe(LATEST_GEMINI_FLASH_MODEL); }); }); diff --git a/packages/core/src/routing/strategies/gemmaClassifierStrategy.ts b/packages/core/src/routing/strategies/gemmaClassifierStrategy.ts index 84ecce2e94e..4a1526d0c20 100644 --- a/packages/core/src/routing/strategies/gemmaClassifierStrategy.ts +++ b/packages/core/src/routing/strategies/gemmaClassifierStrategy.ts @@ -216,7 +216,8 @@ ${formattedHistory} config.getUseCustomToolModel(), config.getHasAccessToPreviewModel(), ]); - const useGemini3_5Flash = config.hasGemini35FlashGAAccess?.() ?? false; + const useLatestFlash = config.hasLatestFlashGAAccess?.() ?? false; + const useLatestFlashLite = config.hasLatestFlashLiteGAAccess?.() ?? false; const selectedModel = resolveClassifierModel( context.requestedModel ?? config.getModel(), @@ -225,7 +226,8 @@ ${formattedHistory} useCustomToolModel, hasAccessToPreview, config, - useGemini3_5Flash, + useLatestFlash, + useLatestFlashLite, ); return { diff --git a/packages/core/src/routing/strategies/numericalClassifierStrategy.test.ts b/packages/core/src/routing/strategies/numericalClassifierStrategy.test.ts index 7988a560a6d..c4a9f595f0d 100644 --- a/packages/core/src/routing/strategies/numericalClassifierStrategy.test.ts +++ b/packages/core/src/routing/strategies/numericalClassifierStrategy.test.ts @@ -20,7 +20,7 @@ import { PREVIEW_GEMINI_MODEL_AUTO, DEFAULT_GEMINI_MODEL_AUTO, DEFAULT_GEMINI_MODEL, - DEFAULT_GEMINI_FLASH_MODEL, + LATEST_GEMINI_FLASH_MODEL, } from '../../config/models.js'; import { promptIdContext } from '../../utils/promptIdContext.js'; import type { Content } from '@google/genai'; @@ -896,8 +896,8 @@ describe('NumericalClassifierStrategy', () => { expect(decision?.model).toBe(PREVIEW_GEMINI_3_1_MODEL); }); - it('should route to DEFAULT_GEMINI_FLASH_MODEL when hasGemini35FlashGAAccess is true', async () => { - mockConfig.hasGemini35FlashGAAccess = vi.fn().mockReturnValue(true); + it('should route to LATEST_GEMINI_FLASH_MODEL when hasLatestFlashGAAccess is true', async () => { + mockConfig.hasLatestFlashGAAccess = vi.fn().mockReturnValue(true); vi.mocked(mockConfig.getModel).mockReturnValue(PREVIEW_GEMINI_MODEL_AUTO); const mockApiResponse = { @@ -915,7 +915,7 @@ describe('NumericalClassifierStrategy', () => { mockLocalLiteRtLmClient, ); - expect(decision?.model).toBe(DEFAULT_GEMINI_FLASH_MODEL); + expect(decision?.model).toBe(LATEST_GEMINI_FLASH_MODEL); }); }); }); diff --git a/packages/core/src/routing/strategies/numericalClassifierStrategy.ts b/packages/core/src/routing/strategies/numericalClassifierStrategy.ts index 32f919986bb..fc648d0b6d6 100644 --- a/packages/core/src/routing/strategies/numericalClassifierStrategy.ts +++ b/packages/core/src/routing/strategies/numericalClassifierStrategy.ts @@ -184,7 +184,8 @@ export class NumericalClassifierStrategy implements RoutingStrategy { config.getGemini31Launched(), config.getUseCustomToolModel(), ]); - const useGemini3_5Flash = config.hasGemini35FlashGAAccess?.() ?? false; + const useLatestFlash = config.hasLatestFlashGAAccess?.() ?? false; + const useLatestFlashLite = config.hasLatestFlashLiteGAAccess?.() ?? false; const selectedModel = normalizeModelId( resolveClassifierModel( normalizeModelId(model), @@ -193,7 +194,8 @@ export class NumericalClassifierStrategy implements RoutingStrategy { useCustomToolModel, config.getHasAccessToPreviewModel?.() ?? true, config, - useGemini3_5Flash, + useLatestFlash, + useLatestFlashLite, ), ); diff --git a/packages/core/src/routing/strategies/overrideStrategy.ts b/packages/core/src/routing/strategies/overrideStrategy.ts index e01bda48795..cf6986d5e56 100644 --- a/packages/core/src/routing/strategies/overrideStrategy.ts +++ b/packages/core/src/routing/strategies/overrideStrategy.ts @@ -41,7 +41,8 @@ export class OverrideStrategy implements RoutingStrategy { false, config.getHasAccessToPreviewModel?.() ?? true, config, - config.hasGemini35FlashGAAccess?.() ?? false, + config.hasLatestFlashGAAccess?.() ?? false, + config.hasLatestFlashLiteGAAccess?.() ?? false, ), metadata: { source: this.name, diff --git a/packages/core/src/services/modelConfigService.ts b/packages/core/src/services/modelConfigService.ts index 24e4325a112..9cdc206753e 100644 --- a/packages/core/src/services/modelConfigService.ts +++ b/packages/core/src/services/modelConfigService.ts @@ -100,7 +100,9 @@ export interface ModelResolution { export interface ResolutionContext { useGemini3_1?: boolean; useGemini3_1FlashLite?: boolean; + useLatestFlashLite?: boolean; useGemini3_5Flash?: boolean; + useLatestFlash?: boolean; useCustomTools?: boolean; hasAccessToPreview?: boolean; hasAccessToProModel?: boolean; @@ -111,10 +113,12 @@ export interface ResolutionContext { export interface ResolutionCondition { useGemini3_1?: boolean; useGemini3_1FlashLite?: boolean; + useLatestFlashLite?: boolean; useGemini3_5Flash?: boolean; + useLatestFlash?: boolean; useCustomTools?: boolean; hasAccessToPreview?: boolean; - /** Matches if the current model is in this list. */ + hasAccessToProModel?: boolean; requestedModels?: string[]; } @@ -160,7 +164,7 @@ export class ModelConfigService { const definitions = this.config.modelDefinitions ?? {}; const shouldShowPreviewModels = context.hasAccessToPreview ?? false; const useGemini31 = context.useGemini3_1 ?? false; - const useGemini3_5Flash = context.useGemini3_5Flash ?? false; + const useLatestFlash = context.useLatestFlash ?? false; const mainOptions = Object.entries(definitions) .filter(([_, m]) => { @@ -175,7 +179,7 @@ export class ModelConfigService { description = getAutoModelDescription( shouldShowPreviewModels, useGemini31, - useGemini3_5Flash, + useLatestFlash, ); } else if (id === 'auto-gemini-3' && useGemini31) { description = description.replace('gemini-3-pro', 'gemini-3.1-pro'); @@ -255,14 +259,28 @@ export class ModelConfigService { switch (key) { case 'useGemini3_1': return value === context.useGemini3_1; - case 'useGemini3_1FlashLite': - return value === context.useGemini3_1FlashLite; - case 'useGemini3_5Flash': - return value === context.useGemini3_5Flash; + case 'useLatestFlashLite': + case 'useGemini3_1FlashLite': { + const actualValue = + key === 'useLatestFlashLite' + ? (context.useLatestFlashLite ?? context.useGemini3_1FlashLite) + : (context.useGemini3_1FlashLite ?? context.useLatestFlashLite); + return value === actualValue; + } + case 'useLatestFlash': + case 'useGemini3_5Flash': { + const actualValue = + key === 'useLatestFlash' + ? (context.useLatestFlash ?? context.useGemini3_5Flash) + : (context.useGemini3_5Flash ?? context.useLatestFlash); + return value === actualValue; + } case 'useCustomTools': return value === context.useCustomTools; case 'hasAccessToPreview': return value === context.hasAccessToPreview; + case 'hasAccessToProModel': + return value === context.hasAccessToProModel; case 'requestedModels': return ( Array.isArray(value) && diff --git a/packages/core/src/services/test-data/resolved-aliases-retry.golden.json b/packages/core/src/services/test-data/resolved-aliases-retry.golden.json index aa470d45fef..5c61c090a09 100644 --- a/packages/core/src/services/test-data/resolved-aliases-retry.golden.json +++ b/packages/core/src/services/test-data/resolved-aliases-retry.golden.json @@ -145,6 +145,18 @@ "topK": 64 } }, + "gemini-3.5-flash-lite": { + "model": "gemini-3.5-flash-lite", + "generateContentConfig": { + "temperature": 1, + "topP": 0.95, + "thinkingConfig": { + "includeThoughts": true, + "thinkingLevel": "HIGH" + }, + "topK": 64 + } + }, "gemini-3.5-flash": { "model": "gemini-3.5-flash", "generateContentConfig": { @@ -157,6 +169,18 @@ "topK": 64 } }, + "gemini-3.8-flash": { + "model": "gemini-3.8-flash", + "generateContentConfig": { + "temperature": 1, + "topP": 0.95, + "thinkingConfig": { + "includeThoughts": true, + "thinkingLevel": "HIGH" + }, + "topK": 64 + } + }, "gemma-4-31b-it": { "model": "gemma-4-31b-it", "generateContentConfig": { diff --git a/packages/core/src/services/test-data/resolved-aliases.golden.json b/packages/core/src/services/test-data/resolved-aliases.golden.json index aa470d45fef..5c61c090a09 100644 --- a/packages/core/src/services/test-data/resolved-aliases.golden.json +++ b/packages/core/src/services/test-data/resolved-aliases.golden.json @@ -145,6 +145,18 @@ "topK": 64 } }, + "gemini-3.5-flash-lite": { + "model": "gemini-3.5-flash-lite", + "generateContentConfig": { + "temperature": 1, + "topP": 0.95, + "thinkingConfig": { + "includeThoughts": true, + "thinkingLevel": "HIGH" + }, + "topK": 64 + } + }, "gemini-3.5-flash": { "model": "gemini-3.5-flash", "generateContentConfig": { @@ -157,6 +169,18 @@ "topK": 64 } }, + "gemini-3.8-flash": { + "model": "gemini-3.8-flash", + "generateContentConfig": { + "temperature": 1, + "topP": 0.95, + "thinkingConfig": { + "includeThoughts": true, + "thinkingLevel": "HIGH" + }, + "topK": 64 + } + }, "gemma-4-31b-it": { "model": "gemma-4-31b-it", "generateContentConfig": { diff --git a/packages/core/src/utils/errorParsing.test.ts b/packages/core/src/utils/errorParsing.test.ts index d3c3a70c612..758444a8722 100644 --- a/packages/core/src/utils/errorParsing.test.ts +++ b/packages/core/src/utils/errorParsing.test.ts @@ -34,7 +34,7 @@ describe('parseAndFormatApiError', () => { ); 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', + `Possible quota limitations in place or slow response times detected. Switching to the ${DEFAULT_GEMINI_FLASH_MODEL} model for the rest of this session.`, ); }); diff --git a/schemas/settings.schema.json b/schemas/settings.schema.json index f78ee6b924d..c912b86ae71 100644 --- a/schemas/settings.schema.json +++ b/schemas/settings.schema.json @@ -741,7 +741,7 @@ "modelConfigs": { "title": "Model Configs", "description": "Model configurations.", - "markdownDescription": "Model configurations.\n\n- Category: `Model`\n- Requires restart: `no`\n- Default: `{\n \"aliases\": {\n \"base\": {\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"temperature\": 0,\n \"topP\": 1\n }\n }\n },\n \"chat-base\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"thinkingConfig\": {\n \"includeThoughts\": true\n },\n \"temperature\": 1,\n \"topP\": 0.95,\n \"topK\": 64\n }\n }\n },\n \"chat-base-2.5\": {\n \"extends\": \"chat-base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"thinkingConfig\": {\n \"thinkingBudget\": 8192\n }\n }\n }\n },\n \"chat-base-3\": {\n \"extends\": \"chat-base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"thinkingConfig\": {\n \"thinkingLevel\": \"HIGH\"\n }\n }\n }\n },\n \"gemini-3-pro-preview\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3-pro-preview\"\n }\n },\n \"gemini-3-flash-preview\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3-flash-preview\"\n }\n },\n \"gemini-3.1-pro-preview\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.1-pro-preview\"\n }\n },\n \"gemini-3.1-pro-preview-customtools\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.1-pro-preview-customtools\"\n }\n },\n \"gemini-3.1-flash-lite-preview\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.1-flash-lite-preview\"\n }\n },\n \"gemini-2.5-pro\": {\n \"extends\": \"chat-base-2.5\",\n \"modelConfig\": {\n \"model\": \"gemini-2.5-pro\"\n }\n },\n \"gemini-2.5-flash\": {\n \"extends\": \"chat-base-2.5\",\n \"modelConfig\": {\n \"model\": \"gemini-2.5-flash\"\n }\n },\n \"gemini-2.5-flash-lite\": {\n \"extends\": \"chat-base-2.5\",\n \"modelConfig\": {\n \"model\": \"gemini-2.5-flash-lite\"\n }\n },\n \"gemini-3.1-flash-lite\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.1-flash-lite\"\n }\n },\n \"gemini-3.5-flash\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.5-flash\"\n }\n },\n \"gemma-4-31b-it\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemma-4-31b-it\"\n }\n },\n \"gemma-4-26b-a4b-it\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemma-4-26b-a4b-it\"\n }\n },\n \"gemini-2.5-flash-base\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"gemini-2.5-flash\"\n }\n },\n \"gemini-3-flash-base\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"gemini-3-flash-preview\"\n }\n },\n \"gemini-3.5-flash-base\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"gemini-3.5-flash\"\n }\n },\n \"classifier\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"maxOutputTokens\": 1024,\n \"thinkingConfig\": {\n \"thinkingBudget\": 512\n }\n }\n }\n },\n \"prompt-completion\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"temperature\": 0.3,\n \"maxOutputTokens\": 16000,\n \"thinkingConfig\": {\n \"thinkingBudget\": 0\n }\n }\n }\n },\n \"fast-ack-helper\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"temperature\": 0.2,\n \"maxOutputTokens\": 120,\n \"thinkingConfig\": {\n \"thinkingBudget\": 0\n }\n }\n }\n },\n \"edit-corrector\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"thinkingConfig\": {\n \"thinkingBudget\": 0\n }\n }\n }\n },\n \"summarizer-default\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"maxOutputTokens\": 2000\n }\n }\n },\n \"summarizer-shell\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"maxOutputTokens\": 2000\n }\n }\n },\n \"web-search\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"tools\": [\n {\n \"googleSearch\": {}\n }\n ]\n }\n }\n },\n \"web-fetch\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"tools\": [\n {\n \"urlContext\": {}\n }\n ]\n }\n }\n },\n \"web-fetch-fallback\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {}\n },\n \"loop-detection\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {}\n },\n \"loop-detection-double-check\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"gemini-3-pro-preview\"\n }\n },\n \"llm-edit-fixer\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {}\n },\n \"next-speaker-checker\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {}\n },\n \"context-snapshotter\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"thinkingConfig\": {\n \"thinkingLevel\": \"HIGH\"\n },\n \"temperature\": 1,\n \"topP\": 0.95,\n \"topK\": 64\n }\n }\n },\n \"chat-compression-3-pro\": {\n \"modelConfig\": {\n \"model\": \"gemini-3-pro-preview\"\n }\n },\n \"chat-compression-3-flash\": {\n \"modelConfig\": {\n \"model\": \"gemini-3-flash-preview\"\n }\n },\n \"chat-compression-3.1-flash-lite\": {\n \"modelConfig\": {\n \"model\": \"gemini-3.1-flash-lite\"\n }\n },\n \"chat-compression-2.5-pro\": {\n \"modelConfig\": {\n \"model\": \"gemini-2.5-pro\"\n }\n },\n \"chat-compression-2.5-flash\": {\n \"modelConfig\": {\n \"model\": \"gemini-2.5-flash\"\n }\n },\n \"chat-compression-2.5-flash-lite\": {\n \"modelConfig\": {\n \"model\": \"gemini-2.5-flash-lite\"\n }\n },\n \"chat-compression-default\": {\n \"modelConfig\": {\n \"model\": \"gemini-3-pro-preview\"\n }\n },\n \"agent-history-provider-summarizer\": {\n \"modelConfig\": {\n \"model\": \"gemini-3-flash-preview\"\n }\n }\n },\n \"overrides\": [\n {\n \"match\": {\n \"model\": \"chat-base\",\n \"isRetry\": true\n },\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"temperature\": 1\n }\n }\n }\n ],\n \"modelDefinitions\": {\n \"gemini-3.1-flash-lite\": {\n \"tier\": \"flash-lite\",\n \"family\": \"gemini-3\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3.1-pro-preview\": {\n \"tier\": \"pro\",\n \"family\": \"gemini-3\",\n \"isPreview\": true,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3.1-pro-preview-customtools\": {\n \"tier\": \"pro\",\n \"family\": \"gemini-3\",\n \"isPreview\": true,\n \"isVisible\": false,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3-pro-preview\": {\n \"tier\": \"pro\",\n \"family\": \"gemini-3\",\n \"isPreview\": true,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3-flash-preview\": {\n \"tier\": \"flash\",\n \"family\": \"gemini-3\",\n \"isPreview\": true,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3.5-flash\": {\n \"tier\": \"flash\",\n \"family\": \"gemini-3\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-2.5-pro\": {\n \"tier\": \"pro\",\n \"family\": \"gemini-2.5\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": false\n }\n },\n \"gemini-2.5-flash\": {\n \"tier\": \"flash\",\n \"family\": \"gemini-2.5\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": false\n }\n },\n \"gemini-2.5-flash-lite\": {\n \"tier\": \"flash-lite\",\n \"family\": \"gemini-2.5\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": false\n }\n },\n \"gemma-4-31b-it\": {\n \"displayName\": \"gemma-4-31b-it\",\n \"tier\": \"custom\",\n \"family\": \"gemma-4\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": false\n }\n },\n \"gemma-4-26b-a4b-it\": {\n \"displayName\": \"gemma-4-26b-a4b-it\",\n \"tier\": \"custom\",\n \"family\": \"gemma-4\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": false\n }\n },\n \"auto\": {\n \"displayName\": \"Auto\",\n \"tier\": \"auto\",\n \"isPreview\": true,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": false\n }\n },\n \"pro\": {\n \"tier\": \"pro\",\n \"isPreview\": false,\n \"isVisible\": false,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": false\n }\n },\n \"flash\": {\n \"tier\": \"flash\",\n \"isPreview\": false,\n \"isVisible\": false,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": false\n }\n },\n \"flash-lite\": {\n \"tier\": \"flash-lite\",\n \"isPreview\": false,\n \"isVisible\": false,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": false\n }\n },\n \"auto-gemini-3\": {\n \"tier\": \"auto\",\n \"family\": \"gemini-3\",\n \"isPreview\": true,\n \"isVisible\": false\n },\n \"auto-gemini-2.5\": {\n \"tier\": \"auto\",\n \"family\": \"gemini-2.5\",\n \"isPreview\": false,\n \"isVisible\": false\n }\n },\n \"modelIdResolutions\": {\n \"gemma-4-31b-it\": {\n \"default\": \"gemma-4-31b-it\"\n },\n \"gemma-4-26b-a4b-it\": {\n \"default\": \"gemma-4-26b-a4b-it\"\n },\n \"gemini-3.1-pro-preview\": {\n \"default\": \"gemini-3.1-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n }\n ]\n },\n \"gemini-3.1-pro-preview-customtools\": {\n \"default\": \"gemini-3.1-pro-preview-customtools\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n }\n ]\n },\n \"gemini-3-flash-preview\": {\n \"default\": \"gemini-3-flash-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false,\n \"useGemini3_5Flash\": true\n },\n \"target\": \"gemini-3.5-flash\"\n },\n {\n \"condition\": {\n \"hasAccessToPreview\": false,\n \"useGemini3_5Flash\": false\n },\n \"target\": \"gemini-2.5-flash\"\n }\n ]\n },\n \"gemini-3.5-flash\": {\n \"default\": \"gemini-3.5-flash\",\n \"contexts\": [\n {\n \"condition\": {\n \"useGemini3_5Flash\": false,\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-flash\"\n },\n {\n \"condition\": {\n \"useGemini3_5Flash\": false\n },\n \"target\": \"gemini-3-flash-preview\"\n }\n ]\n },\n \"gemini-2.5-flash\": {\n \"default\": \"gemini-2.5-flash\",\n \"contexts\": [\n {\n \"condition\": {\n \"useGemini3_5Flash\": true\n },\n \"target\": \"gemini-3.5-flash\"\n }\n ]\n },\n \"gemini-3-pro-preview\": {\n \"default\": \"gemini-3-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true,\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true\n },\n \"target\": \"gemini-3.1-pro-preview\"\n }\n ]\n },\n \"auto\": {\n \"default\": \"gemini-3-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true,\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true\n },\n \"target\": \"gemini-3.1-pro-preview\"\n }\n ]\n },\n \"pro\": {\n \"default\": \"gemini-3-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true,\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true\n },\n \"target\": \"gemini-3.1-pro-preview\"\n }\n ]\n },\n \"gemini-3.1-flash-lite\": {\n \"default\": \"gemini-3.1-flash-lite\"\n },\n \"flash\": {\n \"default\": \"gemini-3-flash-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"useGemini3_5Flash\": true\n },\n \"target\": \"gemini-3.5-flash\"\n },\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-flash\"\n }\n ]\n },\n \"flash-lite\": {\n \"default\": \"gemini-3.1-flash-lite\"\n },\n \"auto-gemini-3\": {\n \"default\": \"gemini-3-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true,\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true\n },\n \"target\": \"gemini-3.1-pro-preview\"\n }\n ]\n },\n \"auto-gemini-2.5\": {\n \"default\": \"gemini-2.5-pro\"\n }\n },\n \"classifierIdResolutions\": {\n \"flash\": {\n \"default\": \"gemini-3-flash-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"useGemini3_5Flash\": true\n },\n \"target\": \"gemini-3.5-flash\"\n },\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-flash\"\n },\n {\n \"condition\": {\n \"requestedModels\": [\n \"gemini-2.5-pro\",\n \"auto-gemini-2.5\"\n ]\n },\n \"target\": \"gemini-2.5-flash\"\n }\n ]\n },\n \"pro\": {\n \"default\": \"gemini-3-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"requestedModels\": [\n \"gemini-2.5-pro\",\n \"auto-gemini-2.5\"\n ]\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true,\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true\n },\n \"target\": \"gemini-3.1-pro-preview\"\n }\n ]\n }\n },\n \"modelChains\": {\n \"preview\": [\n {\n \"model\": \"gemini-3-pro-preview\",\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-3-flash-preview\",\n \"isLastResort\": true,\n \"maxAttempts\": 10,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n }\n ],\n \"auto-preview\": [\n {\n \"model\": \"gemini-3-pro-preview\",\n \"maxAttempts\": 3,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"silent\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"sticky_retry\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-3-flash-preview\",\n \"isLastResort\": true,\n \"maxAttempts\": 10,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n }\n ],\n \"default\": [\n {\n \"model\": \"gemini-2.5-pro\",\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"sticky_retry\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-2.5-flash\",\n \"isLastResort\": true,\n \"maxAttempts\": 10,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n }\n ],\n \"auto-default\": [\n {\n \"model\": \"gemini-2.5-pro\",\n \"maxAttempts\": 3,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"silent\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"sticky_retry\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-2.5-flash\",\n \"isLastResort\": true,\n \"maxAttempts\": 10,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n }\n ],\n \"lite\": [\n {\n \"model\": \"flash-lite\",\n \"actions\": {\n \"terminal\": \"silent\",\n \"transient\": \"silent\",\n \"not_found\": \"silent\",\n \"unknown\": \"silent\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-2.5-flash\",\n \"actions\": {\n \"terminal\": \"silent\",\n \"transient\": \"silent\",\n \"not_found\": \"silent\",\n \"unknown\": \"silent\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-2.5-pro\",\n \"isLastResort\": true,\n \"actions\": {\n \"terminal\": \"silent\",\n \"transient\": \"silent\",\n \"not_found\": \"silent\",\n \"unknown\": \"silent\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n }\n ]\n }\n}`", + "markdownDescription": "Model configurations.\n\n- Category: `Model`\n- Requires restart: `no`\n- Default: `{\n \"aliases\": {\n \"base\": {\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"temperature\": 0,\n \"topP\": 1\n }\n }\n },\n \"chat-base\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"thinkingConfig\": {\n \"includeThoughts\": true\n },\n \"temperature\": 1,\n \"topP\": 0.95,\n \"topK\": 64\n }\n }\n },\n \"chat-base-2.5\": {\n \"extends\": \"chat-base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"thinkingConfig\": {\n \"thinkingBudget\": 8192\n }\n }\n }\n },\n \"chat-base-3\": {\n \"extends\": \"chat-base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"thinkingConfig\": {\n \"thinkingLevel\": \"HIGH\"\n }\n }\n }\n },\n \"gemini-3-pro-preview\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3-pro-preview\"\n }\n },\n \"gemini-3-flash-preview\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3-flash-preview\"\n }\n },\n \"gemini-3.1-pro-preview\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.1-pro-preview\"\n }\n },\n \"gemini-3.1-pro-preview-customtools\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.1-pro-preview-customtools\"\n }\n },\n \"gemini-3.1-flash-lite-preview\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.1-flash-lite-preview\"\n }\n },\n \"gemini-2.5-pro\": {\n \"extends\": \"chat-base-2.5\",\n \"modelConfig\": {\n \"model\": \"gemini-2.5-pro\"\n }\n },\n \"gemini-2.5-flash\": {\n \"extends\": \"chat-base-2.5\",\n \"modelConfig\": {\n \"model\": \"gemini-2.5-flash\"\n }\n },\n \"gemini-2.5-flash-lite\": {\n \"extends\": \"chat-base-2.5\",\n \"modelConfig\": {\n \"model\": \"gemini-2.5-flash-lite\"\n }\n },\n \"gemini-3.1-flash-lite\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.1-flash-lite\"\n }\n },\n \"gemini-3.5-flash-lite\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.5-flash-lite\"\n }\n },\n \"gemini-3.5-flash\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.5-flash\"\n }\n },\n \"gemini-3.8-flash\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.8-flash\"\n }\n },\n \"gemma-4-31b-it\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemma-4-31b-it\"\n }\n },\n \"gemma-4-26b-a4b-it\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemma-4-26b-a4b-it\"\n }\n },\n \"gemini-2.5-flash-base\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"gemini-2.5-flash\"\n }\n },\n \"gemini-3-flash-base\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"gemini-3-flash-preview\"\n }\n },\n \"gemini-3.5-flash-base\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"gemini-3.5-flash\"\n }\n },\n \"classifier\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"maxOutputTokens\": 1024,\n \"thinkingConfig\": {\n \"thinkingBudget\": 512\n }\n }\n }\n },\n \"prompt-completion\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"temperature\": 0.3,\n \"maxOutputTokens\": 16000,\n \"thinkingConfig\": {\n \"thinkingBudget\": 0\n }\n }\n }\n },\n \"fast-ack-helper\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"temperature\": 0.2,\n \"maxOutputTokens\": 120,\n \"thinkingConfig\": {\n \"thinkingBudget\": 0\n }\n }\n }\n },\n \"edit-corrector\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"thinkingConfig\": {\n \"thinkingBudget\": 0\n }\n }\n }\n },\n \"summarizer-default\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"maxOutputTokens\": 2000\n }\n }\n },\n \"summarizer-shell\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"maxOutputTokens\": 2000\n }\n }\n },\n \"web-search\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"tools\": [\n {\n \"googleSearch\": {}\n }\n ]\n }\n }\n },\n \"web-fetch\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"tools\": [\n {\n \"urlContext\": {}\n }\n ]\n }\n }\n },\n \"web-fetch-fallback\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {}\n },\n \"loop-detection\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {}\n },\n \"loop-detection-double-check\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"gemini-3-pro-preview\"\n }\n },\n \"llm-edit-fixer\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {}\n },\n \"next-speaker-checker\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {}\n },\n \"context-snapshotter\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"thinkingConfig\": {\n \"thinkingLevel\": \"HIGH\"\n },\n \"temperature\": 1,\n \"topP\": 0.95,\n \"topK\": 64\n }\n }\n },\n \"chat-compression-3-pro\": {\n \"modelConfig\": {\n \"model\": \"gemini-3-pro-preview\"\n }\n },\n \"chat-compression-3-flash\": {\n \"modelConfig\": {\n \"model\": \"gemini-3-flash-preview\"\n }\n },\n \"chat-compression-3.1-flash-lite\": {\n \"modelConfig\": {\n \"model\": \"gemini-3.1-flash-lite\"\n }\n },\n \"chat-compression-2.5-pro\": {\n \"modelConfig\": {\n \"model\": \"gemini-2.5-pro\"\n }\n },\n \"chat-compression-2.5-flash\": {\n \"modelConfig\": {\n \"model\": \"gemini-2.5-flash\"\n }\n },\n \"chat-compression-2.5-flash-lite\": {\n \"modelConfig\": {\n \"model\": \"gemini-2.5-flash-lite\"\n }\n },\n \"chat-compression-default\": {\n \"modelConfig\": {\n \"model\": \"gemini-3-pro-preview\"\n }\n },\n \"agent-history-provider-summarizer\": {\n \"modelConfig\": {\n \"model\": \"gemini-3-flash-preview\"\n }\n }\n },\n \"overrides\": [\n {\n \"match\": {\n \"model\": \"chat-base\",\n \"isRetry\": true\n },\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"temperature\": 1\n }\n }\n }\n ],\n \"modelDefinitions\": {\n \"gemini-3.1-flash-lite\": {\n \"tier\": \"flash-lite\",\n \"family\": \"gemini-3\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3.5-flash-lite\": {\n \"tier\": \"flash-lite\",\n \"family\": \"gemini-3\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3.1-pro-preview\": {\n \"tier\": \"pro\",\n \"family\": \"gemini-3\",\n \"isPreview\": true,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3.1-pro-preview-customtools\": {\n \"tier\": \"pro\",\n \"family\": \"gemini-3\",\n \"isPreview\": true,\n \"isVisible\": false,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3-pro-preview\": {\n \"tier\": \"pro\",\n \"family\": \"gemini-3\",\n \"isPreview\": true,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3-flash-preview\": {\n \"tier\": \"flash\",\n \"family\": \"gemini-3\",\n \"isPreview\": true,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3.5-flash\": {\n \"tier\": \"flash\",\n \"family\": \"gemini-3\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3.8-flash\": {\n \"tier\": \"flash\",\n \"family\": \"gemini-3\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-2.5-pro\": {\n \"tier\": \"pro\",\n \"family\": \"gemini-2.5\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": false\n }\n },\n \"gemini-2.5-flash\": {\n \"tier\": \"flash\",\n \"family\": \"gemini-2.5\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": false\n }\n },\n \"gemini-2.5-flash-lite\": {\n \"tier\": \"flash-lite\",\n \"family\": \"gemini-2.5\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": false\n }\n },\n \"gemma-4-31b-it\": {\n \"displayName\": \"gemma-4-31b-it\",\n \"tier\": \"custom\",\n \"family\": \"gemma-4\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": false\n }\n },\n \"gemma-4-26b-a4b-it\": {\n \"displayName\": \"gemma-4-26b-a4b-it\",\n \"tier\": \"custom\",\n \"family\": \"gemma-4\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": false\n }\n },\n \"auto\": {\n \"displayName\": \"Auto\",\n \"tier\": \"auto\",\n \"isPreview\": true,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": false\n }\n },\n \"pro\": {\n \"tier\": \"pro\",\n \"isPreview\": false,\n \"isVisible\": false,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": false\n }\n },\n \"flash\": {\n \"tier\": \"flash\",\n \"isPreview\": false,\n \"isVisible\": false,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": false\n }\n },\n \"flash-lite\": {\n \"tier\": \"flash-lite\",\n \"isPreview\": false,\n \"isVisible\": false,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": false\n }\n },\n \"auto-gemini-3\": {\n \"tier\": \"auto\",\n \"family\": \"gemini-3\",\n \"isPreview\": true,\n \"isVisible\": false\n },\n \"auto-gemini-2.5\": {\n \"tier\": \"auto\",\n \"family\": \"gemini-2.5\",\n \"isPreview\": false,\n \"isVisible\": false\n }\n },\n \"modelIdResolutions\": {\n \"gemma-4-31b-it\": {\n \"default\": \"gemma-4-31b-it\"\n },\n \"gemma-4-26b-a4b-it\": {\n \"default\": \"gemma-4-26b-a4b-it\"\n },\n \"gemini-3.1-pro-preview\": {\n \"default\": \"gemini-3.1-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n }\n ]\n },\n \"gemini-3.1-pro-preview-customtools\": {\n \"default\": \"gemini-3.1-pro-preview-customtools\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n }\n ]\n },\n \"gemini-3-flash-preview\": {\n \"default\": \"gemini-3-flash-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false,\n \"useLatestFlash\": true\n },\n \"target\": \"gemini-3.8-flash\"\n },\n {\n \"condition\": {\n \"hasAccessToPreview\": false,\n \"useLatestFlash\": false\n },\n \"target\": \"gemini-3.5-flash\"\n }\n ]\n },\n \"gemini-3.5-flash\": {\n \"default\": \"gemini-3.5-flash\",\n \"contexts\": [\n {\n \"condition\": {\n \"useLatestFlash\": true\n },\n \"target\": \"gemini-3.8-flash\"\n }\n ]\n },\n \"gemini-3.8-flash\": {\n \"default\": \"gemini-3.8-flash\",\n \"contexts\": [\n {\n \"condition\": {\n \"useLatestFlash\": false\n },\n \"target\": \"gemini-3.5-flash\"\n }\n ]\n },\n \"gemini-2.5-flash\": {\n \"default\": \"gemini-2.5-flash\",\n \"contexts\": [\n {\n \"condition\": {\n \"useLatestFlash\": true\n },\n \"target\": \"gemini-3.8-flash\"\n }\n ]\n },\n \"gemini-3-pro-preview\": {\n \"default\": \"gemini-3-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true,\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true\n },\n \"target\": \"gemini-3.1-pro-preview\"\n }\n ]\n },\n \"auto\": {\n \"default\": \"gemini-3-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true,\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true\n },\n \"target\": \"gemini-3.1-pro-preview\"\n }\n ]\n },\n \"pro\": {\n \"default\": \"gemini-3-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true,\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true\n },\n \"target\": \"gemini-3.1-pro-preview\"\n }\n ]\n },\n \"gemini-3.1-flash-lite\": {\n \"default\": \"gemini-3.1-flash-lite\",\n \"contexts\": [\n {\n \"condition\": {\n \"useLatestFlashLite\": true\n },\n \"target\": \"gemini-3.5-flash-lite\"\n }\n ]\n },\n \"gemini-3.5-flash-lite\": {\n \"default\": \"gemini-3.5-flash-lite\",\n \"contexts\": [\n {\n \"condition\": {\n \"useLatestFlashLite\": false\n },\n \"target\": \"gemini-3.1-flash-lite\"\n }\n ]\n },\n \"flash\": {\n \"default\": \"gemini-3-flash-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"useLatestFlash\": true\n },\n \"target\": \"gemini-3.8-flash\"\n },\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-3.5-flash\"\n }\n ]\n },\n \"flash-lite\": {\n \"default\": \"gemini-3.1-flash-lite\",\n \"contexts\": [\n {\n \"condition\": {\n \"useLatestFlashLite\": true\n },\n \"target\": \"gemini-3.5-flash-lite\"\n }\n ]\n },\n \"auto-gemini-3\": {\n \"default\": \"gemini-3-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true,\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true\n },\n \"target\": \"gemini-3.1-pro-preview\"\n }\n ]\n },\n \"auto-gemini-2.5\": {\n \"default\": \"gemini-2.5-pro\"\n }\n },\n \"classifierIdResolutions\": {\n \"flash\": {\n \"default\": \"gemini-3-flash-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"useLatestFlash\": true\n },\n \"target\": \"gemini-3.8-flash\"\n },\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-3.5-flash\"\n },\n {\n \"condition\": {\n \"requestedModels\": [\n \"gemini-2.5-pro\",\n \"auto-gemini-2.5\"\n ]\n },\n \"target\": \"gemini-3.5-flash\"\n }\n ]\n },\n \"pro\": {\n \"default\": \"gemini-3-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"requestedModels\": [\n \"gemini-2.5-pro\",\n \"auto-gemini-2.5\"\n ]\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true,\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true\n },\n \"target\": \"gemini-3.1-pro-preview\"\n }\n ]\n }\n },\n \"modelChains\": {\n \"preview\": [\n {\n \"model\": \"gemini-3-pro-preview\",\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-3-flash-preview\",\n \"isLastResort\": true,\n \"maxAttempts\": 10,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n }\n ],\n \"auto-preview\": [\n {\n \"model\": \"gemini-3-pro-preview\",\n \"maxAttempts\": 3,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"silent\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"sticky_retry\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-3-flash-preview\",\n \"isLastResort\": true,\n \"maxAttempts\": 10,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n }\n ],\n \"default\": [\n {\n \"model\": \"gemini-2.5-pro\",\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"sticky_retry\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-3.5-flash\",\n \"isLastResort\": true,\n \"maxAttempts\": 10,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n }\n ],\n \"auto-default\": [\n {\n \"model\": \"gemini-2.5-pro\",\n \"maxAttempts\": 3,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"silent\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"sticky_retry\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-3.5-flash\",\n \"isLastResort\": true,\n \"maxAttempts\": 10,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n }\n ],\n \"lite\": [\n {\n \"model\": \"gemini-3.1-flash-lite\",\n \"actions\": {\n \"terminal\": \"silent\",\n \"transient\": \"silent\",\n \"not_found\": \"silent\",\n \"unknown\": \"silent\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-3.5-flash\",\n \"actions\": {\n \"terminal\": \"silent\",\n \"transient\": \"silent\",\n \"not_found\": \"silent\",\n \"unknown\": \"silent\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-2.5-pro\",\n \"isLastResort\": true,\n \"actions\": {\n \"terminal\": \"silent\",\n \"transient\": \"silent\",\n \"not_found\": \"silent\",\n \"unknown\": \"silent\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n }\n ]\n }\n}`", "default": { "aliases": { "base": { @@ -839,12 +839,24 @@ "model": "gemini-3.1-flash-lite" } }, + "gemini-3.5-flash-lite": { + "extends": "chat-base-3", + "modelConfig": { + "model": "gemini-3.5-flash-lite" + } + }, "gemini-3.5-flash": { "extends": "chat-base-3", "modelConfig": { "model": "gemini-3.5-flash" } }, + "gemini-3.8-flash": { + "extends": "chat-base-3", + "modelConfig": { + "model": "gemini-3.8-flash" + } + }, "gemma-4-31b-it": { "extends": "chat-base-3", "modelConfig": { @@ -1066,6 +1078,16 @@ "multimodalToolUse": true } }, + "gemini-3.5-flash-lite": { + "tier": "flash-lite", + "family": "gemini-3", + "isPreview": false, + "isVisible": true, + "features": { + "thinking": false, + "multimodalToolUse": true + } + }, "gemini-3.1-pro-preview": { "tier": "pro", "family": "gemini-3", @@ -1116,6 +1138,16 @@ "multimodalToolUse": true } }, + "gemini-3.8-flash": { + "tier": "flash", + "family": "gemini-3", + "isPreview": false, + "isVisible": true, + "features": { + "thinking": false, + "multimodalToolUse": true + } + }, "gemini-2.5-pro": { "tier": "pro", "family": "gemini-2.5", @@ -1259,16 +1291,16 @@ { "condition": { "hasAccessToPreview": false, - "useGemini3_5Flash": true + "useLatestFlash": true }, - "target": "gemini-3.5-flash" + "target": "gemini-3.8-flash" }, { "condition": { "hasAccessToPreview": false, - "useGemini3_5Flash": false + "useLatestFlash": false }, - "target": "gemini-2.5-flash" + "target": "gemini-3.5-flash" } ] }, @@ -1277,16 +1309,20 @@ "contexts": [ { "condition": { - "useGemini3_5Flash": false, - "hasAccessToPreview": false + "useLatestFlash": true }, - "target": "gemini-2.5-flash" - }, + "target": "gemini-3.8-flash" + } + ] + }, + "gemini-3.8-flash": { + "default": "gemini-3.8-flash", + "contexts": [ { "condition": { - "useGemini3_5Flash": false + "useLatestFlash": false }, - "target": "gemini-3-flash-preview" + "target": "gemini-3.5-flash" } ] }, @@ -1295,9 +1331,9 @@ "contexts": [ { "condition": { - "useGemini3_5Flash": true + "useLatestFlash": true }, - "target": "gemini-3.5-flash" + "target": "gemini-3.8-flash" } ] }, @@ -1374,27 +1410,54 @@ ] }, "gemini-3.1-flash-lite": { - "default": "gemini-3.1-flash-lite" + "default": "gemini-3.1-flash-lite", + "contexts": [ + { + "condition": { + "useLatestFlashLite": true + }, + "target": "gemini-3.5-flash-lite" + } + ] + }, + "gemini-3.5-flash-lite": { + "default": "gemini-3.5-flash-lite", + "contexts": [ + { + "condition": { + "useLatestFlashLite": false + }, + "target": "gemini-3.1-flash-lite" + } + ] }, "flash": { "default": "gemini-3-flash-preview", "contexts": [ { "condition": { - "useGemini3_5Flash": true + "useLatestFlash": true }, - "target": "gemini-3.5-flash" + "target": "gemini-3.8-flash" }, { "condition": { "hasAccessToPreview": false }, - "target": "gemini-2.5-flash" + "target": "gemini-3.5-flash" } ] }, "flash-lite": { - "default": "gemini-3.1-flash-lite" + "default": "gemini-3.1-flash-lite", + "contexts": [ + { + "condition": { + "useLatestFlashLite": true + }, + "target": "gemini-3.5-flash-lite" + } + ] }, "auto-gemini-3": { "default": "gemini-3-pro-preview", @@ -1430,21 +1493,21 @@ "contexts": [ { "condition": { - "useGemini3_5Flash": true + "useLatestFlash": true }, - "target": "gemini-3.5-flash" + "target": "gemini-3.8-flash" }, { "condition": { "hasAccessToPreview": false }, - "target": "gemini-2.5-flash" + "target": "gemini-3.5-flash" }, { "condition": { "requestedModels": ["gemini-2.5-pro", "auto-gemini-2.5"] }, - "target": "gemini-2.5-flash" + "target": "gemini-3.5-flash" } ] }, @@ -1566,7 +1629,7 @@ } }, { - "model": "gemini-2.5-flash", + "model": "gemini-3.5-flash", "isLastResort": true, "maxAttempts": 10, "actions": { @@ -1601,7 +1664,7 @@ } }, { - "model": "gemini-2.5-flash", + "model": "gemini-3.5-flash", "isLastResort": true, "maxAttempts": 10, "actions": { @@ -1620,7 +1683,7 @@ ], "lite": [ { - "model": "flash-lite", + "model": "gemini-3.1-flash-lite", "actions": { "terminal": "silent", "transient": "silent", @@ -1635,7 +1698,7 @@ } }, { - "model": "gemini-2.5-flash", + "model": "gemini-3.5-flash", "actions": { "terminal": "silent", "transient": "silent", @@ -1673,7 +1736,7 @@ "aliases": { "title": "Model Config Aliases", "description": "Named presets for model configs. Can be used in place of a model name and can inherit from other aliases using an `extends` property.", - "markdownDescription": "Named presets for model configs. Can be used in place of a model name and can inherit from other aliases using an `extends` property.\n\n- Category: `Model`\n- Requires restart: `no`\n- Default: `{\n \"base\": {\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"temperature\": 0,\n \"topP\": 1\n }\n }\n },\n \"chat-base\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"thinkingConfig\": {\n \"includeThoughts\": true\n },\n \"temperature\": 1,\n \"topP\": 0.95,\n \"topK\": 64\n }\n }\n },\n \"chat-base-2.5\": {\n \"extends\": \"chat-base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"thinkingConfig\": {\n \"thinkingBudget\": 8192\n }\n }\n }\n },\n \"chat-base-3\": {\n \"extends\": \"chat-base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"thinkingConfig\": {\n \"thinkingLevel\": \"HIGH\"\n }\n }\n }\n },\n \"gemini-3-pro-preview\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3-pro-preview\"\n }\n },\n \"gemini-3-flash-preview\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3-flash-preview\"\n }\n },\n \"gemini-3.1-pro-preview\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.1-pro-preview\"\n }\n },\n \"gemini-3.1-pro-preview-customtools\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.1-pro-preview-customtools\"\n }\n },\n \"gemini-3.1-flash-lite-preview\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.1-flash-lite-preview\"\n }\n },\n \"gemini-2.5-pro\": {\n \"extends\": \"chat-base-2.5\",\n \"modelConfig\": {\n \"model\": \"gemini-2.5-pro\"\n }\n },\n \"gemini-2.5-flash\": {\n \"extends\": \"chat-base-2.5\",\n \"modelConfig\": {\n \"model\": \"gemini-2.5-flash\"\n }\n },\n \"gemini-2.5-flash-lite\": {\n \"extends\": \"chat-base-2.5\",\n \"modelConfig\": {\n \"model\": \"gemini-2.5-flash-lite\"\n }\n },\n \"gemini-3.1-flash-lite\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.1-flash-lite\"\n }\n },\n \"gemini-3.5-flash\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.5-flash\"\n }\n },\n \"gemma-4-31b-it\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemma-4-31b-it\"\n }\n },\n \"gemma-4-26b-a4b-it\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemma-4-26b-a4b-it\"\n }\n },\n \"gemini-2.5-flash-base\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"gemini-2.5-flash\"\n }\n },\n \"gemini-3-flash-base\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"gemini-3-flash-preview\"\n }\n },\n \"gemini-3.5-flash-base\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"gemini-3.5-flash\"\n }\n },\n \"classifier\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"maxOutputTokens\": 1024,\n \"thinkingConfig\": {\n \"thinkingBudget\": 512\n }\n }\n }\n },\n \"prompt-completion\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"temperature\": 0.3,\n \"maxOutputTokens\": 16000,\n \"thinkingConfig\": {\n \"thinkingBudget\": 0\n }\n }\n }\n },\n \"fast-ack-helper\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"temperature\": 0.2,\n \"maxOutputTokens\": 120,\n \"thinkingConfig\": {\n \"thinkingBudget\": 0\n }\n }\n }\n },\n \"edit-corrector\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"thinkingConfig\": {\n \"thinkingBudget\": 0\n }\n }\n }\n },\n \"summarizer-default\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"maxOutputTokens\": 2000\n }\n }\n },\n \"summarizer-shell\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"maxOutputTokens\": 2000\n }\n }\n },\n \"web-search\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"tools\": [\n {\n \"googleSearch\": {}\n }\n ]\n }\n }\n },\n \"web-fetch\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"tools\": [\n {\n \"urlContext\": {}\n }\n ]\n }\n }\n },\n \"web-fetch-fallback\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {}\n },\n \"loop-detection\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {}\n },\n \"loop-detection-double-check\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"gemini-3-pro-preview\"\n }\n },\n \"llm-edit-fixer\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {}\n },\n \"next-speaker-checker\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {}\n },\n \"context-snapshotter\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"thinkingConfig\": {\n \"thinkingLevel\": \"HIGH\"\n },\n \"temperature\": 1,\n \"topP\": 0.95,\n \"topK\": 64\n }\n }\n },\n \"chat-compression-3-pro\": {\n \"modelConfig\": {\n \"model\": \"gemini-3-pro-preview\"\n }\n },\n \"chat-compression-3-flash\": {\n \"modelConfig\": {\n \"model\": \"gemini-3-flash-preview\"\n }\n },\n \"chat-compression-3.1-flash-lite\": {\n \"modelConfig\": {\n \"model\": \"gemini-3.1-flash-lite\"\n }\n },\n \"chat-compression-2.5-pro\": {\n \"modelConfig\": {\n \"model\": \"gemini-2.5-pro\"\n }\n },\n \"chat-compression-2.5-flash\": {\n \"modelConfig\": {\n \"model\": \"gemini-2.5-flash\"\n }\n },\n \"chat-compression-2.5-flash-lite\": {\n \"modelConfig\": {\n \"model\": \"gemini-2.5-flash-lite\"\n }\n },\n \"chat-compression-default\": {\n \"modelConfig\": {\n \"model\": \"gemini-3-pro-preview\"\n }\n },\n \"agent-history-provider-summarizer\": {\n \"modelConfig\": {\n \"model\": \"gemini-3-flash-preview\"\n }\n }\n}`", + "markdownDescription": "Named presets for model configs. Can be used in place of a model name and can inherit from other aliases using an `extends` property.\n\n- Category: `Model`\n- Requires restart: `no`\n- Default: `{\n \"base\": {\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"temperature\": 0,\n \"topP\": 1\n }\n }\n },\n \"chat-base\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"thinkingConfig\": {\n \"includeThoughts\": true\n },\n \"temperature\": 1,\n \"topP\": 0.95,\n \"topK\": 64\n }\n }\n },\n \"chat-base-2.5\": {\n \"extends\": \"chat-base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"thinkingConfig\": {\n \"thinkingBudget\": 8192\n }\n }\n }\n },\n \"chat-base-3\": {\n \"extends\": \"chat-base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"thinkingConfig\": {\n \"thinkingLevel\": \"HIGH\"\n }\n }\n }\n },\n \"gemini-3-pro-preview\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3-pro-preview\"\n }\n },\n \"gemini-3-flash-preview\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3-flash-preview\"\n }\n },\n \"gemini-3.1-pro-preview\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.1-pro-preview\"\n }\n },\n \"gemini-3.1-pro-preview-customtools\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.1-pro-preview-customtools\"\n }\n },\n \"gemini-3.1-flash-lite-preview\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.1-flash-lite-preview\"\n }\n },\n \"gemini-2.5-pro\": {\n \"extends\": \"chat-base-2.5\",\n \"modelConfig\": {\n \"model\": \"gemini-2.5-pro\"\n }\n },\n \"gemini-2.5-flash\": {\n \"extends\": \"chat-base-2.5\",\n \"modelConfig\": {\n \"model\": \"gemini-2.5-flash\"\n }\n },\n \"gemini-2.5-flash-lite\": {\n \"extends\": \"chat-base-2.5\",\n \"modelConfig\": {\n \"model\": \"gemini-2.5-flash-lite\"\n }\n },\n \"gemini-3.1-flash-lite\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.1-flash-lite\"\n }\n },\n \"gemini-3.5-flash-lite\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.5-flash-lite\"\n }\n },\n \"gemini-3.5-flash\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.5-flash\"\n }\n },\n \"gemini-3.8-flash\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemini-3.8-flash\"\n }\n },\n \"gemma-4-31b-it\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemma-4-31b-it\"\n }\n },\n \"gemma-4-26b-a4b-it\": {\n \"extends\": \"chat-base-3\",\n \"modelConfig\": {\n \"model\": \"gemma-4-26b-a4b-it\"\n }\n },\n \"gemini-2.5-flash-base\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"gemini-2.5-flash\"\n }\n },\n \"gemini-3-flash-base\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"gemini-3-flash-preview\"\n }\n },\n \"gemini-3.5-flash-base\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"gemini-3.5-flash\"\n }\n },\n \"classifier\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"maxOutputTokens\": 1024,\n \"thinkingConfig\": {\n \"thinkingBudget\": 512\n }\n }\n }\n },\n \"prompt-completion\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"temperature\": 0.3,\n \"maxOutputTokens\": 16000,\n \"thinkingConfig\": {\n \"thinkingBudget\": 0\n }\n }\n }\n },\n \"fast-ack-helper\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"temperature\": 0.2,\n \"maxOutputTokens\": 120,\n \"thinkingConfig\": {\n \"thinkingBudget\": 0\n }\n }\n }\n },\n \"edit-corrector\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"thinkingConfig\": {\n \"thinkingBudget\": 0\n }\n }\n }\n },\n \"summarizer-default\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"maxOutputTokens\": 2000\n }\n }\n },\n \"summarizer-shell\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"flash-lite\",\n \"generateContentConfig\": {\n \"maxOutputTokens\": 2000\n }\n }\n },\n \"web-search\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"tools\": [\n {\n \"googleSearch\": {}\n }\n ]\n }\n }\n },\n \"web-fetch\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"tools\": [\n {\n \"urlContext\": {}\n }\n ]\n }\n }\n },\n \"web-fetch-fallback\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {}\n },\n \"loop-detection\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {}\n },\n \"loop-detection-double-check\": {\n \"extends\": \"base\",\n \"modelConfig\": {\n \"model\": \"gemini-3-pro-preview\"\n }\n },\n \"llm-edit-fixer\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {}\n },\n \"next-speaker-checker\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {}\n },\n \"context-snapshotter\": {\n \"extends\": \"gemini-3-flash-base\",\n \"modelConfig\": {\n \"generateContentConfig\": {\n \"thinkingConfig\": {\n \"thinkingLevel\": \"HIGH\"\n },\n \"temperature\": 1,\n \"topP\": 0.95,\n \"topK\": 64\n }\n }\n },\n \"chat-compression-3-pro\": {\n \"modelConfig\": {\n \"model\": \"gemini-3-pro-preview\"\n }\n },\n \"chat-compression-3-flash\": {\n \"modelConfig\": {\n \"model\": \"gemini-3-flash-preview\"\n }\n },\n \"chat-compression-3.1-flash-lite\": {\n \"modelConfig\": {\n \"model\": \"gemini-3.1-flash-lite\"\n }\n },\n \"chat-compression-2.5-pro\": {\n \"modelConfig\": {\n \"model\": \"gemini-2.5-pro\"\n }\n },\n \"chat-compression-2.5-flash\": {\n \"modelConfig\": {\n \"model\": \"gemini-2.5-flash\"\n }\n },\n \"chat-compression-2.5-flash-lite\": {\n \"modelConfig\": {\n \"model\": \"gemini-2.5-flash-lite\"\n }\n },\n \"chat-compression-default\": {\n \"modelConfig\": {\n \"model\": \"gemini-3-pro-preview\"\n }\n },\n \"agent-history-provider-summarizer\": {\n \"modelConfig\": {\n \"model\": \"gemini-3-flash-preview\"\n }\n }\n}`", "default": { "base": { "modelConfig": { @@ -1770,12 +1833,24 @@ "model": "gemini-3.1-flash-lite" } }, + "gemini-3.5-flash-lite": { + "extends": "chat-base-3", + "modelConfig": { + "model": "gemini-3.5-flash-lite" + } + }, "gemini-3.5-flash": { "extends": "chat-base-3", "modelConfig": { "model": "gemini-3.5-flash" } }, + "gemini-3.8-flash": { + "extends": "chat-base-3", + "modelConfig": { + "model": "gemini-3.8-flash" + } + }, "gemma-4-31b-it": { "extends": "chat-base-3", "modelConfig": { @@ -2003,7 +2078,7 @@ "modelDefinitions": { "title": "Model Definitions", "description": "Registry of model metadata, including tier, family, and features.", - "markdownDescription": "Registry of model metadata, including tier, family, and features.\n\n- Category: `Model`\n- Requires restart: `yes`\n- Default: `{\n \"gemini-3.1-flash-lite\": {\n \"tier\": \"flash-lite\",\n \"family\": \"gemini-3\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3.1-pro-preview\": {\n \"tier\": \"pro\",\n \"family\": \"gemini-3\",\n \"isPreview\": true,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3.1-pro-preview-customtools\": {\n \"tier\": \"pro\",\n \"family\": \"gemini-3\",\n \"isPreview\": true,\n \"isVisible\": false,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3-pro-preview\": {\n \"tier\": \"pro\",\n \"family\": \"gemini-3\",\n \"isPreview\": true,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3-flash-preview\": {\n \"tier\": \"flash\",\n \"family\": \"gemini-3\",\n \"isPreview\": true,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3.5-flash\": {\n \"tier\": \"flash\",\n \"family\": \"gemini-3\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-2.5-pro\": {\n \"tier\": \"pro\",\n \"family\": \"gemini-2.5\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": false\n }\n },\n \"gemini-2.5-flash\": {\n \"tier\": \"flash\",\n \"family\": \"gemini-2.5\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": false\n }\n },\n \"gemini-2.5-flash-lite\": {\n \"tier\": \"flash-lite\",\n \"family\": \"gemini-2.5\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": false\n }\n },\n \"gemma-4-31b-it\": {\n \"displayName\": \"gemma-4-31b-it\",\n \"tier\": \"custom\",\n \"family\": \"gemma-4\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": false\n }\n },\n \"gemma-4-26b-a4b-it\": {\n \"displayName\": \"gemma-4-26b-a4b-it\",\n \"tier\": \"custom\",\n \"family\": \"gemma-4\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": false\n }\n },\n \"auto\": {\n \"displayName\": \"Auto\",\n \"tier\": \"auto\",\n \"isPreview\": true,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": false\n }\n },\n \"pro\": {\n \"tier\": \"pro\",\n \"isPreview\": false,\n \"isVisible\": false,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": false\n }\n },\n \"flash\": {\n \"tier\": \"flash\",\n \"isPreview\": false,\n \"isVisible\": false,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": false\n }\n },\n \"flash-lite\": {\n \"tier\": \"flash-lite\",\n \"isPreview\": false,\n \"isVisible\": false,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": false\n }\n },\n \"auto-gemini-3\": {\n \"tier\": \"auto\",\n \"family\": \"gemini-3\",\n \"isPreview\": true,\n \"isVisible\": false\n },\n \"auto-gemini-2.5\": {\n \"tier\": \"auto\",\n \"family\": \"gemini-2.5\",\n \"isPreview\": false,\n \"isVisible\": false\n }\n}`", + "markdownDescription": "Registry of model metadata, including tier, family, and features.\n\n- Category: `Model`\n- Requires restart: `yes`\n- Default: `{\n \"gemini-3.1-flash-lite\": {\n \"tier\": \"flash-lite\",\n \"family\": \"gemini-3\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3.5-flash-lite\": {\n \"tier\": \"flash-lite\",\n \"family\": \"gemini-3\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3.1-pro-preview\": {\n \"tier\": \"pro\",\n \"family\": \"gemini-3\",\n \"isPreview\": true,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3.1-pro-preview-customtools\": {\n \"tier\": \"pro\",\n \"family\": \"gemini-3\",\n \"isPreview\": true,\n \"isVisible\": false,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3-pro-preview\": {\n \"tier\": \"pro\",\n \"family\": \"gemini-3\",\n \"isPreview\": true,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3-flash-preview\": {\n \"tier\": \"flash\",\n \"family\": \"gemini-3\",\n \"isPreview\": true,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3.5-flash\": {\n \"tier\": \"flash\",\n \"family\": \"gemini-3\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-3.8-flash\": {\n \"tier\": \"flash\",\n \"family\": \"gemini-3\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": true\n }\n },\n \"gemini-2.5-pro\": {\n \"tier\": \"pro\",\n \"family\": \"gemini-2.5\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": false\n }\n },\n \"gemini-2.5-flash\": {\n \"tier\": \"flash\",\n \"family\": \"gemini-2.5\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": false\n }\n },\n \"gemini-2.5-flash-lite\": {\n \"tier\": \"flash-lite\",\n \"family\": \"gemini-2.5\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": false\n }\n },\n \"gemma-4-31b-it\": {\n \"displayName\": \"gemma-4-31b-it\",\n \"tier\": \"custom\",\n \"family\": \"gemma-4\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": false\n }\n },\n \"gemma-4-26b-a4b-it\": {\n \"displayName\": \"gemma-4-26b-a4b-it\",\n \"tier\": \"custom\",\n \"family\": \"gemma-4\",\n \"isPreview\": false,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": false\n }\n },\n \"auto\": {\n \"displayName\": \"Auto\",\n \"tier\": \"auto\",\n \"isPreview\": true,\n \"isVisible\": true,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": false\n }\n },\n \"pro\": {\n \"tier\": \"pro\",\n \"isPreview\": false,\n \"isVisible\": false,\n \"features\": {\n \"thinking\": true,\n \"multimodalToolUse\": false\n }\n },\n \"flash\": {\n \"tier\": \"flash\",\n \"isPreview\": false,\n \"isVisible\": false,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": false\n }\n },\n \"flash-lite\": {\n \"tier\": \"flash-lite\",\n \"isPreview\": false,\n \"isVisible\": false,\n \"features\": {\n \"thinking\": false,\n \"multimodalToolUse\": false\n }\n },\n \"auto-gemini-3\": {\n \"tier\": \"auto\",\n \"family\": \"gemini-3\",\n \"isPreview\": true,\n \"isVisible\": false\n },\n \"auto-gemini-2.5\": {\n \"tier\": \"auto\",\n \"family\": \"gemini-2.5\",\n \"isPreview\": false,\n \"isVisible\": false\n }\n}`", "default": { "gemini-3.1-flash-lite": { "tier": "flash-lite", @@ -2015,6 +2090,16 @@ "multimodalToolUse": true } }, + "gemini-3.5-flash-lite": { + "tier": "flash-lite", + "family": "gemini-3", + "isPreview": false, + "isVisible": true, + "features": { + "thinking": false, + "multimodalToolUse": true + } + }, "gemini-3.1-pro-preview": { "tier": "pro", "family": "gemini-3", @@ -2065,6 +2150,16 @@ "multimodalToolUse": true } }, + "gemini-3.8-flash": { + "tier": "flash", + "family": "gemini-3", + "isPreview": false, + "isVisible": true, + "features": { + "thinking": false, + "multimodalToolUse": true + } + }, "gemini-2.5-pro": { "tier": "pro", "family": "gemini-2.5", @@ -2175,7 +2270,7 @@ "modelIdResolutions": { "title": "Model ID Resolutions", "description": "Rules for resolving requested model names to concrete model IDs based on context.", - "markdownDescription": "Rules for resolving requested model names to concrete model IDs based on context.\n\n- Category: `Model`\n- Requires restart: `yes`\n- Default: `{\n \"gemma-4-31b-it\": {\n \"default\": \"gemma-4-31b-it\"\n },\n \"gemma-4-26b-a4b-it\": {\n \"default\": \"gemma-4-26b-a4b-it\"\n },\n \"gemini-3.1-pro-preview\": {\n \"default\": \"gemini-3.1-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n }\n ]\n },\n \"gemini-3.1-pro-preview-customtools\": {\n \"default\": \"gemini-3.1-pro-preview-customtools\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n }\n ]\n },\n \"gemini-3-flash-preview\": {\n \"default\": \"gemini-3-flash-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false,\n \"useGemini3_5Flash\": true\n },\n \"target\": \"gemini-3.5-flash\"\n },\n {\n \"condition\": {\n \"hasAccessToPreview\": false,\n \"useGemini3_5Flash\": false\n },\n \"target\": \"gemini-2.5-flash\"\n }\n ]\n },\n \"gemini-3.5-flash\": {\n \"default\": \"gemini-3.5-flash\",\n \"contexts\": [\n {\n \"condition\": {\n \"useGemini3_5Flash\": false,\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-flash\"\n },\n {\n \"condition\": {\n \"useGemini3_5Flash\": false\n },\n \"target\": \"gemini-3-flash-preview\"\n }\n ]\n },\n \"gemini-2.5-flash\": {\n \"default\": \"gemini-2.5-flash\",\n \"contexts\": [\n {\n \"condition\": {\n \"useGemini3_5Flash\": true\n },\n \"target\": \"gemini-3.5-flash\"\n }\n ]\n },\n \"gemini-3-pro-preview\": {\n \"default\": \"gemini-3-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true,\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true\n },\n \"target\": \"gemini-3.1-pro-preview\"\n }\n ]\n },\n \"auto\": {\n \"default\": \"gemini-3-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true,\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true\n },\n \"target\": \"gemini-3.1-pro-preview\"\n }\n ]\n },\n \"pro\": {\n \"default\": \"gemini-3-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true,\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true\n },\n \"target\": \"gemini-3.1-pro-preview\"\n }\n ]\n },\n \"gemini-3.1-flash-lite\": {\n \"default\": \"gemini-3.1-flash-lite\"\n },\n \"flash\": {\n \"default\": \"gemini-3-flash-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"useGemini3_5Flash\": true\n },\n \"target\": \"gemini-3.5-flash\"\n },\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-flash\"\n }\n ]\n },\n \"flash-lite\": {\n \"default\": \"gemini-3.1-flash-lite\"\n },\n \"auto-gemini-3\": {\n \"default\": \"gemini-3-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true,\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true\n },\n \"target\": \"gemini-3.1-pro-preview\"\n }\n ]\n },\n \"auto-gemini-2.5\": {\n \"default\": \"gemini-2.5-pro\"\n }\n}`", + "markdownDescription": "Rules for resolving requested model names to concrete model IDs based on context.\n\n- Category: `Model`\n- Requires restart: `yes`\n- Default: `{\n \"gemma-4-31b-it\": {\n \"default\": \"gemma-4-31b-it\"\n },\n \"gemma-4-26b-a4b-it\": {\n \"default\": \"gemma-4-26b-a4b-it\"\n },\n \"gemini-3.1-pro-preview\": {\n \"default\": \"gemini-3.1-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n }\n ]\n },\n \"gemini-3.1-pro-preview-customtools\": {\n \"default\": \"gemini-3.1-pro-preview-customtools\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n }\n ]\n },\n \"gemini-3-flash-preview\": {\n \"default\": \"gemini-3-flash-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false,\n \"useLatestFlash\": true\n },\n \"target\": \"gemini-3.8-flash\"\n },\n {\n \"condition\": {\n \"hasAccessToPreview\": false,\n \"useLatestFlash\": false\n },\n \"target\": \"gemini-3.5-flash\"\n }\n ]\n },\n \"gemini-3.5-flash\": {\n \"default\": \"gemini-3.5-flash\",\n \"contexts\": [\n {\n \"condition\": {\n \"useLatestFlash\": true\n },\n \"target\": \"gemini-3.8-flash\"\n }\n ]\n },\n \"gemini-3.8-flash\": {\n \"default\": \"gemini-3.8-flash\",\n \"contexts\": [\n {\n \"condition\": {\n \"useLatestFlash\": false\n },\n \"target\": \"gemini-3.5-flash\"\n }\n ]\n },\n \"gemini-2.5-flash\": {\n \"default\": \"gemini-2.5-flash\",\n \"contexts\": [\n {\n \"condition\": {\n \"useLatestFlash\": true\n },\n \"target\": \"gemini-3.8-flash\"\n }\n ]\n },\n \"gemini-3-pro-preview\": {\n \"default\": \"gemini-3-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true,\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true\n },\n \"target\": \"gemini-3.1-pro-preview\"\n }\n ]\n },\n \"auto\": {\n \"default\": \"gemini-3-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true,\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true\n },\n \"target\": \"gemini-3.1-pro-preview\"\n }\n ]\n },\n \"pro\": {\n \"default\": \"gemini-3-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true,\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true\n },\n \"target\": \"gemini-3.1-pro-preview\"\n }\n ]\n },\n \"gemini-3.1-flash-lite\": {\n \"default\": \"gemini-3.1-flash-lite\",\n \"contexts\": [\n {\n \"condition\": {\n \"useLatestFlashLite\": true\n },\n \"target\": \"gemini-3.5-flash-lite\"\n }\n ]\n },\n \"gemini-3.5-flash-lite\": {\n \"default\": \"gemini-3.5-flash-lite\",\n \"contexts\": [\n {\n \"condition\": {\n \"useLatestFlashLite\": false\n },\n \"target\": \"gemini-3.1-flash-lite\"\n }\n ]\n },\n \"flash\": {\n \"default\": \"gemini-3-flash-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"useLatestFlash\": true\n },\n \"target\": \"gemini-3.8-flash\"\n },\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-3.5-flash\"\n }\n ]\n },\n \"flash-lite\": {\n \"default\": \"gemini-3.1-flash-lite\",\n \"contexts\": [\n {\n \"condition\": {\n \"useLatestFlashLite\": true\n },\n \"target\": \"gemini-3.5-flash-lite\"\n }\n ]\n },\n \"auto-gemini-3\": {\n \"default\": \"gemini-3-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true,\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true\n },\n \"target\": \"gemini-3.1-pro-preview\"\n }\n ]\n },\n \"auto-gemini-2.5\": {\n \"default\": \"gemini-2.5-pro\"\n }\n}`", "default": { "gemma-4-31b-it": { "default": "gemma-4-31b-it" @@ -2217,16 +2312,16 @@ { "condition": { "hasAccessToPreview": false, - "useGemini3_5Flash": true + "useLatestFlash": true }, - "target": "gemini-3.5-flash" + "target": "gemini-3.8-flash" }, { "condition": { "hasAccessToPreview": false, - "useGemini3_5Flash": false + "useLatestFlash": false }, - "target": "gemini-2.5-flash" + "target": "gemini-3.5-flash" } ] }, @@ -2235,16 +2330,20 @@ "contexts": [ { "condition": { - "useGemini3_5Flash": false, - "hasAccessToPreview": false + "useLatestFlash": true }, - "target": "gemini-2.5-flash" - }, + "target": "gemini-3.8-flash" + } + ] + }, + "gemini-3.8-flash": { + "default": "gemini-3.8-flash", + "contexts": [ { "condition": { - "useGemini3_5Flash": false + "useLatestFlash": false }, - "target": "gemini-3-flash-preview" + "target": "gemini-3.5-flash" } ] }, @@ -2253,9 +2352,9 @@ "contexts": [ { "condition": { - "useGemini3_5Flash": true + "useLatestFlash": true }, - "target": "gemini-3.5-flash" + "target": "gemini-3.8-flash" } ] }, @@ -2332,27 +2431,54 @@ ] }, "gemini-3.1-flash-lite": { - "default": "gemini-3.1-flash-lite" + "default": "gemini-3.1-flash-lite", + "contexts": [ + { + "condition": { + "useLatestFlashLite": true + }, + "target": "gemini-3.5-flash-lite" + } + ] + }, + "gemini-3.5-flash-lite": { + "default": "gemini-3.5-flash-lite", + "contexts": [ + { + "condition": { + "useLatestFlashLite": false + }, + "target": "gemini-3.1-flash-lite" + } + ] }, "flash": { "default": "gemini-3-flash-preview", "contexts": [ { "condition": { - "useGemini3_5Flash": true + "useLatestFlash": true }, - "target": "gemini-3.5-flash" + "target": "gemini-3.8-flash" }, { "condition": { "hasAccessToPreview": false }, - "target": "gemini-2.5-flash" + "target": "gemini-3.5-flash" } ] }, "flash-lite": { - "default": "gemini-3.1-flash-lite" + "default": "gemini-3.1-flash-lite", + "contexts": [ + { + "condition": { + "useLatestFlashLite": true + }, + "target": "gemini-3.5-flash-lite" + } + ] }, "auto-gemini-3": { "default": "gemini-3-pro-preview", @@ -2390,28 +2516,28 @@ "classifierIdResolutions": { "title": "Classifier ID Resolutions", "description": "Rules for resolving classifier tiers (flash, pro) to concrete model IDs.", - "markdownDescription": "Rules for resolving classifier tiers (flash, pro) to concrete model IDs.\n\n- Category: `Model`\n- Requires restart: `yes`\n- Default: `{\n \"flash\": {\n \"default\": \"gemini-3-flash-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"useGemini3_5Flash\": true\n },\n \"target\": \"gemini-3.5-flash\"\n },\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-flash\"\n },\n {\n \"condition\": {\n \"requestedModels\": [\n \"gemini-2.5-pro\",\n \"auto-gemini-2.5\"\n ]\n },\n \"target\": \"gemini-2.5-flash\"\n }\n ]\n },\n \"pro\": {\n \"default\": \"gemini-3-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"requestedModels\": [\n \"gemini-2.5-pro\",\n \"auto-gemini-2.5\"\n ]\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true,\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true\n },\n \"target\": \"gemini-3.1-pro-preview\"\n }\n ]\n }\n}`", + "markdownDescription": "Rules for resolving classifier tiers (flash, pro) to concrete model IDs.\n\n- Category: `Model`\n- Requires restart: `yes`\n- Default: `{\n \"flash\": {\n \"default\": \"gemini-3-flash-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"useLatestFlash\": true\n },\n \"target\": \"gemini-3.8-flash\"\n },\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-3.5-flash\"\n },\n {\n \"condition\": {\n \"requestedModels\": [\n \"gemini-2.5-pro\",\n \"auto-gemini-2.5\"\n ]\n },\n \"target\": \"gemini-3.5-flash\"\n }\n ]\n },\n \"pro\": {\n \"default\": \"gemini-3-pro-preview\",\n \"contexts\": [\n {\n \"condition\": {\n \"hasAccessToPreview\": false\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"requestedModels\": [\n \"gemini-2.5-pro\",\n \"auto-gemini-2.5\"\n ]\n },\n \"target\": \"gemini-2.5-pro\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true,\n \"useCustomTools\": true\n },\n \"target\": \"gemini-3.1-pro-preview-customtools\"\n },\n {\n \"condition\": {\n \"useGemini3_1\": true\n },\n \"target\": \"gemini-3.1-pro-preview\"\n }\n ]\n }\n}`", "default": { "flash": { "default": "gemini-3-flash-preview", "contexts": [ { "condition": { - "useGemini3_5Flash": true + "useLatestFlash": true }, - "target": "gemini-3.5-flash" + "target": "gemini-3.8-flash" }, { "condition": { "hasAccessToPreview": false }, - "target": "gemini-2.5-flash" + "target": "gemini-3.5-flash" }, { "condition": { "requestedModels": ["gemini-2.5-pro", "auto-gemini-2.5"] }, - "target": "gemini-2.5-flash" + "target": "gemini-3.5-flash" } ] }, @@ -2454,7 +2580,7 @@ "modelChains": { "title": "Model Chains", "description": "Availability policy chains defining fallback behavior for models.", - "markdownDescription": "Availability policy chains defining fallback behavior for models.\n\n- Category: `Model`\n- Requires restart: `yes`\n- Default: `{\n \"preview\": [\n {\n \"model\": \"gemini-3-pro-preview\",\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-3-flash-preview\",\n \"isLastResort\": true,\n \"maxAttempts\": 10,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n }\n ],\n \"auto-preview\": [\n {\n \"model\": \"gemini-3-pro-preview\",\n \"maxAttempts\": 3,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"silent\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"sticky_retry\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-3-flash-preview\",\n \"isLastResort\": true,\n \"maxAttempts\": 10,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n }\n ],\n \"default\": [\n {\n \"model\": \"gemini-2.5-pro\",\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"sticky_retry\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-2.5-flash\",\n \"isLastResort\": true,\n \"maxAttempts\": 10,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n }\n ],\n \"auto-default\": [\n {\n \"model\": \"gemini-2.5-pro\",\n \"maxAttempts\": 3,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"silent\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"sticky_retry\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-2.5-flash\",\n \"isLastResort\": true,\n \"maxAttempts\": 10,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n }\n ],\n \"lite\": [\n {\n \"model\": \"flash-lite\",\n \"actions\": {\n \"terminal\": \"silent\",\n \"transient\": \"silent\",\n \"not_found\": \"silent\",\n \"unknown\": \"silent\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-2.5-flash\",\n \"actions\": {\n \"terminal\": \"silent\",\n \"transient\": \"silent\",\n \"not_found\": \"silent\",\n \"unknown\": \"silent\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-2.5-pro\",\n \"isLastResort\": true,\n \"actions\": {\n \"terminal\": \"silent\",\n \"transient\": \"silent\",\n \"not_found\": \"silent\",\n \"unknown\": \"silent\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n }\n ]\n}`", + "markdownDescription": "Availability policy chains defining fallback behavior for models.\n\n- Category: `Model`\n- Requires restart: `yes`\n- Default: `{\n \"preview\": [\n {\n \"model\": \"gemini-3-pro-preview\",\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-3-flash-preview\",\n \"isLastResort\": true,\n \"maxAttempts\": 10,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n }\n ],\n \"auto-preview\": [\n {\n \"model\": \"gemini-3-pro-preview\",\n \"maxAttempts\": 3,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"silent\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"sticky_retry\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-3-flash-preview\",\n \"isLastResort\": true,\n \"maxAttempts\": 10,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n }\n ],\n \"default\": [\n {\n \"model\": \"gemini-2.5-pro\",\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"sticky_retry\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-3.5-flash\",\n \"isLastResort\": true,\n \"maxAttempts\": 10,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n }\n ],\n \"auto-default\": [\n {\n \"model\": \"gemini-2.5-pro\",\n \"maxAttempts\": 3,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"silent\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"sticky_retry\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-3.5-flash\",\n \"isLastResort\": true,\n \"maxAttempts\": 10,\n \"actions\": {\n \"terminal\": \"prompt\",\n \"transient\": \"prompt\",\n \"not_found\": \"prompt\",\n \"unknown\": \"prompt\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n }\n ],\n \"lite\": [\n {\n \"model\": \"gemini-3.1-flash-lite\",\n \"actions\": {\n \"terminal\": \"silent\",\n \"transient\": \"silent\",\n \"not_found\": \"silent\",\n \"unknown\": \"silent\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-3.5-flash\",\n \"actions\": {\n \"terminal\": \"silent\",\n \"transient\": \"silent\",\n \"not_found\": \"silent\",\n \"unknown\": \"silent\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n },\n {\n \"model\": \"gemini-2.5-pro\",\n \"isLastResort\": true,\n \"actions\": {\n \"terminal\": \"silent\",\n \"transient\": \"silent\",\n \"not_found\": \"silent\",\n \"unknown\": \"silent\"\n },\n \"stateTransitions\": {\n \"terminal\": \"terminal\",\n \"transient\": \"terminal\",\n \"not_found\": \"terminal\",\n \"unknown\": \"terminal\"\n }\n }\n ]\n}`", "default": { "preview": [ { @@ -2542,7 +2668,7 @@ } }, { - "model": "gemini-2.5-flash", + "model": "gemini-3.5-flash", "isLastResort": true, "maxAttempts": 10, "actions": { @@ -2577,7 +2703,7 @@ } }, { - "model": "gemini-2.5-flash", + "model": "gemini-3.5-flash", "isLastResort": true, "maxAttempts": 10, "actions": { @@ -2596,7 +2722,7 @@ ], "lite": [ { - "model": "flash-lite", + "model": "gemini-3.1-flash-lite", "actions": { "terminal": "silent", "transient": "silent", @@ -2611,7 +2737,7 @@ } }, { - "model": "gemini-2.5-flash", + "model": "gemini-3.5-flash", "actions": { "terminal": "silent", "transient": "silent", @@ -4525,8 +4651,21 @@ "useGemini3_1": { "type": "boolean" }, + "useLatestFlash": { + "type": "boolean", + "description": "Whether the latest GA Flash model (Gemini 3.8 Flash) is launched and active." + }, + "useLatestFlashLite": { + "type": "boolean", + "description": "Whether the latest GA Flash Lite model (Gemini 3.5 Flash Lite) is launched and active." + }, + "useGemini3_5Flash": { + "type": "boolean", + "description": "Deprecated alias for useLatestFlash." + }, "useGemini3_1FlashLite": { - "type": "boolean" + "type": "boolean", + "description": "Deprecated alias for useLatestFlashLite." }, "useCustomTools": { "type": "boolean"