mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-30 23:14:32 -07:00
Add ModelChain support to ModelConfigService and make ModelDialog dynamic (#22914)
This commit is contained in:
@@ -994,6 +994,10 @@ export class Config implements McpContext, AgentLoopContext {
|
||||
...DEFAULT_MODEL_CONFIGS.classifierIdResolutions,
|
||||
...modelConfigServiceConfig.classifierIdResolutions,
|
||||
};
|
||||
const mergedModelChains = {
|
||||
...DEFAULT_MODEL_CONFIGS.modelChains,
|
||||
...modelConfigServiceConfig.modelChains,
|
||||
};
|
||||
|
||||
modelConfigServiceConfig = {
|
||||
// Preserve other user settings like customAliases
|
||||
@@ -1007,6 +1011,7 @@ export class Config implements McpContext, AgentLoopContext {
|
||||
modelDefinitions: mergedModelDefinitions,
|
||||
modelIdResolutions: mergedModelIdResolutions,
|
||||
classifierIdResolutions: mergedClassifierIdResolutions,
|
||||
modelChains: mergedModelChains,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -251,6 +251,13 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = {
|
||||
],
|
||||
modelDefinitions: {
|
||||
// Concrete Models
|
||||
'gemini-3.1-flash-lite-preview': {
|
||||
tier: 'flash-lite',
|
||||
family: 'gemini-3',
|
||||
isPreview: true,
|
||||
isVisible: true,
|
||||
features: { thinking: false, multimodalToolUse: true },
|
||||
},
|
||||
'gemini-3.1-pro-preview': {
|
||||
tier: 'pro',
|
||||
family: 'gemini-3',
|
||||
@@ -331,7 +338,7 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = {
|
||||
isPreview: true,
|
||||
isVisible: true,
|
||||
dialogDescription:
|
||||
'Let Gemini CLI decide the best model for the task: gemini-3.1-pro, gemini-3-flash',
|
||||
'Let Gemini CLI decide the best model for the task: gemini-3-pro, gemini-3-flash',
|
||||
features: { thinking: true, multimodalToolUse: false },
|
||||
},
|
||||
'auto-gemini-2.5': {
|
||||
@@ -345,6 +352,27 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = {
|
||||
},
|
||||
},
|
||||
modelIdResolutions: {
|
||||
'gemini-3.1-pro-preview': {
|
||||
default: 'gemini-3.1-pro-preview',
|
||||
contexts: [
|
||||
{ condition: { hasAccessToPreview: false }, target: 'gemini-2.5-pro' },
|
||||
],
|
||||
},
|
||||
'gemini-3.1-pro-preview-customtools': {
|
||||
default: 'gemini-3.1-pro-preview-customtools',
|
||||
contexts: [
|
||||
{ condition: { hasAccessToPreview: false }, target: 'gemini-2.5-pro' },
|
||||
],
|
||||
},
|
||||
'gemini-3-flash-preview': {
|
||||
default: 'gemini-3-flash-preview',
|
||||
contexts: [
|
||||
{
|
||||
condition: { hasAccessToPreview: false },
|
||||
target: 'gemini-2.5-flash',
|
||||
},
|
||||
],
|
||||
},
|
||||
'gemini-3-pro-preview': {
|
||||
default: 'gemini-3-pro-preview',
|
||||
contexts: [
|
||||
@@ -451,4 +479,120 @@ export const DEFAULT_MODEL_CONFIGS: ModelConfigServiceConfig = {
|
||||
],
|
||||
},
|
||||
},
|
||||
modelChains: {
|
||||
preview: [
|
||||
{
|
||||
model: 'gemini-3-pro-preview',
|
||||
actions: {
|
||||
terminal: 'prompt',
|
||||
transient: 'prompt',
|
||||
not_found: 'prompt',
|
||||
unknown: 'prompt',
|
||||
},
|
||||
stateTransitions: {
|
||||
terminal: 'terminal',
|
||||
transient: 'terminal',
|
||||
not_found: 'terminal',
|
||||
unknown: 'terminal',
|
||||
},
|
||||
},
|
||||
{
|
||||
model: 'gemini-3-flash-preview',
|
||||
isLastResort: true,
|
||||
actions: {
|
||||
terminal: 'prompt',
|
||||
transient: 'prompt',
|
||||
not_found: 'prompt',
|
||||
unknown: 'prompt',
|
||||
},
|
||||
stateTransitions: {
|
||||
terminal: 'terminal',
|
||||
transient: 'terminal',
|
||||
not_found: 'terminal',
|
||||
unknown: 'terminal',
|
||||
},
|
||||
},
|
||||
],
|
||||
default: [
|
||||
{
|
||||
model: 'gemini-2.5-pro',
|
||||
actions: {
|
||||
terminal: 'prompt',
|
||||
transient: 'prompt',
|
||||
not_found: 'prompt',
|
||||
unknown: 'prompt',
|
||||
},
|
||||
stateTransitions: {
|
||||
terminal: 'terminal',
|
||||
transient: 'terminal',
|
||||
not_found: 'terminal',
|
||||
unknown: 'terminal',
|
||||
},
|
||||
},
|
||||
{
|
||||
model: 'gemini-2.5-flash',
|
||||
isLastResort: true,
|
||||
actions: {
|
||||
terminal: 'prompt',
|
||||
transient: 'prompt',
|
||||
not_found: 'prompt',
|
||||
unknown: 'prompt',
|
||||
},
|
||||
stateTransitions: {
|
||||
terminal: 'terminal',
|
||||
transient: 'terminal',
|
||||
not_found: 'terminal',
|
||||
unknown: 'terminal',
|
||||
},
|
||||
},
|
||||
],
|
||||
lite: [
|
||||
{
|
||||
model: 'gemini-2.5-flash-lite',
|
||||
actions: {
|
||||
terminal: 'silent',
|
||||
transient: 'silent',
|
||||
not_found: 'silent',
|
||||
unknown: 'silent',
|
||||
},
|
||||
stateTransitions: {
|
||||
terminal: 'terminal',
|
||||
transient: 'terminal',
|
||||
not_found: 'terminal',
|
||||
unknown: 'terminal',
|
||||
},
|
||||
},
|
||||
{
|
||||
model: 'gemini-2.5-flash',
|
||||
actions: {
|
||||
terminal: 'silent',
|
||||
transient: 'silent',
|
||||
not_found: 'silent',
|
||||
unknown: 'silent',
|
||||
},
|
||||
stateTransitions: {
|
||||
terminal: 'terminal',
|
||||
transient: 'terminal',
|
||||
not_found: 'terminal',
|
||||
unknown: 'terminal',
|
||||
},
|
||||
},
|
||||
{
|
||||
model: 'gemini-2.5-pro',
|
||||
isLastResort: true,
|
||||
actions: {
|
||||
terminal: 'silent',
|
||||
transient: 'silent',
|
||||
not_found: 'silent',
|
||||
unknown: 'silent',
|
||||
},
|
||||
stateTransitions: {
|
||||
terminal: 'terminal',
|
||||
transient: 'terminal',
|
||||
not_found: 'terminal',
|
||||
unknown: 'terminal',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -190,14 +190,6 @@ describe('Dynamic Configuration Parity', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('supportsModernFeatures should match legacy behavior', () => {
|
||||
for (const model of modelsToTest) {
|
||||
const legacy = supportsModernFeatures(model);
|
||||
const dynamic = supportsModernFeatures(model);
|
||||
expect(dynamic).toBe(legacy);
|
||||
}
|
||||
});
|
||||
|
||||
it('supportsMultimodalFunctionResponse should match legacy behavior', () => {
|
||||
for (const model of modelsToTest) {
|
||||
const legacy = supportsMultimodalFunctionResponse(model, legacyConfig);
|
||||
|
||||
@@ -102,11 +102,24 @@ export function resolveModel(
|
||||
config?: ModelCapabilityContext,
|
||||
): string {
|
||||
if (config?.getExperimentalDynamicModelConfiguration?.() === true) {
|
||||
return config.modelConfigService.resolveModelId(requestedModel, {
|
||||
const resolved = config.modelConfigService.resolveModelId(requestedModel, {
|
||||
useGemini3_1,
|
||||
useCustomTools: useCustomToolModel,
|
||||
hasAccessToPreview,
|
||||
});
|
||||
|
||||
if (!hasAccessToPreview && isPreviewModel(resolved, config)) {
|
||||
// Fallback for unknown preview models.
|
||||
if (resolved.includes('flash-lite')) {
|
||||
return DEFAULT_GEMINI_FLASH_LITE_MODEL;
|
||||
}
|
||||
if (resolved.includes('flash')) {
|
||||
return DEFAULT_GEMINI_FLASH_MODEL;
|
||||
}
|
||||
return DEFAULT_GEMINI_MODEL;
|
||||
}
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
let resolved: string;
|
||||
|
||||
Reference in New Issue
Block a user