Compare commits

...

1 Commits

Author SHA1 Message Date
Dev Randalpura 4a2f9cbaa8 Added validation for model on start 2026-05-15 13:52:50 -04:00
3 changed files with 71 additions and 11 deletions
+35 -3
View File
@@ -324,6 +324,38 @@ describe('Server Config (config.ts)', () => {
});
});
describe('model fallback', () => {
it('should fallback to default model when an obsolete model is provided', () => {
const config = new Config({
...baseParams,
model: 'gemini-pro-latest',
});
expect(config.getModel()).toBe(DEFAULT_GEMINI_MODEL);
});
it('should fallback to default model when an invalid gemini model is provided', () => {
const config = new Config({
...baseParams,
model: 'gemini-invalid-model',
});
expect(config.getModel()).toBe(DEFAULT_GEMINI_MODEL);
});
it('should fallback to default model when setModel is called with an invalid gemini model', () => {
const config = new Config(baseParams);
config.setModel('gemini-invalid-model');
expect(config.getModel()).toBe(DEFAULT_GEMINI_MODEL);
});
it('should allow custom models (non-gemini prefixed)', () => {
const config = new Config({
...baseParams,
model: 'custom-model',
});
expect(config.getModel()).toBe('custom-model');
});
});
describe('setShellExecutionConfig', () => {
it('should preserve existing shell execution fields that are not being updated', () => {
const config = new Config({
@@ -2613,7 +2645,7 @@ describe('Config getHooks', () => {
targetDir: '/path/to/target',
debugMode: false,
sessionId: 'test-session-id',
model: 'gemini-pro',
model: 'gemini-2.5-flash',
usageStatisticsEnabled: false,
};
@@ -2862,7 +2894,7 @@ describe('Config getExperiments', () => {
targetDir: '/path/to/target',
debugMode: false,
sessionId: 'test-session-id',
model: 'gemini-pro',
model: 'gemini-2.5-flash',
usageStatisticsEnabled: false,
};
@@ -2907,7 +2939,7 @@ describe('Config setExperiments logging', () => {
targetDir: '/path/to/target',
debugMode: false,
sessionId: 'test-session-id',
model: 'gemini-pro',
model: 'gemini-2.5-flash',
usageStatisticsEnabled: false,
};
+14 -7
View File
@@ -80,10 +80,12 @@ import { tokenLimit } from '../core/tokenLimits.js';
import {
DEFAULT_GEMINI_EMBEDDING_MODEL,
DEFAULT_GEMINI_FLASH_MODEL,
DEFAULT_GEMINI_MODEL,
DEFAULT_GEMINI_MODEL_AUTO,
isAutoModel,
isPreviewModel,
isGemini2Model,
isValidModel,
PREVIEW_GEMINI_FLASH_MODEL,
resolveModel,
} from './models.js';
@@ -1114,9 +1116,11 @@ export class Config implements McpContext, AgentLoopContext {
this.cwd = params.cwd ?? process.cwd();
this.fileDiscoveryService = params.fileDiscoveryService ?? null;
this.bugCommand = params.bugCommand;
this.model = params.model;
this.model = isValidModel(params.model)
? params.model
: DEFAULT_GEMINI_MODEL;
this.disableLoopDetection = params.disableLoopDetection ?? false;
this._activeModel = params.model;
this._activeModel = this.model;
this.enableAgents = params.enableAgents ?? true;
this.agents = params.agents ?? {};
this.disableLLMCorrection = params.disableLLMCorrection ?? true;
@@ -1902,17 +1906,20 @@ export class Config implements McpContext, AgentLoopContext {
}
setModel(newModel: string, isTemporary: boolean = true): void {
if (this.model !== newModel || this._activeModel !== newModel) {
this.model = newModel;
const validatedModel = isValidModel(newModel)
? newModel
: DEFAULT_GEMINI_MODEL;
if (this.model !== validatedModel || this._activeModel !== validatedModel) {
this.model = validatedModel;
// When the user explicitly sets a model, that becomes the active model.
this._activeModel = newModel;
coreEvents.emitModelChanged(newModel);
this._activeModel = validatedModel;
coreEvents.emitModelChanged(validatedModel);
this.lastEmittedQuotaRemaining = undefined;
this.lastEmittedQuotaLimit = undefined;
this.emitQuotaChangedEvent();
}
if (this.onModelChange && !isTemporary) {
this.onModelChange(newModel);
this.onModelChange(validatedModel);
}
this.modelAvailabilityService.reset();
}
+22 -1
View File
@@ -4,6 +4,8 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { normalizeModelId } from '../utils/modelUtils.js';
export interface ModelResolutionContext {
useGemini3_1?: boolean;
useGemini3_1FlashLite?: boolean;
@@ -110,6 +112,20 @@ export function getAutoModelDescription(
return `Let Gemini CLI decide the best model for the task: ${proModel}, ${flashModel}`;
}
export function isValidModel(model: string): boolean {
const normalized = normalizeModelId(model);
return (
VALID_GEMINI_MODELS.has(normalized) ||
normalized === GEMINI_MODEL_ALIAS_AUTO ||
normalized === GEMINI_MODEL_ALIAS_PRO ||
normalized === GEMINI_MODEL_ALIAS_FLASH ||
normalized === GEMINI_MODEL_ALIAS_FLASH_LITE ||
normalized === PREVIEW_GEMINI_MODEL_AUTO ||
normalized === DEFAULT_GEMINI_MODEL_AUTO ||
!normalized.startsWith('gemini-')
);
}
/**
* Resolves the requested model alias (e.g., 'auto', 'pro', 'flash', 'flash-lite')
* to a concrete model name.
@@ -196,7 +212,12 @@ export function resolveModel(
break;
}
default: {
resolved = normalizedModel;
if (!isValidModel(normalizedModel)) {
// Fallback to stable default for unknown/obsolete models.
resolved = DEFAULT_GEMINI_MODEL;
} else {
resolved = normalizedModel;
}
break;
}
}