mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 08:17:11 +00:00
fix(agy): remove deprecated 4.5 selector options
This commit is contained in:
@@ -91,18 +91,6 @@ export const MODEL_CATALOG: Partial<Record<CLIProxyProvider, ProviderCatalog>> =
|
||||
// extendedContext: true,
|
||||
extendedContext: false,
|
||||
},
|
||||
{
|
||||
id: 'claude-opus-4-5-thinking',
|
||||
name: 'Claude Opus 4.5 Thinking',
|
||||
description: 'Previous flagship, extended thinking',
|
||||
thinking: {
|
||||
type: 'budget',
|
||||
min: 1024,
|
||||
max: 100000,
|
||||
zeroAllowed: false,
|
||||
dynamicAllowed: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'claude-sonnet-4-6',
|
||||
name: 'Claude Sonnet 4.6',
|
||||
@@ -115,24 +103,6 @@ export const MODEL_CATALOG: Partial<Record<CLIProxyProvider, ProviderCatalog>> =
|
||||
dynamicAllowed: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'claude-sonnet-4-5-thinking',
|
||||
name: 'Claude Sonnet 4.5 Thinking',
|
||||
description: 'Balanced with extended thinking',
|
||||
thinking: {
|
||||
type: 'budget',
|
||||
min: 1024,
|
||||
max: 100000,
|
||||
zeroAllowed: false,
|
||||
dynamicAllowed: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'claude-sonnet-4-5',
|
||||
name: 'Claude Sonnet 4.5',
|
||||
description: 'Fast and capable',
|
||||
thinking: { type: 'none' },
|
||||
},
|
||||
{
|
||||
id: 'gemini-3-pro-preview',
|
||||
name: 'Gemini 3 Pro',
|
||||
|
||||
@@ -23,6 +23,12 @@ const CLAUDE_DOTTED_THINKING_REGEX =
|
||||
const DEPRECATED_ANTIGRAVITY_SONNET_46_THINKING_REGEX =
|
||||
/claude-sonnet-4(?:[.-])6-thinking(?=(?:$|-|\[|\(|\/))/gi;
|
||||
const CANONICAL_ANTIGRAVITY_SONNET_46_MODEL = 'claude-sonnet-4-6';
|
||||
const DEPRECATED_ANTIGRAVITY_OPUS_45_THINKING_REGEX =
|
||||
/claude-opus-4(?:[.-])5-thinking(?=(?:$|-|\[|\(|\/))/gi;
|
||||
const CANONICAL_ANTIGRAVITY_OPUS_46_THINKING_MODEL = 'claude-opus-4-6-thinking';
|
||||
const DEPRECATED_ANTIGRAVITY_SONNET_45_THINKING_REGEX =
|
||||
/claude-sonnet-4(?:[.-])5-thinking(?=(?:$|-|\[|\(|\/))/gi;
|
||||
const DEPRECATED_ANTIGRAVITY_SONNET_45_REGEX = /claude-sonnet-4(?:[.-])5(?=(?:$|-|\[|\(|\/))/gi;
|
||||
const CODEX_EFFORT_SUFFIX_REGEX = /-(xhigh|high|medium)$/i;
|
||||
|
||||
function trimModelId(model: string): string {
|
||||
@@ -86,10 +92,17 @@ export function normalizeClaudeDottedThinkingMajorMinor(model: string): string {
|
||||
* 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
|
||||
);
|
||||
return model
|
||||
.replace(
|
||||
DEPRECATED_ANTIGRAVITY_OPUS_45_THINKING_REGEX,
|
||||
CANONICAL_ANTIGRAVITY_OPUS_46_THINKING_MODEL
|
||||
)
|
||||
.replace(DEPRECATED_ANTIGRAVITY_SONNET_45_THINKING_REGEX, CANONICAL_ANTIGRAVITY_SONNET_46_MODEL)
|
||||
.replace(DEPRECATED_ANTIGRAVITY_SONNET_45_REGEX, CANONICAL_ANTIGRAVITY_SONNET_46_MODEL)
|
||||
.replace(
|
||||
DEPRECATED_ANTIGRAVITY_SONNET_46_THINKING_REGEX,
|
||||
CANONICAL_ANTIGRAVITY_SONNET_46_MODEL
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,16 +3,28 @@ import { findModel, supportsThinking } from '../../../src/cliproxy/model-catalog
|
||||
|
||||
describe('model-catalog compatibility lookups', () => {
|
||||
it('finds agy Claude models using dotted major.minor IDs', () => {
|
||||
const dottedThinking = findModel('agy', 'claude-sonnet-4.5-thinking');
|
||||
const dottedNonThinking = findModel('agy', 'claude-sonnet-4.5');
|
||||
const dottedThinking = findModel('agy', 'claude-opus-4.6-thinking');
|
||||
const dottedNonThinking = findModel('agy', 'claude-sonnet-4.6');
|
||||
|
||||
expect(dottedThinking?.id).toBe('claude-sonnet-4-5-thinking');
|
||||
expect(dottedNonThinking?.id).toBe('claude-sonnet-4-5');
|
||||
expect(dottedThinking?.id).toBe('claude-opus-4-6-thinking');
|
||||
expect(dottedNonThinking?.id).toBe('claude-sonnet-4-6');
|
||||
});
|
||||
|
||||
it('maps legacy agy 4.5 IDs to canonical 4.6 catalog models', () => {
|
||||
const legacyOpusThinking = findModel('agy', 'claude-opus-4.5-thinking');
|
||||
const legacySonnetThinking = findModel('agy', 'claude-sonnet-4.5-thinking');
|
||||
const legacySonnet = findModel('agy', 'claude-sonnet-4.5');
|
||||
|
||||
expect(legacyOpusThinking?.id).toBe('claude-opus-4-6-thinking');
|
||||
expect(legacySonnetThinking?.id).toBe('claude-sonnet-4-6');
|
||||
expect(legacySonnet?.id).toBe('claude-sonnet-4-6');
|
||||
});
|
||||
|
||||
it('supports thinking checks for dotted agy model IDs', () => {
|
||||
expect(supportsThinking('agy', 'claude-opus-4.6-thinking')).toBe(true);
|
||||
expect(supportsThinking('agy', 'claude-sonnet-4.5')).toBe(false);
|
||||
expect(supportsThinking('agy', 'claude-sonnet-4.6')).toBe(true);
|
||||
expect(supportsThinking('agy', 'claude-opus-4.5-thinking')).toBe(true);
|
||||
expect(supportsThinking('agy', 'claude-sonnet-4.5')).toBe(true);
|
||||
});
|
||||
|
||||
it('maps legacy sonnet 4.6 thinking aliases to canonical agy model', () => {
|
||||
|
||||
@@ -69,20 +69,11 @@ describe('Model Catalog', () => {
|
||||
assert.strictEqual(MODEL_CATALOG.agy.defaultModel, 'claude-opus-4-6-thinking');
|
||||
});
|
||||
|
||||
it('includes Claude Opus 4.5 Thinking', () => {
|
||||
it('includes Claude Opus 4.6 Thinking', () => {
|
||||
const { MODEL_CATALOG } = modelCatalog;
|
||||
const opus = MODEL_CATALOG.agy.models.find((m) => m.id === 'claude-opus-4-5-thinking');
|
||||
assert(opus, 'Should include Claude Opus 4.5 Thinking');
|
||||
assert.strictEqual(opus.name, 'Claude Opus 4.5 Thinking');
|
||||
});
|
||||
|
||||
it('includes Claude Sonnet 4.5 Thinking', () => {
|
||||
const { MODEL_CATALOG } = modelCatalog;
|
||||
const sonnetThinking = MODEL_CATALOG.agy.models.find(
|
||||
(m) => m.id === 'claude-sonnet-4-5-thinking'
|
||||
);
|
||||
assert(sonnetThinking, 'Should include Claude Sonnet 4.5 Thinking');
|
||||
assert.strictEqual(sonnetThinking.name, 'Claude Sonnet 4.5 Thinking');
|
||||
const opus = MODEL_CATALOG.agy.models.find((m) => m.id === 'claude-opus-4-6-thinking');
|
||||
assert(opus, 'Should include Claude Opus 4.6 Thinking');
|
||||
assert.strictEqual(opus.name, 'Claude Opus 4.6 Thinking');
|
||||
});
|
||||
|
||||
it('includes Claude Sonnet 4.6', () => {
|
||||
@@ -92,11 +83,12 @@ describe('Model Catalog', () => {
|
||||
assert.strictEqual(sonnet.name, 'Claude Sonnet 4.6');
|
||||
});
|
||||
|
||||
it('includes Claude Sonnet 4.5', () => {
|
||||
it('does not include deprecated Claude 4.5 AGY models', () => {
|
||||
const { MODEL_CATALOG } = modelCatalog;
|
||||
const sonnet = MODEL_CATALOG.agy.models.find((m) => m.id === 'claude-sonnet-4-5');
|
||||
assert(sonnet, 'Should include Claude Sonnet 4.5');
|
||||
assert.strictEqual(sonnet.name, 'Claude Sonnet 4.5');
|
||||
const ids = MODEL_CATALOG.agy.models.map((m) => m.id);
|
||||
assert.strictEqual(ids.includes('claude-opus-4-5-thinking'), false);
|
||||
assert.strictEqual(ids.includes('claude-sonnet-4-5-thinking'), false);
|
||||
assert.strictEqual(ids.includes('claude-sonnet-4-5'), false);
|
||||
});
|
||||
|
||||
it('includes Gemini 3 Pro (free via Antigravity)', () => {
|
||||
@@ -108,9 +100,9 @@ describe('Model Catalog', () => {
|
||||
assert.strictEqual(gem3.tier, undefined, 'AGY models should not have paid tier');
|
||||
});
|
||||
|
||||
it('has 6 models total', () => {
|
||||
it('has 3 models total', () => {
|
||||
const { MODEL_CATALOG } = modelCatalog;
|
||||
assert.strictEqual(MODEL_CATALOG.agy.models.length, 6);
|
||||
assert.strictEqual(MODEL_CATALOG.agy.models.length, 3);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -203,11 +195,11 @@ describe('Model Catalog', () => {
|
||||
});
|
||||
|
||||
describe('findModel', () => {
|
||||
it('finds Claude Opus 4.5 Thinking in agy', () => {
|
||||
it('finds Claude Opus 4.6 Thinking in agy', () => {
|
||||
const { findModel } = modelCatalog;
|
||||
const model = findModel('agy', 'claude-opus-4-5-thinking');
|
||||
const model = findModel('agy', 'claude-opus-4-6-thinking');
|
||||
assert(model, 'Should find model');
|
||||
assert.strictEqual(model.name, 'Claude Opus 4.5 Thinking');
|
||||
assert.strictEqual(model.name, 'Claude Opus 4.6 Thinking');
|
||||
});
|
||||
|
||||
it('finds Gemini 2.5 Pro in gemini', () => {
|
||||
@@ -217,6 +209,16 @@ describe('Model Catalog', () => {
|
||||
assert.strictEqual(model.name, 'Gemini 2.5 Pro');
|
||||
});
|
||||
|
||||
it('maps legacy AGY 4.5 IDs to supported 4.6 models', () => {
|
||||
const { findModel } = modelCatalog;
|
||||
const legacyOpus = findModel('agy', 'claude-opus-4-5-thinking');
|
||||
const legacySonnetThinking = findModel('agy', 'claude-sonnet-4-5-thinking');
|
||||
const legacySonnet = findModel('agy', 'claude-sonnet-4-5');
|
||||
assert.strictEqual(legacyOpus?.id, 'claude-opus-4-6-thinking');
|
||||
assert.strictEqual(legacySonnetThinking?.id, 'claude-sonnet-4-6');
|
||||
assert.strictEqual(legacySonnet?.id, 'claude-sonnet-4-6');
|
||||
});
|
||||
|
||||
it('returns undefined for unknown model', () => {
|
||||
const { findModel } = modelCatalog;
|
||||
const model = findModel('agy', 'unknown-model');
|
||||
@@ -269,19 +271,17 @@ describe('Model Catalog', () => {
|
||||
});
|
||||
|
||||
describe('Thinking models ordering', () => {
|
||||
it('Claude Opus 4.5 Thinking is not deprecated', () => {
|
||||
it('Claude Opus 4.6 Thinking is not deprecated', () => {
|
||||
const { MODEL_CATALOG } = modelCatalog;
|
||||
const opus = MODEL_CATALOG.agy.models.find((m) => m.id === 'claude-opus-4-5-thinking');
|
||||
assert(opus, 'Should include Claude Opus 4.5 Thinking');
|
||||
const opus = MODEL_CATALOG.agy.models.find((m) => m.id === 'claude-opus-4-6-thinking');
|
||||
assert(opus, 'Should include Claude Opus 4.6 Thinking');
|
||||
assert.strictEqual(opus.deprecated, undefined, 'Should not be marked as deprecated');
|
||||
});
|
||||
|
||||
it('Claude Sonnet 4.5 Thinking is not deprecated', () => {
|
||||
it('Claude Sonnet 4.6 is not deprecated', () => {
|
||||
const { MODEL_CATALOG } = modelCatalog;
|
||||
const sonnetThinking = MODEL_CATALOG.agy.models.find(
|
||||
(m) => m.id === 'claude-sonnet-4-5-thinking'
|
||||
);
|
||||
assert(sonnetThinking, 'Should include Claude Sonnet 4.5 Thinking');
|
||||
const sonnetThinking = MODEL_CATALOG.agy.models.find((m) => m.id === 'claude-sonnet-4-6');
|
||||
assert(sonnetThinking, 'Should include Claude Sonnet 4.6');
|
||||
assert.strictEqual(
|
||||
sonnetThinking.deprecated,
|
||||
undefined,
|
||||
@@ -294,31 +294,27 @@ describe('Model Catalog', () => {
|
||||
const models = MODEL_CATALOG.agy.models;
|
||||
|
||||
// Find indices of thinking models
|
||||
const opusIdx = models.findIndex((m) => m.id === 'claude-opus-4-5-thinking');
|
||||
const sonnetThinkingIdx = models.findIndex((m) => m.id === 'claude-sonnet-4-5-thinking');
|
||||
const opusIdx = models.findIndex((m) => m.id === 'claude-opus-4-6-thinking');
|
||||
const sonnetThinkingIdx = models.findIndex((m) => m.id === 'claude-sonnet-4-6');
|
||||
|
||||
// Find indices of non-thinking models
|
||||
const sonnetIdx = models.findIndex((m) => m.id === 'claude-sonnet-4-5');
|
||||
// Find indices of the remaining non-Claude model
|
||||
const geminiIdx = models.findIndex((m) => m.id === 'gemini-3-pro-preview');
|
||||
|
||||
// Thinking models should come before non-thinking models
|
||||
assert(opusIdx < sonnetIdx, 'Opus Thinking should be above non-thinking Sonnet');
|
||||
assert(opusIdx < geminiIdx, 'Opus Thinking should be above non-thinking Gemini');
|
||||
assert(sonnetThinkingIdx < sonnetIdx, 'Sonnet Thinking should be above non-thinking Sonnet');
|
||||
assert(sonnetThinkingIdx < geminiIdx, 'Sonnet Thinking should be above non-thinking Gemini');
|
||||
// Primary Claude choices should appear ahead of Gemini fallback.
|
||||
assert(opusIdx < geminiIdx, 'Opus should be above Gemini');
|
||||
assert(sonnetThinkingIdx < geminiIdx, 'Sonnet should be above Gemini');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isModelDeprecated', () => {
|
||||
it('returns false for thinking models (no longer deprecated)', () => {
|
||||
it('returns false for active AGY Claude models', () => {
|
||||
const { isModelDeprecated } = modelCatalog;
|
||||
assert.strictEqual(isModelDeprecated('agy', 'claude-opus-4-5-thinking'), false);
|
||||
assert.strictEqual(isModelDeprecated('agy', 'claude-sonnet-4-5-thinking'), false);
|
||||
assert.strictEqual(isModelDeprecated('agy', 'claude-opus-4-6-thinking'), false);
|
||||
assert.strictEqual(isModelDeprecated('agy', 'claude-sonnet-4-6'), false);
|
||||
});
|
||||
|
||||
it('returns false for non-deprecated models', () => {
|
||||
const { isModelDeprecated } = modelCatalog;
|
||||
assert.strictEqual(isModelDeprecated('agy', 'claude-sonnet-4-5'), false);
|
||||
assert.strictEqual(isModelDeprecated('agy', 'gemini-3-pro-preview'), false);
|
||||
});
|
||||
|
||||
@@ -329,15 +325,15 @@ describe('Model Catalog', () => {
|
||||
});
|
||||
|
||||
describe('getModelDeprecationReason', () => {
|
||||
it('returns undefined for thinking models (no longer deprecated)', () => {
|
||||
it('returns undefined for active AGY Claude models', () => {
|
||||
const { getModelDeprecationReason } = modelCatalog;
|
||||
assert.strictEqual(getModelDeprecationReason('agy', 'claude-opus-4-5-thinking'), undefined);
|
||||
assert.strictEqual(getModelDeprecationReason('agy', 'claude-sonnet-4-5-thinking'), undefined);
|
||||
assert.strictEqual(getModelDeprecationReason('agy', 'claude-opus-4-6-thinking'), undefined);
|
||||
assert.strictEqual(getModelDeprecationReason('agy', 'claude-sonnet-4-6'), undefined);
|
||||
});
|
||||
|
||||
it('returns undefined for non-deprecated models', () => {
|
||||
const { getModelDeprecationReason } = modelCatalog;
|
||||
assert.strictEqual(getModelDeprecationReason('agy', 'claude-sonnet-4-5'), undefined);
|
||||
assert.strictEqual(getModelDeprecationReason('agy', 'gemini-3-pro-preview'), undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -64,6 +64,13 @@ describe('model-id-normalizer', () => {
|
||||
expect(normalizeModelIdForProvider('claude-opus-4.6-thinking', 'agy')).toBe(
|
||||
'claude-opus-4-6-thinking'
|
||||
);
|
||||
expect(normalizeModelIdForProvider('claude-opus-4.5-thinking', 'agy')).toBe(
|
||||
'claude-opus-4-6-thinking'
|
||||
);
|
||||
expect(normalizeModelIdForProvider('claude-sonnet-4.5-thinking', 'agy')).toBe(
|
||||
'claude-sonnet-4-6'
|
||||
);
|
||||
expect(normalizeModelIdForProvider('claude-sonnet-4.5', 'agy')).toBe('claude-sonnet-4-6');
|
||||
expect(normalizeModelIdForProvider('claude-opus-4.6-thinking', 'gemini')).toBe(
|
||||
'claude-opus-4.6-thinking'
|
||||
);
|
||||
@@ -98,9 +105,9 @@ describe('model-id-normalizer', () => {
|
||||
describe('env normalization', () => {
|
||||
it('normalizes model env vars for antigravity only', () => {
|
||||
const input: NodeJS.ProcessEnv = {
|
||||
ANTHROPIC_MODEL: 'claude-sonnet-4.6-thinking',
|
||||
ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-4.6-thinking',
|
||||
ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-4.6',
|
||||
ANTHROPIC_MODEL: 'claude-sonnet-4.5-thinking',
|
||||
ANTHROPIC_DEFAULT_OPUS_MODEL: 'claude-opus-4.5-thinking',
|
||||
ANTHROPIC_DEFAULT_SONNET_MODEL: 'claude-sonnet-4.5',
|
||||
ANTHROPIC_DEFAULT_HAIKU_MODEL: 'claude-haiku-4.5',
|
||||
UNRELATED: 'keep-me',
|
||||
};
|
||||
@@ -113,7 +120,7 @@ describe('model-id-normalizer', () => {
|
||||
expect(normalized.UNRELATED).toBe('keep-me');
|
||||
|
||||
const unchanged = normalizeModelEnvVarsForProvider(input, 'gemini');
|
||||
expect(unchanged.ANTHROPIC_MODEL).toBe('claude-sonnet-4.6-thinking');
|
||||
expect(unchanged.ANTHROPIC_MODEL).toBe('claude-sonnet-4.5-thinking');
|
||||
expect(unchanged.UNRELATED).toBe('keep-me');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -26,17 +26,6 @@ export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
|
||||
haiku: 'claude-sonnet-4-6',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'claude-opus-4-5-thinking',
|
||||
name: 'Claude Opus 4.5 Thinking',
|
||||
description: 'Previous flagship, extended thinking',
|
||||
presetMapping: {
|
||||
default: 'claude-opus-4-5-thinking',
|
||||
opus: 'claude-opus-4-5-thinking',
|
||||
sonnet: 'claude-sonnet-4-6',
|
||||
haiku: 'claude-sonnet-4-6',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'claude-sonnet-4-6',
|
||||
name: 'Claude Sonnet 4.6',
|
||||
@@ -48,28 +37,6 @@ export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
|
||||
haiku: 'claude-sonnet-4-6',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'claude-sonnet-4-5-thinking',
|
||||
name: 'Claude Sonnet 4.5 Thinking',
|
||||
description: 'Balanced with extended thinking',
|
||||
presetMapping: {
|
||||
default: 'claude-sonnet-4-5-thinking',
|
||||
opus: 'claude-opus-4-6-thinking',
|
||||
sonnet: 'claude-sonnet-4-5-thinking',
|
||||
haiku: 'claude-sonnet-4-5',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'claude-sonnet-4-5',
|
||||
name: 'Claude Sonnet 4.5',
|
||||
description: 'Fast and capable',
|
||||
presetMapping: {
|
||||
default: 'claude-sonnet-4-5',
|
||||
opus: 'claude-opus-4-6-thinking',
|
||||
sonnet: 'claude-sonnet-4-5',
|
||||
haiku: 'claude-sonnet-4-5',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'gemini-3-pro-preview',
|
||||
name: 'Gemini 3 Pro',
|
||||
|
||||
Reference in New Issue
Block a user