From 63b3ca776079634fcf59f231e51ad8947795b2a0 Mon Sep 17 00:00:00 2001 From: kaitranntt Date: Sat, 6 Dec 2025 08:44:09 -0500 Subject: [PATCH] feat(cliproxy): deprecate claude thinking models in agy provider Deprecated 2 Claude thinking models: - gemini-claude-opus-4-5-thinking - gemini-claude-sonnet-4-5-thinking These models have compatibility issues with Antigravity. A new deprecation system was added with badges and warnings in the UI. --- src/cliproxy/model-catalog.ts | 49 +++++++++++--- src/cliproxy/model-config.ts | 17 ++++- tests/unit/cliproxy/model-catalog.test.js | 82 +++++++++++++++++++++++ 3 files changed, 136 insertions(+), 12 deletions(-) diff --git a/src/cliproxy/model-catalog.ts b/src/cliproxy/model-catalog.ts index f06edf46..e8b88b52 100644 --- a/src/cliproxy/model-catalog.ts +++ b/src/cliproxy/model-catalog.ts @@ -23,6 +23,10 @@ export interface ModelEntry { broken?: boolean; /** Issue URL for broken models */ issueUrl?: string; + /** Model is deprecated - show warning when selected */ + deprecated?: boolean; + /** Deprecation reason/message */ + deprecationReason?: string; } /** @@ -46,16 +50,6 @@ export const MODEL_CATALOG: Partial> = displayName: 'Antigravity', defaultModel: 'gemini-3-pro-preview', models: [ - { - id: 'gemini-claude-opus-4-5-thinking', - name: 'Claude Opus 4.5 Thinking', - description: 'Most capable, extended thinking', - }, - { - id: 'gemini-claude-sonnet-4-5-thinking', - name: 'Claude Sonnet 4.5 Thinking', - description: 'Balanced with extended thinking', - }, { id: 'gemini-claude-sonnet-4-5', name: 'Claude Sonnet 4.5', @@ -66,6 +60,22 @@ export const MODEL_CATALOG: Partial> = name: 'Gemini 3 Pro', description: 'Google latest model via Antigravity', }, + { + id: 'gemini-claude-opus-4-5-thinking', + name: 'Claude Opus 4.5 Thinking', + description: 'Most capable, extended thinking', + deprecated: true, + deprecationReason: + 'Thinking models are deprecated due to compatibility issues with Antigravity', + }, + { + id: 'gemini-claude-sonnet-4-5-thinking', + name: 'Claude Sonnet 4.5 Thinking', + description: 'Balanced with extended thinking', + deprecated: true, + deprecationReason: + 'Thinking models are deprecated due to compatibility issues with Antigravity', + }, ], }, gemini: { @@ -126,3 +136,22 @@ export function getModelIssueUrl(provider: CLIProxyProvider, modelId: string): s const model = findModel(provider, modelId); return model?.issueUrl; } + +/** + * Check if model is deprecated + */ +export function isModelDeprecated(provider: CLIProxyProvider, modelId: string): boolean { + const model = findModel(provider, modelId); + return model?.deprecated === true; +} + +/** + * Get deprecation reason for deprecated model + */ +export function getModelDeprecationReason( + provider: CLIProxyProvider, + modelId: string +): string | undefined { + const model = findModel(provider, modelId); + return model?.deprecationReason; +} diff --git a/src/cliproxy/model-config.ts b/src/cliproxy/model-config.ts index c9d8e648..b3fbebcd 100644 --- a/src/cliproxy/model-config.ts +++ b/src/cliproxy/model-config.ts @@ -67,7 +67,8 @@ function formatModelOption(model: ModelEntry): string { // Tier badge: clarify that "paid" means paid Google account (not free tier) const tierBadge = model.tier === 'paid' ? color(' [Paid Tier]', 'warning') : ''; const brokenBadge = model.broken ? color(' [BROKEN]', 'error') : ''; - return `${model.name}${tierBadge}${brokenBadge}`; + const deprecatedBadge = model.deprecated ? color(' [DEPRECATED]', 'warning') : ''; + return `${model.name}${tierBadge}${brokenBadge}${deprecatedBadge}`; } /** @@ -78,8 +79,9 @@ function formatModelDetailed(model: ModelEntry, isCurrent: boolean): string { const name = isCurrent ? bold(model.name) : model.name; const tierBadge = model.tier === 'paid' ? color(' [Paid Tier]', 'warning') : ''; const brokenBadge = model.broken ? color(' [BROKEN]', 'error') : ''; + const deprecatedBadge = model.deprecated ? color(' [DEPRECATED]', 'warning') : ''; const desc = model.description ? dim(` - ${model.description}`) : ''; - return ` ${marker} ${name}${tierBadge}${brokenBadge}${desc}`; + return ` ${marker} ${name}${tierBadge}${brokenBadge}${deprecatedBadge}${desc}`; } /** @@ -136,6 +138,7 @@ export async function configureProviderModel( console.error( dim(' Models marked [Paid Tier] require a paid Google account (not free tier).') ); + console.error(dim(' Models marked [DEPRECATED] are not recommended for use.')); console.error(''); // Interactive selection @@ -211,6 +214,15 @@ export async function configureProviderModel( console.error(ok(`Model set to: ${bold(displayName)}`)); console.error(dim(` Config saved: ${settingsPath}`)); + // Show deprecation warning if model is deprecated + if (selectedEntry?.deprecated) { + console.error(''); + console.error(color('[!] DEPRECATION WARNING', 'warning')); + const reason = selectedEntry.deprecationReason || 'This model is deprecated'; + console.error(dim(` ${reason}`)); + console.error(dim(' Consider using a non-deprecated model for better compatibility.')); + } + // Show info for Claude models about thinking token limit if (isClaude) { console.error(''); @@ -261,6 +273,7 @@ export async function showCurrentConfig(provider: CLIProxyProvider): Promise { const isCurrent = m.id === currentModel; diff --git a/tests/unit/cliproxy/model-catalog.test.js b/tests/unit/cliproxy/model-catalog.test.js index f90fae31..ae39a1bc 100644 --- a/tests/unit/cliproxy/model-catalog.test.js +++ b/tests/unit/cliproxy/model-catalog.test.js @@ -214,4 +214,86 @@ describe('Model Catalog', () => { } }); }); + + describe('Deprecated models', () => { + it('Claude Opus 4.5 Thinking is marked as deprecated', () => { + const { MODEL_CATALOG } = modelCatalog; + const opus = MODEL_CATALOG.agy.models.find( + (m) => m.id === 'gemini-claude-opus-4-5-thinking' + ); + assert(opus, 'Should include Claude Opus 4.5 Thinking'); + assert.strictEqual(opus.deprecated, true, 'Should be marked as deprecated'); + assert(opus.deprecationReason, 'Should have deprecation reason'); + }); + + it('Claude Sonnet 4.5 Thinking is marked as deprecated', () => { + const { MODEL_CATALOG } = modelCatalog; + const sonnetThinking = MODEL_CATALOG.agy.models.find( + (m) => m.id === 'gemini-claude-sonnet-4-5-thinking' + ); + assert(sonnetThinking, 'Should include Claude Sonnet 4.5 Thinking'); + assert.strictEqual(sonnetThinking.deprecated, true, 'Should be marked as deprecated'); + assert(sonnetThinking.deprecationReason, 'Should have deprecation reason'); + }); + + it('deprecated models are at the bottom of the list', () => { + const { MODEL_CATALOG } = modelCatalog; + const models = MODEL_CATALOG.agy.models; + + // Find indices of deprecated models + const opusIdx = models.findIndex((m) => m.id === 'gemini-claude-opus-4-5-thinking'); + const sonnetThinkingIdx = models.findIndex( + (m) => m.id === 'gemini-claude-sonnet-4-5-thinking' + ); + + // Find indices of non-deprecated models + const sonnetIdx = models.findIndex((m) => m.id === 'gemini-claude-sonnet-4-5'); + const geminiIdx = models.findIndex((m) => m.id === 'gemini-3-pro-preview'); + + // Deprecated models should come after non-deprecated models + assert(opusIdx > sonnetIdx, 'Opus Thinking should be below non-deprecated Sonnet'); + assert(opusIdx > geminiIdx, 'Opus Thinking should be below non-deprecated Gemini'); + assert( + sonnetThinkingIdx > sonnetIdx, + 'Sonnet Thinking should be below non-deprecated Sonnet' + ); + assert( + sonnetThinkingIdx > geminiIdx, + 'Sonnet Thinking should be below non-deprecated Gemini' + ); + }); + }); + + describe('isModelDeprecated', () => { + it('returns true for deprecated models', () => { + const { isModelDeprecated } = modelCatalog; + assert.strictEqual(isModelDeprecated('agy', 'gemini-claude-opus-4-5-thinking'), true); + assert.strictEqual(isModelDeprecated('agy', 'gemini-claude-sonnet-4-5-thinking'), true); + }); + + it('returns false for non-deprecated models', () => { + const { isModelDeprecated } = modelCatalog; + assert.strictEqual(isModelDeprecated('agy', 'gemini-claude-sonnet-4-5'), false); + assert.strictEqual(isModelDeprecated('agy', 'gemini-3-pro-preview'), false); + }); + + it('returns false for unknown models', () => { + const { isModelDeprecated } = modelCatalog; + assert.strictEqual(isModelDeprecated('agy', 'unknown-model'), false); + }); + }); + + describe('getModelDeprecationReason', () => { + it('returns deprecation reason for deprecated models', () => { + const { getModelDeprecationReason } = modelCatalog; + const reason = getModelDeprecationReason('agy', 'gemini-claude-opus-4-5-thinking'); + assert(reason, 'Should have deprecation reason'); + assert(typeof reason === 'string', 'Reason should be a string'); + }); + + it('returns undefined for non-deprecated models', () => { + const { getModelDeprecationReason } = modelCatalog; + assert.strictEqual(getModelDeprecationReason('agy', 'gemini-claude-sonnet-4-5'), undefined); + }); + }); });