mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-13 12:14:19 +00:00
fix(cliproxy): align gemini 3.1 preset compatibility
This commit is contained in:
1 parent
fcc5fad601
commit
5ac91e0cac
10 files changed
+125
-42
No files matched your search
@@ -35,8 +35,9 @@ export const CCS_CONTROL_PANEL_SECRET = 'ccs';
|
|||||||
* v11: Migrated deprecated claude-sonnet-4-6-thinking aliases to claude-sonnet-4-6
|
* v11: Migrated deprecated claude-sonnet-4-6-thinking aliases to claude-sonnet-4-6
|
||||||
* v12: Removed denylisted Antigravity Claude 4.5 aliases
|
* v12: Removed denylisted Antigravity Claude 4.5 aliases
|
||||||
* v13: Removed aggressive Gemini alias expansion to reduce model list noise in Control Panel
|
* v13: Removed aggressive Gemini alias expansion to reduce model list noise in Control Panel
|
||||||
|
* v14: Added Gemini 3.1 Flash Antigravity aliases for upcoming rollout compatibility
|
||||||
*/
|
*/
|
||||||
export const CLIPROXY_CONFIG_VERSION = 13;
|
export const CLIPROXY_CONFIG_VERSION = 14;
|
||||||
|
|
||||||
interface OAuthModelAliasEntry {
|
interface OAuthModelAliasEntry {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -61,6 +62,7 @@ const DEFAULT_ANTIGRAVITY_ALIASES: OAuthModelAliasEntry[] = [
|
|||||||
{ name: 'gemini-3-pro-high', alias: 'gemini-3.1-pro-preview' },
|
{ name: 'gemini-3-pro-high', alias: 'gemini-3.1-pro-preview' },
|
||||||
{ name: 'gemini-3-pro-high', alias: 'gemini-3.1-pro-preview-customtools' },
|
{ name: 'gemini-3-pro-high', alias: 'gemini-3.1-pro-preview-customtools' },
|
||||||
{ name: 'gemini-3-flash', alias: 'gemini-3-flash-preview' },
|
{ name: 'gemini-3-flash', alias: 'gemini-3-flash-preview' },
|
||||||
|
{ name: 'gemini-3-flash', alias: 'gemini-3.1-flash-preview' },
|
||||||
{ name: 'claude-sonnet-4-6', alias: 'claude-sonnet-4-6', fork: true },
|
{ name: 'claude-sonnet-4-6', alias: 'claude-sonnet-4-6', fork: true },
|
||||||
// Backward compatibility: legacy sonnet thinking alias now routes to canonical model ID.
|
// Backward compatibility: legacy sonnet thinking alias now routes to canonical model ID.
|
||||||
{ name: 'claude-sonnet-4-6-thinking', alias: 'claude-sonnet-4-6', fork: true },
|
{ name: 'claude-sonnet-4-6-thinking', alias: 'claude-sonnet-4-6', fork: true },
|
||||||
|
|||||||
@@ -716,7 +716,7 @@ export async function execClaudeWithCLIProxy(
|
|||||||
const issueUrl = getModelIssueUrl(provider, currentModel);
|
const issueUrl = getModelIssueUrl(provider, currentModel);
|
||||||
console.error('');
|
console.error('');
|
||||||
console.error(warn(`${modelEntry?.name || currentModel} has known issues with Claude Code`));
|
console.error(warn(`${modelEntry?.name || currentModel} has known issues with Claude Code`));
|
||||||
console.error(' Tool calls will fail. Use "gemini-3-pro-preview" instead.');
|
console.error(' Tool calls will fail. Use "gemini-3.1-pro-preview" instead.');
|
||||||
if (issueUrl) {
|
if (issueUrl) {
|
||||||
console.error(` Tracking: ${issueUrl}`);
|
console.error(` Tracking: ${issueUrl}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,14 @@ import {
|
|||||||
migrateDeniedAntigravityModelAliases,
|
migrateDeniedAntigravityModelAliases,
|
||||||
normalizeModelIdForProvider,
|
normalizeModelIdForProvider,
|
||||||
} from './model-id-normalizer';
|
} from './model-id-normalizer';
|
||||||
|
import { stripModelConfigurationSuffixes } from '../shared/extended-context-utils';
|
||||||
|
|
||||||
|
const GEMINI_MINOR_VERSION_COMPATIBILITY_IDS = Object.freeze({
|
||||||
|
'gemini-3-pro-preview': 'gemini-3.1-pro-preview',
|
||||||
|
'gemini-3.1-pro-preview': 'gemini-3-pro-preview',
|
||||||
|
'gemini-3-flash-preview': 'gemini-3.1-flash-preview',
|
||||||
|
'gemini-3.1-flash-preview': 'gemini-3-flash-preview',
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thinking support configuration for a model.
|
* Thinking support configuration for a model.
|
||||||
@@ -108,9 +116,9 @@ export const MODEL_CATALOG: Partial<Record<CLIProxyProvider, ProviderCatalog>> =
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'gemini-3-pro-preview',
|
id: 'gemini-3.1-pro-preview',
|
||||||
name: 'Gemini 3 Pro',
|
name: 'Gemini 3.1 Pro',
|
||||||
description: 'Google latest model via Antigravity',
|
description: 'Google latest Gemini Pro model via Antigravity',
|
||||||
thinking: { type: 'levels', levels: ['low', 'high'], dynamicAllowed: true },
|
thinking: { type: 'levels', levels: ['low', 'high'], dynamicAllowed: true },
|
||||||
extendedContext: true,
|
extendedContext: true,
|
||||||
},
|
},
|
||||||
@@ -122,10 +130,10 @@ export const MODEL_CATALOG: Partial<Record<CLIProxyProvider, ProviderCatalog>> =
|
|||||||
defaultModel: 'gemini-2.5-pro',
|
defaultModel: 'gemini-2.5-pro',
|
||||||
models: [
|
models: [
|
||||||
{
|
{
|
||||||
id: 'gemini-3-pro-preview',
|
id: 'gemini-3.1-pro-preview',
|
||||||
name: 'Gemini 3 Pro',
|
name: 'Gemini 3.1 Pro',
|
||||||
tier: 'pro',
|
tier: 'pro',
|
||||||
description: 'Latest model, requires paid Google account',
|
description: 'Latest Gemini Pro model, requires paid Google account',
|
||||||
thinking: { type: 'levels', levels: ['low', 'high'], dynamicAllowed: true },
|
thinking: { type: 'levels', levels: ['low', 'high'], dynamicAllowed: true },
|
||||||
extendedContext: true,
|
extendedContext: true,
|
||||||
},
|
},
|
||||||
@@ -390,7 +398,7 @@ export function getProviderCatalog(provider: CLIProxyProvider): ProviderCatalog
|
|||||||
export function findModel(provider: CLIProxyProvider, modelId: string): ModelEntry | undefined {
|
export function findModel(provider: CLIProxyProvider, modelId: string): ModelEntry | undefined {
|
||||||
const catalog = MODEL_CATALOG[provider];
|
const catalog = MODEL_CATALOG[provider];
|
||||||
if (!catalog || !modelId) return undefined;
|
if (!catalog || !modelId) return undefined;
|
||||||
const normalizedId = modelId.trim().toLowerCase();
|
const normalizedId = stripModelConfigurationSuffixes(modelId).trim().toLowerCase();
|
||||||
const providerNormalizedId = normalizeModelIdForProvider(normalizedId, provider)
|
const providerNormalizedId = normalizeModelIdForProvider(normalizedId, provider)
|
||||||
.trim()
|
.trim()
|
||||||
.toLowerCase();
|
.toLowerCase();
|
||||||
@@ -404,6 +412,16 @@ export function findModel(provider: CLIProxyProvider, modelId: string): ModelEnt
|
|||||||
lookupCandidates.add(migratedProvider);
|
lookupCandidates.add(migratedProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const candidate of [...lookupCandidates]) {
|
||||||
|
const compatibilityId =
|
||||||
|
GEMINI_MINOR_VERSION_COMPATIBILITY_IDS[
|
||||||
|
candidate as keyof typeof GEMINI_MINOR_VERSION_COMPATIBILITY_IDS
|
||||||
|
];
|
||||||
|
if (compatibilityId) {
|
||||||
|
lookupCandidates.add(compatibilityId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return catalog.models.find((m) => lookupCandidates.has(m.id.toLowerCase()));
|
return catalog.models.find((m) => lookupCandidates.has(m.id.toLowerCase()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,11 +32,16 @@ const GEMINI_CLI_GROUPS: Record<
|
|||||||
> = {
|
> = {
|
||||||
'gemini-flash-series': {
|
'gemini-flash-series': {
|
||||||
label: 'Gemini Flash Series',
|
label: 'Gemini Flash Series',
|
||||||
models: ['gemini-3-flash-preview', 'gemini-2.5-flash', 'gemini-2.5-flash-lite'],
|
models: [
|
||||||
|
'gemini-3-flash-preview',
|
||||||
|
'gemini-3.1-flash-preview',
|
||||||
|
'gemini-2.5-flash',
|
||||||
|
'gemini-2.5-flash-lite',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
'gemini-pro-series': {
|
'gemini-pro-series': {
|
||||||
label: 'Gemini Pro Series',
|
label: 'Gemini Pro Series',
|
||||||
models: ['gemini-3-pro-preview', 'gemini-2.5-pro'],
|
models: ['gemini-3-pro-preview', 'gemini-3.1-pro-preview', 'gemini-2.5-pro'],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -718,6 +718,10 @@ const MODEL_PRICING_ALIASES: Record<string, string> = {
|
|||||||
'qwen3-235b': 'qwen3-max',
|
'qwen3-235b': 'qwen3-max',
|
||||||
'qwen3-vl-plus': 'qwen3.5-plus',
|
'qwen3-vl-plus': 'qwen3.5-plus',
|
||||||
'qwen3-32b': 'qwen3.5-plus',
|
'qwen3-32b': 'qwen3.5-plus',
|
||||||
|
'gemini-3.1-pro-preview': 'gemini-3-pro-preview',
|
||||||
|
'gemini-3.1-pro-preview-customtools': 'gemini-3-pro-preview',
|
||||||
|
'gemini-3-1-pro-preview': 'gemini-3-pro-preview',
|
||||||
|
'gemini-3-1-pro-preview-customtools': 'gemini-3-pro-preview',
|
||||||
};
|
};
|
||||||
|
|
||||||
// Default pricing for unknown models
|
// Default pricing for unknown models
|
||||||
|
|||||||
@@ -640,6 +640,8 @@ auth-dir: "${cliproxyDir.replace(/\\/g, '/')}/auth"
|
|||||||
const gemini31AliasLines = [
|
const gemini31AliasLines = [
|
||||||
'alias: gemini-3.1-pro-preview',
|
'alias: gemini-3.1-pro-preview',
|
||||||
'alias: gemini-3.1-pro-preview-customtools',
|
'alias: gemini-3.1-pro-preview-customtools',
|
||||||
|
'alias: gemini-3.1-flash-preview',
|
||||||
|
'alias: gemini-3.1-flash-preview-customtools',
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const aliasLine of gemini31AliasLines) {
|
for (const aliasLine of gemini31AliasLines) {
|
||||||
|
|||||||
@@ -91,11 +91,11 @@ describe('Model Catalog', () => {
|
|||||||
assert.strictEqual(ids.includes('claude-sonnet-4-5'), false);
|
assert.strictEqual(ids.includes('claude-sonnet-4-5'), false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('includes Gemini 3 Pro (free via Antigravity)', () => {
|
it('includes Gemini 3.1 Pro (free via Antigravity)', () => {
|
||||||
const { MODEL_CATALOG } = modelCatalog;
|
const { MODEL_CATALOG } = modelCatalog;
|
||||||
const gem3 = MODEL_CATALOG.agy.models.find((m) => m.id === 'gemini-3-pro-preview');
|
const gem3 = MODEL_CATALOG.agy.models.find((m) => m.id === 'gemini-3.1-pro-preview');
|
||||||
assert(gem3, 'Should include Gemini 3 Pro');
|
assert(gem3, 'Should include Gemini 3.1 Pro');
|
||||||
assert.strictEqual(gem3.name, 'Gemini 3 Pro');
|
assert.strictEqual(gem3.name, 'Gemini 3.1 Pro');
|
||||||
// AGY models are all free - no paid tier
|
// AGY models are all free - no paid tier
|
||||||
assert.strictEqual(gem3.tier, undefined, 'AGY models should not have paid tier');
|
assert.strictEqual(gem3.tier, undefined, 'AGY models should not have paid tier');
|
||||||
});
|
});
|
||||||
@@ -139,11 +139,11 @@ describe('Model Catalog', () => {
|
|||||||
assert.strictEqual(MODEL_CATALOG.gemini.defaultModel, 'gemini-2.5-pro');
|
assert.strictEqual(MODEL_CATALOG.gemini.defaultModel, 'gemini-2.5-pro');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('includes Gemini 3 Pro with pro tier', () => {
|
it('includes Gemini 3.1 Pro with pro tier', () => {
|
||||||
const { MODEL_CATALOG } = modelCatalog;
|
const { MODEL_CATALOG } = modelCatalog;
|
||||||
const gem3 = MODEL_CATALOG.gemini.models.find((m) => m.id === 'gemini-3-pro-preview');
|
const gem3 = MODEL_CATALOG.gemini.models.find((m) => m.id === 'gemini-3.1-pro-preview');
|
||||||
assert(gem3, 'Should include Gemini 3 Pro');
|
assert(gem3, 'Should include Gemini 3.1 Pro');
|
||||||
assert.strictEqual(gem3.name, 'Gemini 3 Pro');
|
assert.strictEqual(gem3.name, 'Gemini 3.1 Pro');
|
||||||
assert.strictEqual(gem3.tier, 'pro');
|
assert.strictEqual(gem3.tier, 'pro');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -246,6 +246,15 @@ describe('Model Catalog', () => {
|
|||||||
assert.strictEqual(legacySonnet?.id, 'claude-sonnet-4-6');
|
assert.strictEqual(legacySonnet?.id, 'claude-sonnet-4-6');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('treats Gemini 3 and 3.1 preview IDs as the same catalog family', () => {
|
||||||
|
const { findModel } = modelCatalog;
|
||||||
|
const legacyGemini = findModel('gemini', 'gemini-3-pro-preview');
|
||||||
|
const currentGemini = findModel('gemini', 'gemini-3.1-pro-preview');
|
||||||
|
|
||||||
|
assert.strictEqual(legacyGemini?.id, 'gemini-3.1-pro-preview');
|
||||||
|
assert.strictEqual(currentGemini?.id, 'gemini-3.1-pro-preview');
|
||||||
|
});
|
||||||
|
|
||||||
it('returns undefined for unknown model', () => {
|
it('returns undefined for unknown model', () => {
|
||||||
const { findModel } = modelCatalog;
|
const { findModel } = modelCatalog;
|
||||||
const model = findModel('agy', 'unknown-model');
|
const model = findModel('agy', 'unknown-model');
|
||||||
@@ -325,7 +334,7 @@ describe('Model Catalog', () => {
|
|||||||
const sonnetThinkingIdx = models.findIndex((m) => m.id === 'claude-sonnet-4-6');
|
const sonnetThinkingIdx = models.findIndex((m) => m.id === 'claude-sonnet-4-6');
|
||||||
|
|
||||||
// Find indices of the remaining non-Claude model
|
// Find indices of the remaining non-Claude model
|
||||||
const geminiIdx = models.findIndex((m) => m.id === 'gemini-3-pro-preview');
|
const geminiIdx = models.findIndex((m) => m.id === 'gemini-3.1-pro-preview');
|
||||||
|
|
||||||
// Primary Claude choices should appear ahead of Gemini fallback.
|
// Primary Claude choices should appear ahead of Gemini fallback.
|
||||||
assert(opusIdx < geminiIdx, 'Opus should be above Gemini');
|
assert(opusIdx < geminiIdx, 'Opus should be above Gemini');
|
||||||
|
|||||||
@@ -168,6 +168,23 @@ describe('Gemini CLI Quota Fetcher', () => {
|
|||||||
expect(proBucket!.remainingFraction).toBe(0.9);
|
expect(proBucket!.remainingFraction).toBe(0.9);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should recognize Gemini 3.1 preview IDs during the rollout', () => {
|
||||||
|
const rawBuckets = [
|
||||||
|
{ model_id: 'gemini-3.1-flash-preview', remaining_fraction: 0.7 },
|
||||||
|
{ model_id: 'gemini-3.1-pro-preview', remaining_fraction: 0.4 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const buckets = buildGeminiCliBuckets(rawBuckets);
|
||||||
|
|
||||||
|
const flashBucket = buckets.find((b) => b.label === 'Gemini Flash Series');
|
||||||
|
const proBucket = buckets.find((b) => b.label === 'Gemini Pro Series');
|
||||||
|
|
||||||
|
expect(flashBucket).toBeDefined();
|
||||||
|
expect(flashBucket!.modelIds).toContain('gemini-3.1-flash-preview');
|
||||||
|
expect(proBucket).toBeDefined();
|
||||||
|
expect(proBucket!.modelIds).toContain('gemini-3.1-pro-preview');
|
||||||
|
});
|
||||||
|
|
||||||
it('should handle camelCase API response', () => {
|
it('should handle camelCase API response', () => {
|
||||||
const rawBuckets = [{ modelId: 'gemini-3-flash-preview', remainingFraction: 0.75 }];
|
const rawBuckets = [{ modelId: 'gemini-3-flash-preview', remainingFraction: 0.75 }];
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,13 @@
|
|||||||
import type { ProviderCatalog } from '@/components/cliproxy/provider-model-selector';
|
import type { ProviderCatalog } from '@/components/cliproxy/provider-model-selector';
|
||||||
import { stripModelConfigurationSuffixes } from '@/lib/extended-context-utils';
|
import { stripModelConfigurationSuffixes } from '@/lib/extended-context-utils';
|
||||||
|
|
||||||
|
const GEMINI_MINOR_VERSION_COMPATIBILITY_IDS = Object.freeze({
|
||||||
|
'gemini-3-pro-preview': 'gemini-3.1-pro-preview',
|
||||||
|
'gemini-3.1-pro-preview': 'gemini-3-pro-preview',
|
||||||
|
'gemini-3-flash-preview': 'gemini-3.1-flash-preview',
|
||||||
|
'gemini-3.1-flash-preview': 'gemini-3-flash-preview',
|
||||||
|
});
|
||||||
|
|
||||||
/** Model catalog data - mirrors src/cliproxy/model-catalog.ts */
|
/** Model catalog data - mirrors src/cliproxy/model-catalog.ts */
|
||||||
export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
|
export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
|
||||||
agy: {
|
agy: {
|
||||||
@@ -39,26 +46,26 @@ export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'gemini-3-pro-preview',
|
id: 'gemini-3.1-pro-preview',
|
||||||
name: 'Gemini 3 Pro',
|
name: 'Gemini 3.1 Pro',
|
||||||
description: 'Google latest model via Antigravity',
|
description: 'Google latest Gemini Pro model via Antigravity',
|
||||||
extendedContext: true,
|
extendedContext: true,
|
||||||
presetMapping: {
|
presetMapping: {
|
||||||
default: 'gemini-3-pro-preview',
|
default: 'gemini-3.1-pro-preview',
|
||||||
opus: 'gemini-3-pro-preview',
|
opus: 'gemini-3.1-pro-preview',
|
||||||
sonnet: 'gemini-3-pro-preview',
|
sonnet: 'gemini-3.1-pro-preview',
|
||||||
haiku: 'gemini-3-flash-preview',
|
haiku: 'gemini-3-flash-preview',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'gemini-3-flash-preview',
|
id: 'gemini-3-flash-preview',
|
||||||
name: 'Gemini 3 Flash',
|
name: 'Gemini Flash',
|
||||||
description: 'Fast Gemini model via Antigravity',
|
description: 'Fast Gemini model via Antigravity with 3/3.1 Flash rollout compatibility',
|
||||||
extendedContext: true,
|
extendedContext: true,
|
||||||
presetMapping: {
|
presetMapping: {
|
||||||
default: 'gemini-3-flash-preview',
|
default: 'gemini-3-flash-preview',
|
||||||
opus: 'gemini-3-pro-preview',
|
opus: 'gemini-3.1-pro-preview',
|
||||||
sonnet: 'gemini-3-pro-preview',
|
sonnet: 'gemini-3.1-pro-preview',
|
||||||
haiku: 'gemini-3-flash-preview',
|
haiku: 'gemini-3-flash-preview',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -70,28 +77,28 @@ export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
|
|||||||
defaultModel: 'gemini-2.5-pro',
|
defaultModel: 'gemini-2.5-pro',
|
||||||
models: [
|
models: [
|
||||||
{
|
{
|
||||||
id: 'gemini-3-pro-preview',
|
id: 'gemini-3.1-pro-preview',
|
||||||
name: 'Gemini 3 Pro',
|
name: 'Gemini 3.1 Pro',
|
||||||
tier: 'paid',
|
tier: 'paid',
|
||||||
description: 'Latest model, requires paid Google account',
|
description: 'Latest Gemini Pro model, requires paid Google account',
|
||||||
extendedContext: true,
|
extendedContext: true,
|
||||||
presetMapping: {
|
presetMapping: {
|
||||||
default: 'gemini-3-pro-preview',
|
default: 'gemini-3.1-pro-preview',
|
||||||
opus: 'gemini-3-pro-preview',
|
opus: 'gemini-3.1-pro-preview',
|
||||||
sonnet: 'gemini-3-pro-preview',
|
sonnet: 'gemini-3.1-pro-preview',
|
||||||
haiku: 'gemini-3-flash-preview',
|
haiku: 'gemini-3-flash-preview',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'gemini-3-flash-preview',
|
id: 'gemini-3-flash-preview',
|
||||||
name: 'Gemini 3 Flash',
|
name: 'Gemini Flash',
|
||||||
tier: 'paid',
|
tier: 'paid',
|
||||||
description: 'Fast Gemini 3 model, requires paid Google account',
|
description: 'Fast Gemini model, requires paid Google account and tracks 3/3.1 Flash IDs',
|
||||||
extendedContext: true,
|
extendedContext: true,
|
||||||
presetMapping: {
|
presetMapping: {
|
||||||
default: 'gemini-3-flash-preview',
|
default: 'gemini-3-flash-preview',
|
||||||
opus: 'gemini-3-pro-preview',
|
opus: 'gemini-3.1-pro-preview',
|
||||||
sonnet: 'gemini-3-pro-preview',
|
sonnet: 'gemini-3.1-pro-preview',
|
||||||
haiku: 'gemini-3-flash-preview',
|
haiku: 'gemini-3-flash-preview',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -560,7 +567,14 @@ export function findCatalogModel(provider: string, modelId: string) {
|
|||||||
if (!catalog) return undefined;
|
if (!catalog) return undefined;
|
||||||
|
|
||||||
const normalizedModelId = stripModelConfigurationSuffixes(modelId);
|
const normalizedModelId = stripModelConfigurationSuffixes(modelId);
|
||||||
return catalog.models.find((model) => model.id === normalizedModelId);
|
const compatibilityModelId =
|
||||||
|
GEMINI_MINOR_VERSION_COMPATIBILITY_IDS[
|
||||||
|
normalizedModelId.toLowerCase() as keyof typeof GEMINI_MINOR_VERSION_COMPATIBILITY_IDS
|
||||||
|
];
|
||||||
|
|
||||||
|
return catalog.models.find(
|
||||||
|
(model) => model.id === normalizedModelId || model.id === compatibilityModelId
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function supportsExtendedContext(provider: string, modelId: string): boolean {
|
export function supportsExtendedContext(provider: string, modelId: string): boolean {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||||
|
|
||||||
import { MODEL_CATALOGS } from '@/lib/model-catalogs';
|
import { MODEL_CATALOGS, findCatalogModel } from '@/lib/model-catalogs';
|
||||||
import { applyDefaultPreset } from '@/lib/preset-utils';
|
import { applyDefaultPreset } from '@/lib/preset-utils';
|
||||||
|
|
||||||
describe('claude preset utils', () => {
|
describe('claude preset utils', () => {
|
||||||
@@ -41,4 +41,16 @@ describe('claude preset utils', () => {
|
|||||||
ANTHROPIC_DEFAULT_HAIKU_MODEL: 'claude-haiku-4-5-20251001',
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: 'claude-haiku-4-5-20251001',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('keeps Gemini presets on 3.1 Pro while resolving 3/3.1 alias variants', () => {
|
||||||
|
const geminiCatalog = MODEL_CATALOGS.gemini;
|
||||||
|
const latestPro = geminiCatalog.models.find((model) => model.id === 'gemini-3.1-pro-preview');
|
||||||
|
|
||||||
|
expect(latestPro?.name).toBe('Gemini 3.1 Pro');
|
||||||
|
expect(latestPro?.presetMapping?.default).toBe('gemini-3.1-pro-preview');
|
||||||
|
expect(findCatalogModel('gemini', 'gemini-3-pro-preview')?.id).toBe('gemini-3.1-pro-preview');
|
||||||
|
expect(findCatalogModel('gemini', 'gemini-3.1-flash-preview')?.id).toBe(
|
||||||
|
'gemini-3-flash-preview'
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
Reference in new issue
Block a user