fix(agy): normalize sonnet 4.6 model ids and migrate legacy thinking alias

This commit is contained in:
Tam Nhu Tran
2026-03-02 21:10:49 +07:00
parent 8c6913b0ed
commit 8a2b55449b
10 changed files with 96 additions and 62 deletions
+35 -8
View File
@@ -60,7 +60,11 @@ function stripCodexEffortSuffix(modelId: string): string {
* *
* Returns true if migration was performed and file was updated. * Returns true if migration was performed and file was updated.
*/ */
function migrateDeprecatedModelNames(settingsPath: string, settings: ProviderSettings): boolean { function migrateDeprecatedModelNames(
settingsPath: string,
provider: CLIProxyProvider,
settings: ProviderSettings
): boolean {
if (!settings.env || typeof settings.env !== 'object') return false; if (!settings.env || typeof settings.env !== 'object') return false;
let migrated = false; let migrated = false;
@@ -68,13 +72,36 @@ function migrateDeprecatedModelNames(settingsPath: string, settings: ProviderSet
const value = settings.env[key]; const value = settings.env[key];
if (typeof value !== 'string') continue; if (typeof value !== 'string') continue;
// Check if the base model name (before any suffixes) uses the deprecated prefix let canonical = value;
if (value.toLowerCase().startsWith(DEPRECATED_MODEL_PREFIX)) { // Check if the base model name (before any suffixes) uses the deprecated prefix.
settings.env[key] = UPSTREAM_MODEL_PREFIX + value.slice(DEPRECATED_MODEL_PREFIX.length); if (canonical.toLowerCase().startsWith(DEPRECATED_MODEL_PREFIX)) {
canonical = UPSTREAM_MODEL_PREFIX + canonical.slice(DEPRECATED_MODEL_PREFIX.length);
}
canonical = normalizeModelIdForProvider(canonical, provider);
if (canonical !== value) {
settings.env[key] = canonical;
migrated = true; migrated = true;
} }
} }
if (provider === 'agy' && Array.isArray(settings.presets)) {
for (const preset of settings.presets) {
if (!preset || typeof preset !== 'object') continue;
const presetRecord = preset as Record<string, unknown>;
for (const key of PRESET_MODEL_KEYS) {
const value = presetRecord[key];
if (typeof value !== 'string') continue;
const canonical = normalizeModelIdForProvider(value, provider);
if (canonical !== value) {
presetRecord[key] = canonical;
migrated = true;
}
}
}
}
if (migrated) { if (migrated) {
try { try {
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', { mode: 0o600 }); fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', { mode: 0o600 });
@@ -409,7 +436,7 @@ export function getEffectiveEnvVars(
if (settings.env && typeof settings.env === 'object') { if (settings.env && typeof settings.env === 'object') {
// Migrate deprecated gemini-claude-* model names if present // Migrate deprecated gemini-claude-* model names if present
migrateDeprecatedModelNames(expandedPath, settings); migrateDeprecatedModelNames(expandedPath, provider, settings);
// Migrate codex effort suffixes to canonical IDs if present // Migrate codex effort suffixes to canonical IDs if present
migrateCodexEffortSuffixes(expandedPath, provider, settings); migrateCodexEffortSuffixes(expandedPath, provider, settings);
// Migrate legacy iFlow placeholders to supported model IDs // Migrate legacy iFlow placeholders to supported model IDs
@@ -444,7 +471,7 @@ export function getEffectiveEnvVars(
if (settings.env && typeof settings.env === 'object') { if (settings.env && typeof settings.env === 'object') {
// Migrate deprecated gemini-claude-* model names if present // Migrate deprecated gemini-claude-* model names if present
migrateDeprecatedModelNames(settingsPath, settings); migrateDeprecatedModelNames(settingsPath, provider, settings);
// Migrate codex effort suffixes to canonical IDs if present // Migrate codex effort suffixes to canonical IDs if present
migrateCodexEffortSuffixes(settingsPath, provider, settings); migrateCodexEffortSuffixes(settingsPath, provider, settings);
// Migrate legacy iFlow placeholders to supported model IDs // Migrate legacy iFlow placeholders to supported model IDs
@@ -584,7 +611,7 @@ export function getRemoteEnvVars(
const content = fs.readFileSync(expandedPath, 'utf-8'); const content = fs.readFileSync(expandedPath, 'utf-8');
const settings: ProviderSettings = JSON.parse(content); const settings: ProviderSettings = JSON.parse(content);
if (settings.env && typeof settings.env === 'object') { if (settings.env && typeof settings.env === 'object') {
migrateDeprecatedModelNames(expandedPath, settings); migrateDeprecatedModelNames(expandedPath, provider, settings);
migrateCodexEffortSuffixes(expandedPath, provider, settings); migrateCodexEffortSuffixes(expandedPath, provider, settings);
migrateIFlowPlaceholderModel(expandedPath, provider, settings); migrateIFlowPlaceholderModel(expandedPath, provider, settings);
userEnvVars = settings.env as Record<string, string>; userEnvVars = settings.env as Record<string, string>;
@@ -604,7 +631,7 @@ export function getRemoteEnvVars(
const content = fs.readFileSync(settingsPath, 'utf-8'); const content = fs.readFileSync(settingsPath, 'utf-8');
const settings: ProviderSettings = JSON.parse(content); const settings: ProviderSettings = JSON.parse(content);
if (settings.env && typeof settings.env === 'object') { if (settings.env && typeof settings.env === 'object') {
migrateDeprecatedModelNames(settingsPath, settings); migrateDeprecatedModelNames(settingsPath, provider, settings);
migrateCodexEffortSuffixes(settingsPath, provider, settings); migrateCodexEffortSuffixes(settingsPath, provider, settings);
migrateIFlowPlaceholderModel(settingsPath, provider, settings); migrateIFlowPlaceholderModel(settingsPath, provider, settings);
userEnvVars = settings.env as Record<string, string>; userEnvVars = settings.env as Record<string, string>;
+14 -5
View File
@@ -32,8 +32,9 @@ export const CCS_CONTROL_PANEL_SECRET = 'ccs';
* v8: Added Gemini 3.1 preview aliases for provider routing compatibility * v8: Added Gemini 3.1 preview aliases for provider routing compatibility
* v9: Added resilient alias compatibility expansion and cache-assisted alias enrichment * v9: Added resilient alias compatibility expansion and cache-assisted alias enrichment
* v10: Migrated deprecated gemini-claude-* aliases to upstream claude-* aliases * v10: Migrated deprecated gemini-claude-* aliases to upstream claude-* aliases
* v11: Migrated deprecated claude-sonnet-4-6-thinking aliases to claude-sonnet-4-6
*/ */
export const CLIPROXY_CONFIG_VERSION = 10; export const CLIPROXY_CONFIG_VERSION = 11;
interface OAuthModelAliasEntry { interface OAuthModelAliasEntry {
name: string; name: string;
@@ -44,6 +45,8 @@ interface OAuthModelAliasEntry {
const GEMINI_MINOR_COMPAT_RANGE = [1, 2, 3, 4, 5, 6, 7, 8, 9] as const; const GEMINI_MINOR_COMPAT_RANGE = [1, 2, 3, 4, 5, 6, 7, 8, 9] as const;
const DEPRECATED_ANTIGRAVITY_ALIAS_PREFIX = 'gemini-claude-'; const DEPRECATED_ANTIGRAVITY_ALIAS_PREFIX = 'gemini-claude-';
const UPSTREAM_CLAUDE_ALIAS_PREFIX = 'claude-'; const UPSTREAM_CLAUDE_ALIAS_PREFIX = 'claude-';
const DEPRECATED_ANTIGRAVITY_SONNET_46_THINKING_ALIAS = 'claude-sonnet-4-6-thinking';
const CANONICAL_ANTIGRAVITY_SONNET_46_ALIAS = 'claude-sonnet-4-6';
/** /**
* Default Antigravity oauth-model-alias entries. * Default Antigravity oauth-model-alias entries.
@@ -58,7 +61,8 @@ const DEFAULT_ANTIGRAVITY_ALIASES: OAuthModelAliasEntry[] = [
{ 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: 'claude-sonnet-4-6', alias: 'claude-sonnet-4-6', fork: true }, { name: 'claude-sonnet-4-6', alias: 'claude-sonnet-4-6', fork: true },
{ name: 'claude-sonnet-4-6-thinking', alias: 'claude-sonnet-4-6-thinking', fork: true }, // 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-5', alias: 'claude-sonnet-4-5', fork: true }, { name: 'claude-sonnet-4-5', alias: 'claude-sonnet-4-5', fork: true },
{ name: 'claude-sonnet-4-5-thinking', alias: 'claude-sonnet-4-5-thinking', fork: true }, { name: 'claude-sonnet-4-5-thinking', alias: 'claude-sonnet-4-5-thinking', fork: true },
{ name: 'claude-opus-4-5-thinking', alias: 'claude-opus-4-5-thinking', fork: true }, { name: 'claude-opus-4-5-thinking', alias: 'claude-opus-4-5-thinking', fork: true },
@@ -107,10 +111,15 @@ function sanitizeYamlScalar(rawValue: string): string {
function normalizeAntigravityAlias(rawAlias: string): string { function normalizeAntigravityAlias(rawAlias: string): string {
const normalized = sanitizeYamlScalar(rawAlias); const normalized = sanitizeYamlScalar(rawAlias);
if (normalized.toLowerCase().startsWith(DEPRECATED_ANTIGRAVITY_ALIAS_PREFIX)) { if (normalized.toLowerCase().startsWith(DEPRECATED_ANTIGRAVITY_ALIAS_PREFIX)) {
return ( const migratedPrefix =
UPSTREAM_CLAUDE_ALIAS_PREFIX + normalized.slice(DEPRECATED_ANTIGRAVITY_ALIAS_PREFIX.length) UPSTREAM_CLAUDE_ALIAS_PREFIX + normalized.slice(DEPRECATED_ANTIGRAVITY_ALIAS_PREFIX.length);
); return normalizeAntigravityAlias(migratedPrefix);
} }
if (normalized.toLowerCase() === DEPRECATED_ANTIGRAVITY_SONNET_46_THINKING_ALIAS) {
return CANONICAL_ANTIGRAVITY_SONNET_46_ALIAS;
}
return normalized; return normalized;
} }
+4 -10
View File
@@ -104,23 +104,17 @@ export const MODEL_CATALOG: Partial<Record<CLIProxyProvider, ProviderCatalog>> =
}, },
}, },
{ {
id: 'claude-sonnet-4-6-thinking', id: 'claude-sonnet-4-6',
name: 'Claude Sonnet 4.6 Thinking', name: 'Claude Sonnet 4.6',
description: 'Latest Sonnet with extended thinking', description: 'Latest Sonnet with thinking budget support',
thinking: { thinking: {
type: 'budget', type: 'budget',
min: 1024, min: 1024,
max: 128000, max: 64000,
zeroAllowed: true, zeroAllowed: true,
dynamicAllowed: true, dynamicAllowed: true,
}, },
}, },
{
id: 'claude-sonnet-4-6',
name: 'Claude Sonnet 4.6',
description: 'Latest Sonnet baseline',
thinking: { type: 'none' },
},
{ {
id: 'claude-sonnet-4-5-thinking', id: 'claude-sonnet-4-5-thinking',
name: 'Claude Sonnet 4.5 Thinking', name: 'Claude Sonnet 4.5 Thinking',
+21 -5
View File
@@ -20,6 +20,9 @@ type ProviderLike = CLIProxyProvider | string | null | undefined;
const CLAUDE_DOTTED_VERSION_REGEX = /claude-(sonnet|opus|haiku)-(\d+)\.(\d+)(?=(?:$|-|\[|\(|\/))/gi; const CLAUDE_DOTTED_VERSION_REGEX = /claude-(sonnet|opus|haiku)-(\d+)\.(\d+)(?=(?:$|-|\[|\(|\/))/gi;
const CLAUDE_DOTTED_THINKING_REGEX = const CLAUDE_DOTTED_THINKING_REGEX =
/claude-(sonnet|opus|haiku)-(\d+)\.(\d+)-thinking(?=(?:$|-|\[|\(|\/))/gi; /claude-(sonnet|opus|haiku)-(\d+)\.(\d+)-thinking(?=(?:$|-|\[|\(|\/))/gi;
const DEPRECATED_ANTIGRAVITY_SONNET_46_THINKING_REGEX =
/claude-sonnet-4(?:[.-])6-thinking(?=(?:$|-|\[|\(|\/))/gi;
const CANONICAL_ANTIGRAVITY_SONNET_46_MODEL = 'claude-sonnet-4-6';
/** /**
* Extract provider segment from `/api/provider/{provider}` request paths. * Extract provider segment from `/api/provider/{provider}` request paths.
@@ -62,6 +65,17 @@ export function normalizeClaudeDottedThinkingMajorMinor(model: string): string {
); );
} }
/**
* Antigravity no longer exposes `claude-sonnet-4-6-thinking`.
* Canonicalize legacy aliases to `claude-sonnet-4-6` while preserving suffixes.
*/
export function normalizeDeprecatedAntigravityModelAliases(model: string): string {
return model.replace(
DEPRECATED_ANTIGRAVITY_SONNET_46_THINKING_REGEX,
CANONICAL_ANTIGRAVITY_SONNET_46_MODEL
);
}
/** /**
* Normalize model ID for a specific provider. * Normalize model ID for a specific provider.
* Antigravity requires hyphenated Claude major.minor model IDs. * Antigravity requires hyphenated Claude major.minor model IDs.
@@ -76,7 +90,8 @@ export function normalizeClaudeDottedThinkingMajorMinor(model: string): string {
*/ */
export function normalizeModelIdForProvider(model: string, provider: ProviderLike): string { export function normalizeModelIdForProvider(model: string, provider: ProviderLike): string {
if (!isAntigravityProvider(provider)) return model; if (!isAntigravityProvider(provider)) return model;
return normalizeClaudeDottedMajorMinor(model); const normalizedDottedVersion = normalizeClaudeDottedMajorMinor(model);
return normalizeDeprecatedAntigravityModelAliases(normalizedDottedVersion);
} }
/** /**
@@ -87,7 +102,7 @@ export function normalizeModelIdForProvider(model: string, provider: ProviderLik
* *
* @example * @example
* normalizeModelIdForRouting('claude-sonnet-4.6-thinking', null) * normalizeModelIdForRouting('claude-sonnet-4.6-thinking', null)
* // => 'claude-sonnet-4-6-thinking' * // => 'claude-sonnet-4-6'
* *
* @example * @example
* normalizeModelIdForRouting('claude-sonnet-4.6', null) * normalizeModelIdForRouting('claude-sonnet-4.6', null)
@@ -95,9 +110,10 @@ export function normalizeModelIdForProvider(model: string, provider: ProviderLik
*/ */
export function normalizeModelIdForRouting(model: string, provider: ProviderLike): string { export function normalizeModelIdForRouting(model: string, provider: ProviderLike): string {
if (isAntigravityProvider(provider)) { if (isAntigravityProvider(provider)) {
return normalizeClaudeDottedMajorMinor(model); return normalizeModelIdForProvider(model, provider);
} }
return normalizeClaudeDottedThinkingMajorMinor(model); const normalizedThinking = normalizeClaudeDottedThinkingMajorMinor(model);
return normalizeDeprecatedAntigravityModelAliases(normalizedThinking);
} }
/** /**
@@ -109,7 +125,7 @@ export function normalizeModelIdForRouting(model: string, provider: ProviderLike
* { ANTHROPIC_MODEL: 'claude-sonnet-4.6-thinking' }, * { ANTHROPIC_MODEL: 'claude-sonnet-4.6-thinking' },
* 'agy' * 'agy'
* ) * )
* // => { ANTHROPIC_MODEL: 'claude-sonnet-4-6-thinking' } * // => { ANTHROPIC_MODEL: 'claude-sonnet-4-6' }
*/ */
export function normalizeModelEnvVarsForProvider( export function normalizeModelEnvVarsForProvider(
envVars: NodeJS.ProcessEnv, envVars: NodeJS.ProcessEnv,
+2 -2
View File
@@ -792,8 +792,8 @@ oauth-model-alias:
const newConfig = fs.readFileSync(path.join(cliproxyDir, 'config.yaml'), 'utf-8'); const newConfig = fs.readFileSync(path.join(cliproxyDir, 'config.yaml'), 'utf-8');
assert( assert(
newConfig.includes('alias: claude-sonnet-4-6-thinking'), newConfig.includes('alias: claude-sonnet-4-6'),
'Should include normalized upstream Claude alias' 'Should migrate deprecated sonnet thinking alias to canonical model ID'
); );
assert( assert(
!newConfig.includes('alias: gemini-claude-sonnet-4-6-thinking'), !newConfig.includes('alias: gemini-claude-sonnet-4-6-thinking'),
@@ -105,10 +105,17 @@ describe('getEffectiveEnvVars local provider URL normalization', () => {
}); });
const env = getEffectiveEnvVars('agy', 8317, settingsPath); const env = getEffectiveEnvVars('agy', 8317, settingsPath);
expect(env.ANTHROPIC_MODEL).toBe('claude-sonnet-4-6-thinking'); expect(env.ANTHROPIC_MODEL).toBe('claude-sonnet-4-6');
expect(env.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('claude-opus-4-6-thinking'); expect(env.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('claude-opus-4-6-thinking');
expect(env.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('claude-sonnet-4-6-thinking'); expect(env.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('claude-sonnet-4-6');
expect(env.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe('claude-haiku-4-5'); expect(env.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe('claude-haiku-4-5');
const persisted = JSON.parse(fs.readFileSync(settingsPath, 'utf-8')) as {
env: Record<string, string>;
};
expect(persisted.env.ANTHROPIC_MODEL).toBe('claude-sonnet-4-6');
expect(persisted.env.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('claude-opus-4-6-thinking');
expect(persisted.env.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('claude-sonnet-4-6');
}); });
it('migrates codex preset model mappings to canonical IDs', () => { it('migrates codex preset model mappings to canonical IDs', () => {
+2 -11
View File
@@ -85,15 +85,6 @@ describe('Model Catalog', () => {
assert.strictEqual(sonnetThinking.name, 'Claude Sonnet 4.5 Thinking'); assert.strictEqual(sonnetThinking.name, 'Claude Sonnet 4.5 Thinking');
}); });
it('includes Claude Sonnet 4.6 Thinking', () => {
const { MODEL_CATALOG } = modelCatalog;
const sonnetThinking = MODEL_CATALOG.agy.models.find(
(m) => m.id === 'claude-sonnet-4-6-thinking'
);
assert(sonnetThinking, 'Should include Claude Sonnet 4.6 Thinking');
assert.strictEqual(sonnetThinking.name, 'Claude Sonnet 4.6 Thinking');
});
it('includes Claude Sonnet 4.6', () => { it('includes Claude Sonnet 4.6', () => {
const { MODEL_CATALOG } = modelCatalog; const { MODEL_CATALOG } = modelCatalog;
const sonnet = MODEL_CATALOG.agy.models.find((m) => m.id === 'claude-sonnet-4-6'); const sonnet = MODEL_CATALOG.agy.models.find((m) => m.id === 'claude-sonnet-4-6');
@@ -117,9 +108,9 @@ describe('Model Catalog', () => {
assert.strictEqual(gem3.tier, undefined, 'AGY models should not have paid tier'); assert.strictEqual(gem3.tier, undefined, 'AGY models should not have paid tier');
}); });
it('has 7 models total', () => { it('has 6 models total', () => {
const { MODEL_CATALOG } = modelCatalog; const { MODEL_CATALOG } = modelCatalog;
assert.strictEqual(MODEL_CATALOG.agy.models.length, 7); assert.strictEqual(MODEL_CATALOG.agy.models.length, 6);
}); });
}); });
@@ -44,13 +44,16 @@ describe('model-id-normalizer', () => {
it('applies provider-aware routing normalization', () => { it('applies provider-aware routing normalization', () => {
expect(normalizeModelIdForRouting('claude-sonnet-4.6-thinking', null)).toBe( expect(normalizeModelIdForRouting('claude-sonnet-4.6-thinking', null)).toBe(
'claude-sonnet-4-6-thinking' 'claude-sonnet-4-6'
); );
expect(normalizeModelIdForRouting('claude-sonnet-4.6', null)).toBe('claude-sonnet-4.6'); expect(normalizeModelIdForRouting('claude-sonnet-4.6', null)).toBe('claude-sonnet-4.6');
expect(normalizeModelIdForRouting('claude-sonnet-4.6', 'agy')).toBe('claude-sonnet-4-6'); expect(normalizeModelIdForRouting('claude-sonnet-4.6', 'agy')).toBe('claude-sonnet-4-6');
}); });
it('applies provider-only normalization for antigravity', () => { it('applies provider-only normalization for antigravity', () => {
expect(normalizeModelIdForProvider('claude-sonnet-4.6-thinking', 'agy')).toBe(
'claude-sonnet-4-6'
);
expect(normalizeModelIdForProvider('claude-opus-4.6-thinking', 'agy')).toBe( expect(normalizeModelIdForProvider('claude-opus-4.6-thinking', 'agy')).toBe(
'claude-opus-4-6-thinking' 'claude-opus-4-6-thinking'
); );
@@ -71,7 +74,7 @@ describe('model-id-normalizer', () => {
}; };
const normalized = normalizeModelEnvVarsForProvider(input, 'agy'); const normalized = normalizeModelEnvVarsForProvider(input, 'agy');
expect(normalized.ANTHROPIC_MODEL).toBe('claude-sonnet-4-6-thinking'); expect(normalized.ANTHROPIC_MODEL).toBe('claude-sonnet-4-6');
expect(normalized.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('claude-opus-4-6-thinking'); expect(normalized.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('claude-opus-4-6-thinking');
expect(normalized.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('claude-sonnet-4-6'); expect(normalized.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('claude-sonnet-4-6');
expect(normalized.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe('claude-haiku-4-5'); expect(normalized.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe('claude-haiku-4-5');
@@ -201,9 +201,7 @@ describe('ToolSanitizationProxy Integration', () => {
}); });
expect(lastRequest).not.toBeNull(); expect(lastRequest).not.toBeNull();
expect((lastRequest!.body as Record<string, unknown>).model).toBe( expect((lastRequest!.body as Record<string, unknown>).model).toBe('claude-sonnet-4-6');
'claude-sonnet-4-6-thinking'
);
} finally { } finally {
proxy.stop(); proxy.stop();
} }
+3 -14
View File
@@ -22,7 +22,7 @@ export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
presetMapping: { presetMapping: {
default: 'claude-opus-4-6-thinking', default: 'claude-opus-4-6-thinking',
opus: 'claude-opus-4-6-thinking', opus: 'claude-opus-4-6-thinking',
sonnet: 'claude-sonnet-4-6-thinking', sonnet: 'claude-sonnet-4-6',
haiku: 'claude-sonnet-4-6', haiku: 'claude-sonnet-4-6',
}, },
}, },
@@ -33,25 +33,14 @@ export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
presetMapping: { presetMapping: {
default: 'claude-opus-4-5-thinking', default: 'claude-opus-4-5-thinking',
opus: 'claude-opus-4-5-thinking', opus: 'claude-opus-4-5-thinking',
sonnet: 'claude-sonnet-4-6-thinking', sonnet: 'claude-sonnet-4-6',
haiku: 'claude-sonnet-4-6',
},
},
{
id: 'claude-sonnet-4-6-thinking',
name: 'Claude Sonnet 4.6 Thinking',
description: 'Latest Sonnet with extended thinking',
presetMapping: {
default: 'claude-sonnet-4-6-thinking',
opus: 'claude-opus-4-6-thinking',
sonnet: 'claude-sonnet-4-6-thinking',
haiku: 'claude-sonnet-4-6', haiku: 'claude-sonnet-4-6',
}, },
}, },
{ {
id: 'claude-sonnet-4-6', id: 'claude-sonnet-4-6',
name: 'Claude Sonnet 4.6', name: 'Claude Sonnet 4.6',
description: 'Latest Sonnet baseline', description: 'Latest Sonnet with thinking budget support',
presetMapping: { presetMapping: {
default: 'claude-sonnet-4-6', default: 'claude-sonnet-4-6',
opus: 'claude-opus-4-6-thinking', opus: 'claude-opus-4-6-thinking',