From ed0b0fae497ee85a3009bb4a807ebb5369f371bd Mon Sep 17 00:00:00 2001 From: Sehoon Shon Date: Tue, 20 Jan 2026 16:03:34 -0500 Subject: [PATCH] fix(core): resolve auto model in default strategy (#17116) --- packages/core/src/config/models.ts | 1 + .../strategies/defaultStrategy.test.ts | 103 +++++++++++++++++- .../src/routing/strategies/defaultStrategy.ts | 12 +- scripts/lint.js | 1 + 4 files changed, 109 insertions(+), 8 deletions(-) diff --git a/packages/core/src/config/models.ts b/packages/core/src/config/models.ts index 4475a5db97..519f49c98e 100644 --- a/packages/core/src/config/models.ts +++ b/packages/core/src/config/models.ts @@ -51,6 +51,7 @@ export function resolveModel( case DEFAULT_GEMINI_MODEL_AUTO: { return DEFAULT_GEMINI_MODEL; } + case GEMINI_MODEL_ALIAS_AUTO: case GEMINI_MODEL_ALIAS_PRO: { return previewFeaturesEnabled ? PREVIEW_GEMINI_MODEL diff --git a/packages/core/src/routing/strategies/defaultStrategy.test.ts b/packages/core/src/routing/strategies/defaultStrategy.test.ts index 1c739545a4..2f1ce539e2 100644 --- a/packages/core/src/routing/strategies/defaultStrategy.test.ts +++ b/packages/core/src/routing/strategies/defaultStrategy.test.ts @@ -4,18 +4,28 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, vi } from 'vitest'; import { DefaultStrategy } from './defaultStrategy.js'; import type { RoutingContext } from '../routingStrategy.js'; import type { BaseLlmClient } from '../../core/baseLlmClient.js'; -import { DEFAULT_GEMINI_MODEL } from '../../config/models.js'; +import { + DEFAULT_GEMINI_MODEL, + PREVIEW_GEMINI_MODEL, + PREVIEW_GEMINI_MODEL_AUTO, + DEFAULT_GEMINI_MODEL_AUTO, + GEMINI_MODEL_ALIAS_AUTO, + PREVIEW_GEMINI_FLASH_MODEL, +} from '../../config/models.js'; import type { Config } from '../../config/config.js'; describe('DefaultStrategy', () => { - it('should always route to the default Gemini model', async () => { + it('should route to the default model when requested model is default auto', async () => { const strategy = new DefaultStrategy(); const mockContext = {} as RoutingContext; - const mockConfig = {} as Config; + const mockConfig = { + getModel: vi.fn().mockReturnValue(DEFAULT_GEMINI_MODEL_AUTO), + getPreviewFeatures: vi.fn().mockReturnValue(false), + } as unknown as Config; const mockClient = {} as BaseLlmClient; const decision = await strategy.route(mockContext, mockConfig, mockClient); @@ -29,4 +39,89 @@ describe('DefaultStrategy', () => { }, }); }); + + it('should route to the preview model when requested model is preview auto', async () => { + const strategy = new DefaultStrategy(); + const mockContext = {} as RoutingContext; + const mockConfig = { + getModel: vi.fn().mockReturnValue(PREVIEW_GEMINI_MODEL_AUTO), + getPreviewFeatures: vi.fn().mockReturnValue(false), + } as unknown as Config; + const mockClient = {} as BaseLlmClient; + + const decision = await strategy.route(mockContext, mockConfig, mockClient); + + expect(decision).toEqual({ + model: PREVIEW_GEMINI_MODEL, + metadata: { + source: 'default', + latencyMs: 0, + reasoning: `Routing to default model: ${PREVIEW_GEMINI_MODEL}`, + }, + }); + }); + + it('should route to the preview model when requested model is auto and previewfeature is on', async () => { + const strategy = new DefaultStrategy(); + const mockContext = {} as RoutingContext; + const mockConfig = { + getModel: vi.fn().mockReturnValue(GEMINI_MODEL_ALIAS_AUTO), + getPreviewFeatures: vi.fn().mockReturnValue(true), + } as unknown as Config; + const mockClient = {} as BaseLlmClient; + + const decision = await strategy.route(mockContext, mockConfig, mockClient); + + expect(decision).toEqual({ + model: PREVIEW_GEMINI_MODEL, + metadata: { + source: 'default', + latencyMs: 0, + reasoning: `Routing to default model: ${PREVIEW_GEMINI_MODEL}`, + }, + }); + }); + + it('should route to the default model when requested model is auto and previewfeature is off', async () => { + const strategy = new DefaultStrategy(); + const mockContext = {} as RoutingContext; + const mockConfig = { + getModel: vi.fn().mockReturnValue(GEMINI_MODEL_ALIAS_AUTO), + getPreviewFeatures: vi.fn().mockReturnValue(false), + } as unknown as Config; + const mockClient = {} as BaseLlmClient; + + const decision = await strategy.route(mockContext, mockConfig, mockClient); + + expect(decision).toEqual({ + model: DEFAULT_GEMINI_MODEL, + metadata: { + source: 'default', + latencyMs: 0, + reasoning: `Routing to default model: ${DEFAULT_GEMINI_MODEL}`, + }, + }); + }); + + // this should not happen, adding the test just in case it happens. + it('should route to the same model if it is not an auto mode', async () => { + const strategy = new DefaultStrategy(); + const mockContext = {} as RoutingContext; + const mockConfig = { + getModel: vi.fn().mockReturnValue(PREVIEW_GEMINI_FLASH_MODEL), + getPreviewFeatures: vi.fn().mockReturnValue(false), + } as unknown as Config; + const mockClient = {} as BaseLlmClient; + + const decision = await strategy.route(mockContext, mockConfig, mockClient); + + expect(decision).toEqual({ + model: PREVIEW_GEMINI_FLASH_MODEL, + metadata: { + source: 'default', + latencyMs: 0, + reasoning: `Routing to default model: ${PREVIEW_GEMINI_FLASH_MODEL}`, + }, + }); + }); }); diff --git a/packages/core/src/routing/strategies/defaultStrategy.ts b/packages/core/src/routing/strategies/defaultStrategy.ts index dba7949f9e..5552ad1057 100644 --- a/packages/core/src/routing/strategies/defaultStrategy.ts +++ b/packages/core/src/routing/strategies/defaultStrategy.ts @@ -11,22 +11,26 @@ import type { RoutingDecision, TerminalStrategy, } from '../routingStrategy.js'; -import { DEFAULT_GEMINI_MODEL } from '../../config/models.js'; +import { resolveModel } from '../../config/models.js'; export class DefaultStrategy implements TerminalStrategy { readonly name = 'default'; async route( _context: RoutingContext, - _config: Config, + config: Config, _baseLlmClient: BaseLlmClient, ): Promise { + const defaultModel = resolveModel( + config.getModel(), + config.getPreviewFeatures(), + ); return { - model: DEFAULT_GEMINI_MODEL, + model: defaultModel, metadata: { source: this.name, latencyMs: 0, - reasoning: `Routing to default model: ${DEFAULT_GEMINI_MODEL}`, + reasoning: `Routing to default model: ${defaultModel}`, }, }; } diff --git a/scripts/lint.js b/scripts/lint.js index c0c5689a01..08ad893242 100644 --- a/scripts/lint.js +++ b/scripts/lint.js @@ -197,6 +197,7 @@ export function runSensitiveKeywordLinter() { console.log('\nRunning sensitive keyword linter...'); const SENSITIVE_PATTERN = /gemini-\d+(\.\d+)?/g; const ALLOWED_KEYWORDS = new Set([ + 'gemini-3', 'gemini-3.0', 'gemini-2.5', 'gemini-2.0',