# feat(routing): Introduce useModelRouter feature flag (#8366)

This commit is contained in:
Abhi
2025-09-12 15:57:07 -04:00
committed by GitHub
parent bc7c7fe466
commit c15774ce68
14 changed files with 267 additions and 48 deletions

View File

@@ -7,7 +7,13 @@
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import * as os from 'node:os';
import * as path from 'node:path';
import { ShellTool, EditTool, WriteFileTool } from '@google/gemini-cli-core';
import {
ShellTool,
EditTool,
WriteFileTool,
DEFAULT_GEMINI_MODEL,
DEFAULT_GEMINI_MODEL_AUTO,
} from '@google/gemini-cli-core';
import { loadCliConfig, parseArguments, type CliArgs } from './config.js';
import type { Settings } from './settings.js';
import type { Extension } from './extension.js';
@@ -1484,6 +1490,97 @@ describe('loadCliConfig model selection', () => {
});
});
describe('loadCliConfig model selection with model router', () => {
it('should use auto model when useModelRouter is true and no model is provided', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(
{
experimental: {
useModelRouter: true,
},
},
[],
'test-session',
argv,
);
expect(config.getModel()).toBe(DEFAULT_GEMINI_MODEL_AUTO);
});
it('should use default model when useModelRouter is false and no model is provided', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(
{
experimental: {
useModelRouter: false,
},
},
[],
'test-session',
argv,
);
expect(config.getModel()).toBe(DEFAULT_GEMINI_MODEL);
});
it('should prioritize argv over useModelRouter', async () => {
process.argv = ['node', 'script.js', '--model', 'gemini-from-argv'];
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(
{
experimental: {
useModelRouter: true,
},
},
[],
'test-session',
argv,
);
expect(config.getModel()).toBe('gemini-from-argv');
});
it('should prioritize settings over useModelRouter', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(
{
experimental: {
useModelRouter: true,
},
model: {
name: 'gemini-from-settings',
},
},
[],
'test-session',
argv,
);
expect(config.getModel()).toBe('gemini-from-settings');
});
it('should prioritize environment variable over useModelRouter', async () => {
process.argv = ['node', 'script.js'];
vi.stubEnv('GEMINI_MODEL', 'gemini-from-env');
const argv = await parseArguments({} as Settings);
const config = await loadCliConfig(
{
experimental: {
useModelRouter: true,
},
},
[],
'test-session',
argv,
);
expect(config.getModel()).toBe('gemini-from-env');
});
});
describe('loadCliConfig folderTrust', () => {
const originalArgv = process.argv;
@@ -1668,6 +1765,32 @@ describe('loadCliConfig useRipgrep', () => {
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getUseRipgrep()).toBe(true);
});
describe('loadCliConfig useModelRouter', () => {
it('should be false by default when useModelRouter is not set in settings', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments({} as Settings);
const settings: Settings = {};
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getUseModelRouter()).toBe(false);
});
it('should be true when useModelRouter is set to true in settings', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments({} as Settings);
const settings: Settings = { experimental: { useModelRouter: true } };
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getUseModelRouter()).toBe(true);
});
it('should be false when useModelRouter is explicitly set to false in settings', async () => {
process.argv = ['node', 'script.js'];
const argv = await parseArguments({} as Settings);
const settings: Settings = { experimental: { useModelRouter: false } };
const config = await loadCliConfig(settings, [], 'test-session', argv);
expect(config.getUseModelRouter()).toBe(false);
});
});
});
describe('loadCliConfig tool exclusions', () => {

View File

@@ -25,6 +25,7 @@ import {
getCurrentGeminiMdFilename,
ApprovalMode,
DEFAULT_GEMINI_MODEL,
DEFAULT_GEMINI_MODEL_AUTO,
DEFAULT_GEMINI_EMBEDDING_MODEL,
DEFAULT_MEMORY_FILE_FILTERING_OPTIONS,
FileDiscoveryService,
@@ -98,7 +99,6 @@ export async function parseArguments(settings: Settings): Promise<CliArgs> {
alias: 'm',
type: 'string',
description: `Model`,
default: process.env['GEMINI_MODEL'],
})
.option('prompt', {
alias: 'p',
@@ -550,6 +550,16 @@ export async function loadCliConfig(
);
}
const useModelRouter = settings.experimental?.useModelRouter ?? false;
const defaultModel = useModelRouter
? DEFAULT_GEMINI_MODEL_AUTO
: DEFAULT_GEMINI_MODEL;
const resolvedModel: string =
argv.model ||
process.env['GEMINI_MODEL'] ||
settings.model?.name ||
defaultModel;
const sandboxConfig = await loadSandboxConfig(settings, argv);
const screenReader =
argv.screenReader !== undefined
@@ -611,7 +621,7 @@ export async function loadCliConfig(
cwd,
fileDiscoveryService: fileService,
bugCommand: settings.advanced?.bugCommand,
model: argv.model || settings.model?.name || DEFAULT_GEMINI_MODEL,
model: resolvedModel,
extensionContextFilePaths,
maxSessionTurns: settings.model?.maxSessionTurns ?? -1,
experimentalZedIntegration: argv.experimentalAcp || false,
@@ -637,6 +647,7 @@ export async function loadCliConfig(
output: {
format: (argv.outputFormat ?? settings.output?.format) as OutputFormat,
},
useModelRouter,
});
}

View File

@@ -315,5 +315,20 @@ describe('SettingsSchema', () => {
.description,
).toBe('Enable debug logging of keystrokes to the console.');
});
it('should have useModelRouter setting in schema', () => {
expect(
getSettingsSchema().experimental.properties.useModelRouter,
).toBeDefined();
expect(
getSettingsSchema().experimental.properties.useModelRouter.type,
).toBe('boolean');
expect(
getSettingsSchema().experimental.properties.useModelRouter.category,
).toBe('Experimental');
expect(
getSettingsSchema().experimental.properties.useModelRouter.default,
).toBe(false);
});
});
});

View File

@@ -962,6 +962,16 @@ const SETTINGS_SCHEMA = {
description: 'Enable extension management features.',
showInDialog: false,
},
useModelRouter: {
type: 'boolean',
label: 'Use Model Router',
category: 'Experimental',
requiresRestart: true,
default: false,
description:
'Enable model routing to route requests to the best model based on complexity.',
showInDialog: false,
},
},
},