mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-22 02:54:31 -07:00
[Gemma x Gemini CLI] Add an Experimental Gemma Router that uses a LiteRT-LM shim into the Composite Model Classifier Strategy (#17231)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Co-authored-by: Allen Hutchison <adh@google.com>
This commit is contained in:
@@ -2765,6 +2765,66 @@ describe('loadCliConfig approval mode', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('loadCliConfig gemmaModelRouter', () => {
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks();
|
||||
vi.mocked(os.homedir).mockReturnValue('/mock/home/user');
|
||||
vi.stubEnv('GEMINI_API_KEY', 'test-api-key');
|
||||
vi.spyOn(ExtensionManager.prototype, 'getExtensions').mockReturnValue([]);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('should have gemmaModelRouter disabled by default', async () => {
|
||||
process.argv = ['node', 'script.js'];
|
||||
const argv = await parseArguments(createTestMergedSettings());
|
||||
const settings = createTestMergedSettings();
|
||||
const config = await loadCliConfig(settings, 'test-session', argv);
|
||||
expect(config.getGemmaModelRouterEnabled()).toBe(false);
|
||||
});
|
||||
|
||||
it('should load gemmaModelRouter settings from merged settings', async () => {
|
||||
process.argv = ['node', 'script.js'];
|
||||
const argv = await parseArguments(createTestMergedSettings());
|
||||
const settings = createTestMergedSettings({
|
||||
experimental: {
|
||||
gemmaModelRouter: {
|
||||
enabled: true,
|
||||
classifier: {
|
||||
host: 'http://custom:1234',
|
||||
model: 'custom-gemma',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const config = await loadCliConfig(settings, 'test-session', argv);
|
||||
expect(config.getGemmaModelRouterEnabled()).toBe(true);
|
||||
const gemmaSettings = config.getGemmaModelRouterSettings();
|
||||
expect(gemmaSettings.classifier?.host).toBe('http://custom:1234');
|
||||
expect(gemmaSettings.classifier?.model).toBe('custom-gemma');
|
||||
});
|
||||
|
||||
it('should handle partial gemmaModelRouter settings', async () => {
|
||||
process.argv = ['node', 'script.js'];
|
||||
const argv = await parseArguments(createTestMergedSettings());
|
||||
const settings = createTestMergedSettings({
|
||||
experimental: {
|
||||
gemmaModelRouter: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
const config = await loadCliConfig(settings, 'test-session', argv);
|
||||
expect(config.getGemmaModelRouterEnabled()).toBe(true);
|
||||
const gemmaSettings = config.getGemmaModelRouterSettings();
|
||||
expect(gemmaSettings.classifier?.host).toBe('http://localhost:9379');
|
||||
expect(gemmaSettings.classifier?.model).toBe('gemma3-1b-gpu-custom');
|
||||
});
|
||||
});
|
||||
|
||||
describe('loadCliConfig fileFiltering', () => {
|
||||
const originalArgv = process.argv;
|
||||
|
||||
|
||||
@@ -856,6 +856,7 @@ export async function loadCliConfig(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
||||
format: (argv.outputFormat ?? settings.output?.format) as OutputFormat,
|
||||
},
|
||||
gemmaModelRouter: settings.experimental?.gemmaModelRouter,
|
||||
fakeResponses: argv.fakeResponses,
|
||||
recordResponses: argv.recordResponses,
|
||||
retryFetchErrors: settings.general?.retryFetchErrors,
|
||||
|
||||
@@ -444,6 +444,60 @@ describe('SettingsSchema', () => {
|
||||
expect(hookItemProperties.description).toBeDefined();
|
||||
expect(hookItemProperties.description.type).toBe('string');
|
||||
});
|
||||
|
||||
it('should have gemmaModelRouter setting in schema', () => {
|
||||
const gemmaModelRouter =
|
||||
getSettingsSchema().experimental.properties.gemmaModelRouter;
|
||||
expect(gemmaModelRouter).toBeDefined();
|
||||
expect(gemmaModelRouter.type).toBe('object');
|
||||
expect(gemmaModelRouter.category).toBe('Experimental');
|
||||
expect(gemmaModelRouter.default).toEqual({});
|
||||
expect(gemmaModelRouter.requiresRestart).toBe(true);
|
||||
expect(gemmaModelRouter.showInDialog).toBe(true);
|
||||
expect(gemmaModelRouter.description).toBe(
|
||||
'Enable Gemma model router (experimental).',
|
||||
);
|
||||
|
||||
const enabled = gemmaModelRouter.properties.enabled;
|
||||
expect(enabled).toBeDefined();
|
||||
expect(enabled.type).toBe('boolean');
|
||||
expect(enabled.category).toBe('Experimental');
|
||||
expect(enabled.default).toBe(false);
|
||||
expect(enabled.requiresRestart).toBe(true);
|
||||
expect(enabled.showInDialog).toBe(true);
|
||||
expect(enabled.description).toBe(
|
||||
'Enable the Gemma Model Router. Requires a local endpoint serving Gemma via the Gemini API using LiteRT-LM shim.',
|
||||
);
|
||||
|
||||
const classifier = gemmaModelRouter.properties.classifier;
|
||||
expect(classifier).toBeDefined();
|
||||
expect(classifier.type).toBe('object');
|
||||
expect(classifier.category).toBe('Experimental');
|
||||
expect(classifier.default).toEqual({});
|
||||
expect(classifier.requiresRestart).toBe(true);
|
||||
expect(classifier.showInDialog).toBe(false);
|
||||
expect(classifier.description).toBe('Classifier configuration.');
|
||||
|
||||
const host = classifier.properties.host;
|
||||
expect(host).toBeDefined();
|
||||
expect(host.type).toBe('string');
|
||||
expect(host.category).toBe('Experimental');
|
||||
expect(host.default).toBe('http://localhost:9379');
|
||||
expect(host.requiresRestart).toBe(true);
|
||||
expect(host.showInDialog).toBe(false);
|
||||
expect(host.description).toBe('The host of the classifier.');
|
||||
|
||||
const model = classifier.properties.model;
|
||||
expect(model).toBeDefined();
|
||||
expect(model.type).toBe('string');
|
||||
expect(model.category).toBe('Experimental');
|
||||
expect(model.default).toBe('gemma3-1b-gpu-custom');
|
||||
expect(model.requiresRestart).toBe(true);
|
||||
expect(model.showInDialog).toBe(false);
|
||||
expect(model.description).toBe(
|
||||
'The model to use for the classifier. Only tested on `gemma3-1b-gpu-custom`.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('has JSON schema definitions for every referenced ref', () => {
|
||||
|
||||
@@ -1787,6 +1787,57 @@ const SETTINGS_SCHEMA = {
|
||||
'Enable web fetch behavior that bypasses LLM summarization.',
|
||||
showInDialog: true,
|
||||
},
|
||||
gemmaModelRouter: {
|
||||
type: 'object',
|
||||
label: 'Gemma Model Router',
|
||||
category: 'Experimental',
|
||||
requiresRestart: true,
|
||||
default: {},
|
||||
description: 'Enable Gemma model router (experimental).',
|
||||
showInDialog: true,
|
||||
properties: {
|
||||
enabled: {
|
||||
type: 'boolean',
|
||||
label: 'Enable Gemma Model Router',
|
||||
category: 'Experimental',
|
||||
requiresRestart: true,
|
||||
default: false,
|
||||
description:
|
||||
'Enable the Gemma Model Router. Requires a local endpoint serving Gemma via the Gemini API using LiteRT-LM shim.',
|
||||
showInDialog: true,
|
||||
},
|
||||
classifier: {
|
||||
type: 'object',
|
||||
label: 'Classifier',
|
||||
category: 'Experimental',
|
||||
requiresRestart: true,
|
||||
default: {},
|
||||
description: 'Classifier configuration.',
|
||||
showInDialog: false,
|
||||
properties: {
|
||||
host: {
|
||||
type: 'string',
|
||||
label: 'Host',
|
||||
category: 'Experimental',
|
||||
requiresRestart: true,
|
||||
default: 'http://localhost:9379',
|
||||
description: 'The host of the classifier.',
|
||||
showInDialog: false,
|
||||
},
|
||||
model: {
|
||||
type: 'string',
|
||||
label: 'Model',
|
||||
category: 'Experimental',
|
||||
requiresRestart: true,
|
||||
default: 'gemma3-1b-gpu-custom',
|
||||
description:
|
||||
'The model to use for the classifier. Only tested on `gemma3-1b-gpu-custom`.',
|
||||
showInDialog: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -2532,7 +2583,9 @@ type InferSettings<T extends SettingsSchema> = {
|
||||
: T[K]['default']
|
||||
: T[K]['default'] extends boolean
|
||||
? boolean
|
||||
: T[K]['default'];
|
||||
: T[K]['default'] extends string
|
||||
? string
|
||||
: T[K]['default'];
|
||||
};
|
||||
|
||||
type InferMergedSettings<T extends SettingsSchema> = {
|
||||
@@ -2544,7 +2597,9 @@ type InferMergedSettings<T extends SettingsSchema> = {
|
||||
: T[K]['default']
|
||||
: T[K]['default'] extends boolean
|
||||
? boolean
|
||||
: T[K]['default'];
|
||||
: T[K]['default'] extends string
|
||||
? string
|
||||
: T[K]['default'];
|
||||
};
|
||||
|
||||
export type Settings = InferSettings<SettingsSchemaType>;
|
||||
|
||||
Reference in New Issue
Block a user