From e781537294b90df25c67d6f38a55a82faa2fe61d Mon Sep 17 00:00:00 2001 From: Akhilesh Kumar Date: Wed, 15 Apr 2026 01:51:35 +0000 Subject: [PATCH] feat(config): Redirect Gemini Pro and Flash requests to Gemma 4 Introduces a new `model.gemma4Variant` setting that allows users to optionally redirect all requests destined for `gemini-pro` and `gemini-flash` (and their related aliases) to the selected Gemma 4 variant (`gemma-4-26b-a4b-it` or `gemma-4-31b-it`). The router model (`flash-lite`) remains unaffected. --- packages/cli/src/config/config.ts | 1 + packages/cli/src/config/settingsSchema.ts | 17 ++ packages/core/src/config/config.ts | 10 ++ .../core/src/config/defaultModelConfigs.ts | 158 ++++++++++++++++++ packages/core/src/config/models.ts | 19 +++ .../core/src/services/modelConfigService.ts | 4 + .../resolved-aliases-retry.golden.json | 22 +++ .../test-data/resolved-aliases.golden.json | 22 +++ 8 files changed, 253 insertions(+) diff --git a/packages/cli/src/config/config.ts b/packages/cli/src/config/config.ts index 4e7e1db6f2..ba7035d49f 100755 --- a/packages/cli/src/config/config.ts +++ b/packages/cli/src/config/config.ts @@ -913,6 +913,7 @@ export async function loadCliConfig( debugMode, question, worktreeSettings, + gemma4Variant: settings.model?.gemma4Variant, coreTools: settings.tools?.core || undefined, allowedTools: allowedTools.length > 0 ? allowedTools : undefined, diff --git a/packages/cli/src/config/settingsSchema.ts b/packages/cli/src/config/settingsSchema.ts index fcfd604e3a..58a13b06d1 100644 --- a/packages/cli/src/config/settingsSchema.ts +++ b/packages/cli/src/config/settingsSchema.ts @@ -1047,6 +1047,23 @@ const SETTINGS_SCHEMA = { description: 'Skip the next speaker check.', showInDialog: true, }, + gemma4Variant: { + type: 'enum', + label: 'Gemma 4 Variant', + category: 'Model', + requiresRestart: true, + default: undefined as + | 'gemma-4-26b-a4b-it' + | 'gemma-4-31b-it' + | undefined, + description: + 'Select which Gemma 4 model variant to use when routing Gemini Pro and Flash requests.', + showInDialog: true, + options: [ + { value: 'gemma-4-26b-a4b-it', label: 'Gemma 4 26B A4B IT' }, + { value: 'gemma-4-31b-it', label: 'Gemma 4 31B IT' }, + ], + }, }, }, diff --git a/packages/core/src/config/config.ts b/packages/core/src/config/config.ts index c19cc257c3..ae86c8ce6c 100644 --- a/packages/core/src/config/config.ts +++ b/packages/core/src/config/config.ts @@ -726,6 +726,7 @@ export interface ConfigParameters { billing?: { overageStrategy?: OverageStrategy; }; + gemma4Variant?: 'gemma-4-26b-a4b-it' | 'gemma-4-31b-it'; } export class Config implements McpContext, AgentLoopContext { @@ -759,6 +760,10 @@ export class Config implements McpContext, AgentLoopContext { private readonly debugMode: boolean; private readonly question: string | undefined; private readonly worktreeSettings: WorktreeSettings | undefined; + private readonly gemma4Variant: + | 'gemma-4-26b-a4b-it' + | 'gemma-4-31b-it' + | undefined; readonly enableConseca: boolean; private readonly coreTools: string[] | undefined; @@ -1027,6 +1032,7 @@ export class Config implements McpContext, AgentLoopContext { this.debugMode = params.debugMode; this.question = params.question; this.worktreeSettings = params.worktreeSettings; + this.gemma4Variant = params.gemma4Variant; this.coreTools = params.coreTools; this.mainAgentTools = params.mainAgentTools; @@ -1755,6 +1761,10 @@ export class Config implements McpContext, AgentLoopContext { return this.worktreeSettings; } + getGemma4Variant(): 'gemma-4-26b-a4b-it' | 'gemma-4-31b-it' | undefined { + return this.gemma4Variant; + } + getClientName(): string | undefined { return this.clientName; } diff --git a/packages/core/src/config/defaultModelConfigs.ts b/packages/core/src/config/defaultModelConfigs.ts index 84c2478a5f..1849b1e206 100644 --- a/packages/core/src/config/defaultModelConfigs.ts +++ b/packages/core/src/config/defaultModelConfigs.ts @@ -89,6 +89,18 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { model: 'gemini-2.5-flash-lite', }, }, + 'gemma-4-26b-a4b-it': { + extends: 'chat-base', + modelConfig: { + model: 'gemma-4-26b-a4b-it', + }, + }, + 'gemma-4-31b-it': { + extends: 'chat-base', + modelConfig: { + model: 'gemma-4-31b-it', + }, + }, // Bases for the internal model configs. 'gemini-2.5-flash-base': { extends: 'base', @@ -317,6 +329,20 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { isVisible: true, features: { thinking: false, multimodalToolUse: false }, }, + 'gemma-4-26b-a4b-it': { + tier: 'pro', + family: 'gemma-4', + isPreview: true, + isVisible: true, + features: { thinking: false, multimodalToolUse: false }, + }, + 'gemma-4-31b-it': { + tier: 'pro', + family: 'gemma-4', + isPreview: true, + isVisible: true, + features: { thinking: false, multimodalToolUse: false }, + }, // Aliases auto: { tier: 'auto', @@ -362,9 +388,43 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { }, }, modelIdResolutions: { + 'gemini-2.5-flash': { + default: 'gemini-2.5-flash', + contexts: [ + { + condition: { gemma4Variant: 'gemma-4-26b-a4b-it' }, + target: 'gemma-4-26b-a4b-it', + }, + { + condition: { gemma4Variant: 'gemma-4-31b-it' }, + target: 'gemma-4-31b-it', + }, + ], + }, + 'gemini-2.5-pro': { + default: 'gemini-2.5-pro', + contexts: [ + { + condition: { gemma4Variant: 'gemma-4-26b-a4b-it' }, + target: 'gemma-4-26b-a4b-it', + }, + { + condition: { gemma4Variant: 'gemma-4-31b-it' }, + target: 'gemma-4-31b-it', + }, + ], + }, 'gemini-3.1-pro-preview': { default: 'gemini-3.1-pro-preview', contexts: [ + { + condition: { gemma4Variant: 'gemma-4-26b-a4b-it' }, + target: 'gemma-4-26b-a4b-it', + }, + { + condition: { gemma4Variant: 'gemma-4-31b-it' }, + target: 'gemma-4-31b-it', + }, { condition: { hasAccessToPreview: false }, target: 'gemini-2.5-pro' }, { condition: { useCustomTools: true }, @@ -375,12 +435,28 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { 'gemini-3.1-pro-preview-customtools': { default: 'gemini-3.1-pro-preview-customtools', contexts: [ + { + condition: { gemma4Variant: 'gemma-4-26b-a4b-it' }, + target: 'gemma-4-26b-a4b-it', + }, + { + condition: { gemma4Variant: 'gemma-4-31b-it' }, + target: 'gemma-4-31b-it', + }, { condition: { hasAccessToPreview: false }, target: 'gemini-2.5-pro' }, ], }, 'gemini-3-flash-preview': { default: 'gemini-3-flash-preview', contexts: [ + { + condition: { gemma4Variant: 'gemma-4-26b-a4b-it' }, + target: 'gemma-4-26b-a4b-it', + }, + { + condition: { gemma4Variant: 'gemma-4-31b-it' }, + target: 'gemma-4-31b-it', + }, { condition: { hasAccessToPreview: false }, target: 'gemini-2.5-flash', @@ -390,6 +466,14 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { 'gemini-3-pro-preview': { default: 'gemini-3-pro-preview', contexts: [ + { + condition: { gemma4Variant: 'gemma-4-26b-a4b-it' }, + target: 'gemma-4-26b-a4b-it', + }, + { + condition: { gemma4Variant: 'gemma-4-31b-it' }, + target: 'gemma-4-31b-it', + }, { condition: { hasAccessToPreview: false }, target: 'gemini-2.5-pro' }, { condition: { useGemini3_1: true, useCustomTools: true }, @@ -404,6 +488,14 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { 'auto-gemini-3': { default: 'gemini-3-pro-preview', contexts: [ + { + condition: { gemma4Variant: 'gemma-4-26b-a4b-it' }, + target: 'gemma-4-26b-a4b-it', + }, + { + condition: { gemma4Variant: 'gemma-4-31b-it' }, + target: 'gemma-4-31b-it', + }, { condition: { hasAccessToPreview: false }, target: 'gemini-2.5-pro' }, { condition: { useGemini3_1: true, useCustomTools: true }, @@ -418,6 +510,14 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { auto: { default: 'gemini-3-pro-preview', contexts: [ + { + condition: { gemma4Variant: 'gemma-4-26b-a4b-it' }, + target: 'gemma-4-26b-a4b-it', + }, + { + condition: { gemma4Variant: 'gemma-4-31b-it' }, + target: 'gemma-4-31b-it', + }, { condition: { hasAccessToPreview: false }, target: 'gemini-2.5-pro' }, { condition: { useGemini3_1: true, useCustomTools: true }, @@ -432,6 +532,14 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { pro: { default: 'gemini-3-pro-preview', contexts: [ + { + condition: { gemma4Variant: 'gemma-4-26b-a4b-it' }, + target: 'gemma-4-26b-a4b-it', + }, + { + condition: { gemma4Variant: 'gemma-4-31b-it' }, + target: 'gemma-4-31b-it', + }, { condition: { hasAccessToPreview: false }, target: 'gemini-2.5-pro' }, { condition: { useGemini3_1: true, useCustomTools: true }, @@ -445,6 +553,16 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { }, 'auto-gemini-2.5': { default: 'gemini-2.5-pro', + contexts: [ + { + condition: { gemma4Variant: 'gemma-4-26b-a4b-it' }, + target: 'gemma-4-26b-a4b-it', + }, + { + condition: { gemma4Variant: 'gemma-4-31b-it' }, + target: 'gemma-4-31b-it', + }, + ], }, 'gemini-3.1-flash-lite-preview': { default: 'gemini-3.1-flash-lite-preview', @@ -458,6 +576,14 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { flash: { default: 'gemini-3-flash-preview', contexts: [ + { + condition: { gemma4Variant: 'gemma-4-26b-a4b-it' }, + target: 'gemma-4-26b-a4b-it', + }, + { + condition: { gemma4Variant: 'gemma-4-31b-it' }, + target: 'gemma-4-31b-it', + }, { condition: { hasAccessToPreview: false }, target: 'gemini-2.5-flash', @@ -478,6 +604,22 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { flash: { default: 'gemini-3-flash-preview', contexts: [ + { + condition: { gemma4Variant: 'gemma-4-26b-a4b-it' }, + target: 'gemma-4-26b-a4b-it', + }, + { + condition: { gemma4Variant: 'gemma-4-31b-it' }, + target: 'gemma-4-31b-it', + }, + { + condition: { gemma4Variant: 'gemma-4-26b-a4b-it' }, + target: 'gemma-4-26b-a4b-it', + }, + { + condition: { gemma4Variant: 'gemma-4-31b-it' }, + target: 'gemma-4-31b-it', + }, { condition: { requestedModels: ['auto-gemini-2.5', 'gemini-2.5-pro'] }, target: 'gemini-2.5-flash', @@ -493,6 +635,22 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = { pro: { default: 'gemini-3-pro-preview', contexts: [ + { + condition: { gemma4Variant: 'gemma-4-26b-a4b-it' }, + target: 'gemma-4-26b-a4b-it', + }, + { + condition: { gemma4Variant: 'gemma-4-31b-it' }, + target: 'gemma-4-31b-it', + }, + { + condition: { gemma4Variant: 'gemma-4-26b-a4b-it' }, + target: 'gemma-4-26b-a4b-it', + }, + { + condition: { gemma4Variant: 'gemma-4-31b-it' }, + target: 'gemma-4-31b-it', + }, { condition: { requestedModels: ['auto-gemini-2.5', 'gemini-2.5-pro'] }, target: 'gemini-2.5-pro', diff --git a/packages/core/src/config/models.ts b/packages/core/src/config/models.ts index b8420dd259..2c6b98aae2 100644 --- a/packages/core/src/config/models.ts +++ b/packages/core/src/config/models.ts @@ -10,6 +10,7 @@ export interface ModelResolutionContext { useCustomTools?: boolean; hasAccessToPreview?: boolean; requestedModel?: string; + gemma4Variant?: 'gemma-4-26b-a4b-it' | 'gemma-4-31b-it'; } /** @@ -48,6 +49,7 @@ export interface IModelConfigService { export interface ModelCapabilityContext { readonly modelConfigService: IModelConfigService; getExperimentalDynamicModelConfiguration(): boolean; + getGemma4Variant?: () => 'gemma-4-26b-a4b-it' | 'gemma-4-31b-it' | undefined; } export const PREVIEW_GEMINI_MODEL = 'gemini-3-pro-preview'; @@ -60,6 +62,8 @@ export const PREVIEW_GEMINI_3_1_FLASH_LITE_MODEL = export const DEFAULT_GEMINI_MODEL = 'gemini-2.5-pro'; export const DEFAULT_GEMINI_FLASH_MODEL = 'gemini-2.5-flash'; export const DEFAULT_GEMINI_FLASH_LITE_MODEL = 'gemini-2.5-flash-lite'; +export const GEMMA_4_26B_IT = 'gemma-4-26b-a4b-it'; +export const GEMMA_4_31B_IT = 'gemma-4-31b-it'; export const VALID_GEMINI_MODELS = new Set([ PREVIEW_GEMINI_MODEL, @@ -70,6 +74,8 @@ export const VALID_GEMINI_MODELS = new Set([ DEFAULT_GEMINI_MODEL, DEFAULT_GEMINI_FLASH_MODEL, DEFAULT_GEMINI_FLASH_LITE_MODEL, + GEMMA_4_26B_IT, + GEMMA_4_31B_IT, ]); export const PREVIEW_GEMINI_MODEL_AUTO = 'auto-gemini-3'; @@ -109,6 +115,7 @@ export function resolveModel( useGemini3_1FlashLite, useCustomTools: useCustomToolModel, hasAccessToPreview, + gemma4Variant: config.getGemma4Variant?.(), }); if (!hasAccessToPreview && isPreviewModel(resolved, config)) { @@ -160,6 +167,17 @@ export function resolveModel( } } + const variant = config?.getGemma4Variant?.(); + if ( + variant && + (resolved === PREVIEW_GEMINI_MODEL || + resolved === DEFAULT_GEMINI_MODEL || + resolved === PREVIEW_GEMINI_FLASH_MODEL || + resolved === DEFAULT_GEMINI_FLASH_MODEL) + ) { + return variant; + } + if (!hasAccessToPreview && isPreviewModel(resolved)) { // Downgrade to stable models if user lacks preview access. switch (resolved) { @@ -214,6 +232,7 @@ export function resolveClassifierModel( useGemini3_1FlashLite, useCustomTools: useCustomToolModel, hasAccessToPreview, + gemma4Variant: config.getGemma4Variant?.(), }, ); } diff --git a/packages/core/src/services/modelConfigService.ts b/packages/core/src/services/modelConfigService.ts index a6d59365d7..8e7e5918f0 100644 --- a/packages/core/src/services/modelConfigService.ts +++ b/packages/core/src/services/modelConfigService.ts @@ -101,6 +101,7 @@ export interface ResolutionContext { hasAccessToPreview?: boolean; hasAccessToProModel?: boolean; requestedModel?: string; + gemma4Variant?: 'gemma-4-26b-a4b-it' | 'gemma-4-31b-it'; } /** The requirements defined in the registry. */ @@ -109,6 +110,7 @@ export interface ResolutionCondition { useGemini3_1FlashLite?: boolean; useCustomTools?: boolean; hasAccessToPreview?: boolean; + gemma4Variant?: 'gemma-4-26b-a4b-it' | 'gemma-4-31b-it'; /** Matches if the current model is in this list. */ requestedModels?: string[]; } @@ -252,6 +254,8 @@ export class ModelConfigService { return value === context.useCustomTools; case 'hasAccessToPreview': return value === context.hasAccessToPreview; + case 'gemma4Variant': + return value === context.gemma4Variant; 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 33e9ce684b..16b7c67adf 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 @@ -97,6 +97,28 @@ "topK": 64 } }, + "gemma-4-26b-a4b-it": { + "model": "gemma-4-26b-a4b-it", + "generateContentConfig": { + "temperature": 1, + "topP": 0.95, + "thinkingConfig": { + "includeThoughts": true + }, + "topK": 64 + } + }, + "gemma-4-31b-it": { + "model": "gemma-4-31b-it", + "generateContentConfig": { + "temperature": 1, + "topP": 0.95, + "thinkingConfig": { + "includeThoughts": true + }, + "topK": 64 + } + }, "gemini-2.5-flash-base": { "model": "gemini-2.5-flash", "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 33e9ce684b..16b7c67adf 100644 --- a/packages/core/src/services/test-data/resolved-aliases.golden.json +++ b/packages/core/src/services/test-data/resolved-aliases.golden.json @@ -97,6 +97,28 @@ "topK": 64 } }, + "gemma-4-26b-a4b-it": { + "model": "gemma-4-26b-a4b-it", + "generateContentConfig": { + "temperature": 1, + "topP": 0.95, + "thinkingConfig": { + "includeThoughts": true + }, + "topK": 64 + } + }, + "gemma-4-31b-it": { + "model": "gemma-4-31b-it", + "generateContentConfig": { + "temperature": 1, + "topP": 0.95, + "thinkingConfig": { + "includeThoughts": true + }, + "topK": 64 + } + }, "gemini-2.5-flash-base": { "model": "gemini-2.5-flash", "generateContentConfig": {