mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-29 22:44:45 -07:00
fix(core): handle non-string model flags in resolution (#26069)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
@@ -804,6 +804,100 @@ describe('loadCliConfig', () => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('Model resolution', () => {
|
||||
it('should handle multiple --model flags by taking the last one', async () => {
|
||||
const argv = {
|
||||
query: undefined,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
model: ['gemini-1.5-pro', 'gemini-2.0-flash'] as any,
|
||||
sandbox: undefined,
|
||||
debug: false,
|
||||
prompt: undefined,
|
||||
promptInteractive: undefined,
|
||||
yolo: undefined,
|
||||
approvalMode: undefined,
|
||||
policy: undefined,
|
||||
adminPolicy: undefined,
|
||||
allowedMcpServerNames: undefined,
|
||||
allowedTools: undefined,
|
||||
extensions: undefined,
|
||||
listExtensions: false,
|
||||
listSessions: false,
|
||||
deleteSession: undefined,
|
||||
screenReader: undefined,
|
||||
isCommand: false,
|
||||
rawOutput: false,
|
||||
acceptRawOutputRisk: false,
|
||||
startupMessages: [],
|
||||
resume: undefined,
|
||||
includeDirectories: [],
|
||||
useWriteTodos: false,
|
||||
outputFormat: undefined,
|
||||
fakeResponses: undefined,
|
||||
recordResponses: undefined,
|
||||
skipTrust: false,
|
||||
};
|
||||
|
||||
const settings = createTestMergedSettings();
|
||||
const config = await loadCliConfig(
|
||||
settings,
|
||||
'test-session',
|
||||
argv as unknown as CliArgs,
|
||||
{
|
||||
cwd: process.cwd(),
|
||||
},
|
||||
);
|
||||
|
||||
expect(config.getModel()).toBe('gemini-2.0-flash');
|
||||
});
|
||||
|
||||
it('should handle non-string model flags by coercing to string', async () => {
|
||||
const argv = {
|
||||
query: undefined,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
model: true as any,
|
||||
sandbox: undefined,
|
||||
debug: false,
|
||||
prompt: undefined,
|
||||
promptInteractive: undefined,
|
||||
yolo: undefined,
|
||||
approvalMode: undefined,
|
||||
policy: undefined,
|
||||
adminPolicy: undefined,
|
||||
allowedMcpServerNames: undefined,
|
||||
allowedTools: undefined,
|
||||
extensions: undefined,
|
||||
listExtensions: false,
|
||||
listSessions: false,
|
||||
deleteSession: undefined,
|
||||
screenReader: undefined,
|
||||
isCommand: false,
|
||||
rawOutput: false,
|
||||
acceptRawOutputRisk: false,
|
||||
startupMessages: [],
|
||||
resume: undefined,
|
||||
includeDirectories: [],
|
||||
useWriteTodos: false,
|
||||
outputFormat: undefined,
|
||||
fakeResponses: undefined,
|
||||
recordResponses: undefined,
|
||||
skipTrust: false,
|
||||
};
|
||||
|
||||
const settings = createTestMergedSettings();
|
||||
const config = await loadCliConfig(
|
||||
settings,
|
||||
'test-session',
|
||||
argv as unknown as CliArgs,
|
||||
{
|
||||
cwd: process.cwd(),
|
||||
},
|
||||
);
|
||||
|
||||
expect(config.getModel()).toBe('true');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Proxy configuration', () => {
|
||||
const originalProxyEnv: { [key: string]: string | undefined } = {};
|
||||
const proxyEnvVars = [
|
||||
|
||||
@@ -841,9 +841,16 @@ export async function loadCliConfig(
|
||||
);
|
||||
|
||||
const defaultModel = PREVIEW_GEMINI_MODEL_AUTO;
|
||||
const specifiedModel =
|
||||
const rawModel =
|
||||
argv.model || process.env['GEMINI_MODEL'] || settings.model?.name;
|
||||
|
||||
// Ensure specifiedModel is a string (e.g. if yargs parsed multiple --model as an array)
|
||||
const specifiedModel = Array.isArray(rawModel)
|
||||
? String(rawModel.at(-1) ?? '').trim() || ''
|
||||
: rawModel === undefined
|
||||
? undefined
|
||||
: String(rawModel ?? '').trim() || '';
|
||||
|
||||
const resolvedModel =
|
||||
specifiedModel === GEMINI_MODEL_ALIAS_AUTO
|
||||
? defaultModel
|
||||
|
||||
@@ -273,6 +273,13 @@ describe('isCustomModel', () => {
|
||||
expect(isCustomModel(GEMINI_MODEL_ALIAS_AUTO)).toBe(false);
|
||||
expect(isCustomModel(GEMINI_MODEL_ALIAS_PRO)).toBe(false);
|
||||
});
|
||||
|
||||
it('should not throw if the model is an array (e.g. from yargs)', () => {
|
||||
// @ts-expect-error - testing invalid runtime input
|
||||
expect(() => isCustomModel(['gemini-2.0-flash', 'gpt-4'])).not.toThrow();
|
||||
// @ts-expect-error - testing invalid runtime input
|
||||
expect(isCustomModel(['gemini-2.0-flash', 'gpt-4'])).toBe(true); // last one is custom
|
||||
});
|
||||
});
|
||||
|
||||
describe('supportsModernFeatures', () => {
|
||||
@@ -431,6 +438,15 @@ describe('resolveModel', () => {
|
||||
const model = resolveModel(customModel);
|
||||
expect(model).toBe(customModel);
|
||||
});
|
||||
|
||||
it('should handle non-string inputs gracefully', () => {
|
||||
// @ts-expect-error - testing invalid runtime input
|
||||
expect(resolveModel(['a', 'b'])).toBe('b');
|
||||
// @ts-expect-error - testing invalid runtime input
|
||||
expect(resolveModel(true)).toBe('true');
|
||||
// @ts-expect-error - testing invalid runtime input
|
||||
expect(resolveModel(null)).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('hasAccessToPreview logic', () => {
|
||||
|
||||
@@ -109,8 +109,15 @@ export function resolveModel(
|
||||
hasAccessToPreview: boolean = true,
|
||||
config?: ModelCapabilityContext,
|
||||
): string {
|
||||
// Defensive check against non-string inputs at runtime
|
||||
const normalizedModel = Array.isArray(requestedModel)
|
||||
? String(requestedModel.at(-1) ?? '').trim() || ''
|
||||
: typeof requestedModel !== 'string'
|
||||
? String(requestedModel ?? '').trim() || ''
|
||||
: requestedModel.trim() || '';
|
||||
|
||||
if (config?.getExperimentalDynamicModelConfiguration?.() === true) {
|
||||
const resolved = config.modelConfigService.resolveModelId(requestedModel, {
|
||||
const resolved = config.modelConfigService.resolveModelId(normalizedModel, {
|
||||
useGemini3_1,
|
||||
useGemini3_1FlashLite,
|
||||
useCustomTools: useCustomToolModel,
|
||||
@@ -132,7 +139,7 @@ export function resolveModel(
|
||||
}
|
||||
|
||||
let resolved: string;
|
||||
switch (requestedModel) {
|
||||
switch (normalizedModel) {
|
||||
case PREVIEW_GEMINI_MODEL:
|
||||
case PREVIEW_GEMINI_MODEL_AUTO:
|
||||
case GEMINI_MODEL_ALIAS_AUTO:
|
||||
@@ -161,7 +168,7 @@ export function resolveModel(
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
resolved = requestedModel;
|
||||
resolved = normalizedModel;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user