feat: migrate all Sonnet targets to Opus 4.6-thinking

All Claude Sonnet models (claude-sonnet-4-5, claude-sonnet-4-5-thinking,
claude-sonnet-4-6) in Antigravity default mapping now redirect to
claude-opus-4-6-thinking. Includes DB migration script for existing accounts.
This commit is contained in:
erio
2026-03-23 19:38:55 +08:00
parent 8cbfe9dcc6
commit 36d99d6399
11 changed files with 119 additions and 80 deletions
+7 -7
View File
@@ -75,15 +75,15 @@ var DefaultAntigravityModelMapping = map[string]string{
"claude-opus-4-6-thinking": "claude-opus-4-6-thinking", // 官方模型
"claude-opus-4-6": "claude-opus-4-6-thinking", // 简称映射
"claude-opus-4-5-thinking": "claude-opus-4-6-thinking", // 迁移旧模型
"claude-sonnet-4-6": "claude-sonnet-4-6",
"claude-sonnet-4-5": "claude-sonnet-4-5",
"claude-sonnet-4-5-thinking": "claude-sonnet-4-5-thinking",
"claude-sonnet-4-6": "claude-opus-4-6-thinking", // Sonnet → Opus
"claude-sonnet-4-5": "claude-opus-4-6-thinking", // Sonnet → Opus
"claude-sonnet-4-5-thinking": "claude-opus-4-6-thinking", // Sonnet → Opus
// Claude 详细版本 ID 映射
"claude-opus-4-5-20251101": "claude-opus-4-6-thinking", // 迁移旧模型
"claude-sonnet-4-5-20250929": "claude-sonnet-4-5",
// Claude Haiku → Sonnet(无 Haiku 支持)
"claude-haiku-4-5": "claude-sonnet-4-6",
"claude-haiku-4-5-20251001": "claude-sonnet-4-6",
"claude-sonnet-4-5-20250929": "claude-opus-4-6-thinking", // Sonnet → Opus
// Claude Haiku → Opus(无 Haiku/Sonnet 支持)
"claude-haiku-4-5": "claude-opus-4-6-thinking",
"claude-haiku-4-5-20251001": "claude-opus-4-6-thinking",
// Gemini 2.5 白名单
"gemini-2.5-flash": "gemini-2.5-flash",
"gemini-2.5-flash-image": "gemini-2.5-flash-image",
@@ -239,7 +239,7 @@ func TestAntigravityRetryLoop_ModelRateLimited_InjectsCredits(t *testing.T) {
Extra: map[string]any{
"allow_overages": true,
modelRateLimitsKey: map[string]any{
"claude-sonnet-4-5": map[string]any{
"claude-opus-4-6-thinking": map[string]any{
"rate_limited_at": time.Now().UTC().Format(time.RFC3339),
"rate_limit_reset_at": time.Now().Add(30 * time.Minute).UTC().Format(time.RFC3339),
},
@@ -254,9 +254,9 @@ func TestAntigravityRetryLoop_ModelRateLimited_InjectsCredits(t *testing.T) {
account: account,
accessToken: "token",
action: "generateContent",
body: []byte(`{"model":"claude-sonnet-4-5","request":{}}`),
body: []byte(`{"model":"claude-opus-4-6-thinking","request":{}}`),
httpUpstream: upstream,
requestedModel: "claude-sonnet-4-5",
requestedModel: "claude-opus-4-6-thinking",
handleError: func(ctx context.Context, prefix string, account *Account, statusCode int, headers http.Header, body []byte, requestedModel string, groupID int64, sessionHash string, isStickySession bool) *handleModelRateLimitResult {
return nil
},
@@ -290,7 +290,7 @@ func TestAntigravityRetryLoop_CreditsExhausted_DoesNotInject(t *testing.T) {
Extra: map[string]any{
"allow_overages": true,
modelRateLimitsKey: map[string]any{
"claude-sonnet-4-5": map[string]any{
"claude-opus-4-6-thinking": map[string]any{
"rate_limited_at": time.Now().UTC().Format(time.RFC3339),
"rate_limit_reset_at": time.Now().Add(30 * time.Minute).UTC().Format(time.RFC3339),
},
@@ -309,8 +309,8 @@ func TestAntigravityRetryLoop_CreditsExhausted_DoesNotInject(t *testing.T) {
account: account,
accessToken: "token",
action: "generateContent",
body: []byte(`{"model":"claude-sonnet-4-5","request":{}}`),
requestedModel: "claude-sonnet-4-5",
body: []byte(`{"model":"claude-opus-4-6-thinking","request":{}}`),
requestedModel: "claude-opus-4-6-thinking",
handleError: func(ctx context.Context, prefix string, account *Account, statusCode int, headers http.Header, body []byte, requestedModel string, groupID int64, sessionHash string, isStickySession bool) *handleModelRateLimitResult {
return nil
},
@@ -355,7 +355,7 @@ func TestAntigravityRetryLoop_CreditErrorMarksExhausted(t *testing.T) {
Extra: map[string]any{
"allow_overages": true,
modelRateLimitsKey: map[string]any{
"claude-sonnet-4-5": map[string]any{
"claude-opus-4-6-thinking": map[string]any{
"rate_limited_at": time.Now().UTC().Format(time.RFC3339),
"rate_limit_reset_at": time.Now().Add(30 * time.Minute).UTC().Format(time.RFC3339),
},
@@ -370,10 +370,10 @@ func TestAntigravityRetryLoop_CreditErrorMarksExhausted(t *testing.T) {
account: account,
accessToken: "token",
action: "generateContent",
body: []byte(`{"model":"claude-sonnet-4-5","request":{}}`),
body: []byte(`{"model":"claude-opus-4-6-thinking","request":{}}`),
httpUpstream: upstream,
accountRepo: repo,
requestedModel: "claude-sonnet-4-5",
requestedModel: "claude-opus-4-6-thinking",
handleError: func(ctx context.Context, prefix string, account *Account, statusCode int, headers http.Header, body []byte, requestedModel string, groupID int64, sessionHash string, isStickySession bool) *handleModelRateLimitResult {
return nil
},
@@ -977,14 +977,8 @@ func (s *AntigravityGatewayService) getMappedModel(account *Account, requestedMo
}
// applyThinkingModelSuffix 根据 thinking 配置调整模型名
// 当映射结果是 claude-sonnet-4-5 且请求开启了 thinking 时,改为 claude-sonnet-4-5-thinking
// 所有 Sonnet 已统一映射到 Opus,此函数保留为扩展点
func applyThinkingModelSuffix(mappedModel string, thinkingEnabled bool) string {
if !thinkingEnabled {
return mappedModel
}
if mappedModel == "claude-sonnet-4-5" {
return "claude-sonnet-4-5-thinking"
}
return mappedModel
}
@@ -57,36 +57,36 @@ func TestAntigravityGatewayService_GetMappedModel(t *testing.T) {
expected: "claude-opus-4-6-thinking",
},
{
name: "默认映射 - claude-haiku-4-5 → claude-sonnet-4-6",
name: "默认映射 - claude-haiku-4-5 → claude-opus-4-6-thinking",
requestedModel: "claude-haiku-4-5",
accountMapping: nil,
expected: "claude-sonnet-4-6",
expected: "claude-opus-4-6-thinking",
},
{
name: "默认映射 - claude-haiku-4-5-20251001 → claude-sonnet-4-6",
name: "默认映射 - claude-haiku-4-5-20251001 → claude-opus-4-6-thinking",
requestedModel: "claude-haiku-4-5-20251001",
accountMapping: nil,
expected: "claude-sonnet-4-6",
expected: "claude-opus-4-6-thinking",
},
{
name: "默认映射 - claude-sonnet-4-5-20250929 → claude-sonnet-4-5",
name: "默认映射 - claude-sonnet-4-5-20250929 → claude-opus-4-6-thinking",
requestedModel: "claude-sonnet-4-5-20250929",
accountMapping: nil,
expected: "claude-sonnet-4-5",
expected: "claude-opus-4-6-thinking",
},
// 3. 默认映射中的透传(映射到自己)
// 3. 默认映射 - Sonnet → Opus
{
name: "默认映射透传 - claude-sonnet-4-6",
name: "默认映射 - claude-sonnet-4-6 → claude-opus-4-6-thinking",
requestedModel: "claude-sonnet-4-6",
accountMapping: nil,
expected: "claude-sonnet-4-6",
expected: "claude-opus-4-6-thinking",
},
{
name: "默认映射透传 - claude-sonnet-4-5",
name: "默认映射 - claude-sonnet-4-5 → claude-opus-4-6-thinking",
requestedModel: "claude-sonnet-4-5",
accountMapping: nil,
expected: "claude-sonnet-4-5",
expected: "claude-opus-4-6-thinking",
},
{
name: "默认映射透传 - claude-opus-4-6-thinking",
@@ -95,10 +95,10 @@ func TestAntigravityGatewayService_GetMappedModel(t *testing.T) {
expected: "claude-opus-4-6-thinking",
},
{
name: "默认映射透传 - claude-sonnet-4-5-thinking",
name: "默认映射 - claude-sonnet-4-5-thinking → claude-opus-4-6-thinking",
requestedModel: "claude-sonnet-4-5-thinking",
accountMapping: nil,
expected: "claude-sonnet-4-5-thinking",
expected: "claude-opus-4-6-thinking",
},
{
name: "默认映射透传 - gemini-2.5-flash",
@@ -202,10 +202,11 @@ func TestHandleUpstreamError_429_NonModelRateLimit(t *testing.T) {
result := svc.handleUpstreamError(context.Background(), "[test]", account, http.StatusTooManyRequests, http.Header{}, body, "claude-sonnet-4-5", 0, "", false)
// handleModelRateLimit 不会处理(因为没有 RATE_LIMIT_EXCEEDED),
// 但 429 兜底逻辑会使用 requestedModel 设置模型级限流
// 但 429 兜底逻辑会使用 requestedModel 经过映射后的最终模型 key 设置模型级限流
// claude-sonnet-4-5 在默认映射中映射到 claude-opus-4-6-thinking
require.Nil(t, result)
require.Len(t, repo.modelRateLimitCalls, 1)
require.Equal(t, "claude-sonnet-4-5", repo.modelRateLimitCalls[0].modelKey)
require.Equal(t, "claude-opus-4-6-thinking", repo.modelRateLimitCalls[0].modelKey)
}
// TestHandleUpstreamError_429_NonModelRateLimit_UsesMappedModelKey 测试 429 非模型限流场景
@@ -822,6 +823,7 @@ func TestSetModelRateLimitByModelName_NotConvertToScope(t *testing.T) {
func TestAntigravityRetryLoop_PreCheck_SwitchesWhenRateLimited(t *testing.T) {
upstream := &recordingOKUpstream{}
// 限流 key 使用映射后的最终模型名:claude-sonnet-4-5 → claude-opus-4-6-thinking
account := &Account{
ID: 1,
Name: "acc-1",
@@ -831,7 +833,7 @@ func TestAntigravityRetryLoop_PreCheck_SwitchesWhenRateLimited(t *testing.T) {
Concurrency: 1,
Extra: map[string]any{
modelRateLimitsKey: map[string]any{
"claude-sonnet-4-5": map[string]any{
"claude-opus-4-6-thinking": map[string]any{
"rate_limit_reset_at": time.Now().Add(2 * time.Second).Format(time.RFC3339),
},
},
@@ -865,6 +867,7 @@ func TestAntigravityRetryLoop_PreCheck_SwitchesWhenRateLimited(t *testing.T) {
func TestAntigravityRetryLoop_PreCheck_SwitchesWhenRemainingLong(t *testing.T) {
upstream := &recordingOKUpstream{}
// 限流 key 使用映射后的最终模型名:claude-sonnet-4-5 → claude-opus-4-6-thinking
account := &Account{
ID: 2,
Name: "acc-2",
@@ -874,7 +877,7 @@ func TestAntigravityRetryLoop_PreCheck_SwitchesWhenRemainingLong(t *testing.T) {
Concurrency: 1,
Extra: map[string]any{
modelRateLimitsKey: map[string]any{
"claude-sonnet-4-5": map[string]any{
"claude-opus-4-6-thinking": map[string]any{
"rate_limit_reset_at": time.Now().Add(11 * time.Second).Format(time.RFC3339),
},
},
@@ -678,6 +678,7 @@ func TestHandleSingleAccountRetryInPlace_NetworkError_ContinuesRetry(t *testing.
// 预检查中,如果有 SingleAccountRetry 标记,即使账号已限流也跳过直接发请求
func TestAntigravityRetryLoop_PreCheck_SingleAccountRetry_SkipsRateLimit(t *testing.T) {
// 创建一个已设模型限流的账号
// 限流 key 使用映射后的最终模型名:claude-sonnet-4-5 → claude-opus-4-6-thinking
upstream := &recordingOKUpstream{}
account := &Account{
ID: 20,
@@ -689,7 +690,7 @@ func TestAntigravityRetryLoop_PreCheck_SingleAccountRetry_SkipsRateLimit(t *test
Concurrency: 1,
Extra: map[string]any{
modelRateLimitsKey: map[string]any{
"claude-sonnet-4-5": map[string]any{
"claude-opus-4-6-thinking": map[string]any{
"rate_limit_reset_at": time.Now().Add(30 * time.Second).Format(time.RFC3339),
},
},
@@ -723,6 +724,7 @@ func TestAntigravityRetryLoop_PreCheck_SingleAccountRetry_SkipsRateLimit(t *test
// 对照组:无 SingleAccountRetry + 已限流 → 预检查返回 switchError
func TestAntigravityRetryLoop_PreCheck_NoSingleAccountRetry_SwitchesOnRateLimit(t *testing.T) {
upstream := &recordingOKUpstream{}
// 限流 key 使用映射后的最终模型名:claude-sonnet-4-5 → claude-opus-4-6-thinking
account := &Account{
ID: 21,
Name: "acc-rate-limited-multi",
@@ -733,7 +735,7 @@ func TestAntigravityRetryLoop_PreCheck_NoSingleAccountRetry_SwitchesOnRateLimit(
Concurrency: 1,
Extra: map[string]any{
modelRateLimitsKey: map[string]any{
"claude-sonnet-4-5": map[string]any{
"claude-opus-4-6-thinking": map[string]any{
"rate_limit_reset_at": time.Now().Add(30 * time.Second).Format(time.RFC3339),
},
},
@@ -13,37 +13,15 @@ func TestApplyThinkingModelSuffix(t *testing.T) {
thinkingEnabled bool
expected string
}{
// Thinking 未开启:保持原样
// 函数现在直接返回原值(所有 Sonnet 已在映射层统一到 Opus)
{
name: "thinking disabled - claude-sonnet-4-5 unchanged",
mappedModel: "claude-sonnet-4-5",
thinkingEnabled: false,
expected: "claude-sonnet-4-5",
},
{
name: "thinking disabled - other model unchanged",
name: "thinking disabled - model unchanged",
mappedModel: "claude-opus-4-6-thinking",
thinkingEnabled: false,
expected: "claude-opus-4-6-thinking",
},
// Thinking 开启 + claude-sonnet-4-5:自动添加后缀
{
name: "thinking enabled - claude-sonnet-4-5 becomes thinking version",
mappedModel: "claude-sonnet-4-5",
thinkingEnabled: true,
expected: "claude-sonnet-4-5-thinking",
},
// Thinking 开启 + 其他模型:保持原样
{
name: "thinking enabled - claude-sonnet-4-5-thinking unchanged",
mappedModel: "claude-sonnet-4-5-thinking",
thinkingEnabled: true,
expected: "claude-sonnet-4-5-thinking",
},
{
name: "thinking enabled - claude-opus-4-6-thinking unchanged",
name: "thinking enabled - model unchanged",
mappedModel: "claude-opus-4-6-thinking",
thinkingEnabled: true,
expected: "claude-opus-4-6-thinking",
@@ -103,7 +103,7 @@ func TestGatewayService_isModelSupportedByAccountWithContext_ThinkingMode(t *tes
expected: false,
},
// 场景 3: 配置 claude-sonnet-4-5(非 thinking),请求 claude-sonnet-4-5 + thinking=true
// 最终模型名 = claude-sonnet-4-5-thinking,不在 mapping 中,应该不匹配
// applyThinkingModelSuffix 不再做转换,所以 finalModel == mapped,映射直接通过
{
name: "thinking_enabled_no_match_non_thinking_mapping",
modelMapping: map[string]any{
@@ -111,6 +111,16 @@ func TestGatewayService_isModelSupportedByAccountWithContext_ThinkingMode(t *tes
},
requestedModel: "claude-sonnet-4-5",
thinkingEnabled: true,
expected: true, // applyThinkingModelSuffix 不做转换,映射通过
},
// 场景 3b: 请求一个不在映射中的模型,thinking=true 时也不应支持
{
name: "thinking_enabled_unmapped_model_returns_false",
modelMapping: map[string]any{
"claude-sonnet-4-5": "claude-sonnet-4-5",
},
requestedModel: "claude-unknown-model",
thinkingEnabled: true,
expected: false,
},
// 场景 4: 配置两种模型,请求 claude-sonnet-4-5 + thinking=true,应该匹配 thinking 版本
@@ -181,11 +181,13 @@ func TestIsModelRateLimited_Antigravity_ThinkingAffectsModelKey(t *testing.T) {
now := time.Now()
future := now.Add(10 * time.Minute).Format(time.RFC3339)
// applyThinkingModelSuffix 不再做转换,claude-sonnet-4-5 在默认映射中映射到 claude-opus-4-6-thinking
// 所以限流 key 应为 claude-opus-4-6-thinking
account := &Account{
Platform: PlatformAntigravity,
Extra: map[string]any{
modelRateLimitsKey: map[string]any{
"claude-sonnet-4-5-thinking": map[string]any{
"claude-opus-4-6-thinking": map[string]any{
"rate_limit_reset_at": future,
},
},
@@ -343,7 +345,8 @@ func TestGetRateLimitRemainingTime(t *testing.T) {
Platform: PlatformAntigravity,
Extra: map[string]any{
modelRateLimitsKey: map[string]any{
"claude-sonnet-4-5": map[string]any{
// claude-sonnet-4-5 在默认映射中映射到 claude-opus-4-6-thinking
"claude-opus-4-6-thinking": map[string]any{
"rate_limit_reset_at": future15m,
},
},
@@ -359,7 +362,8 @@ func TestGetRateLimitRemainingTime(t *testing.T) {
Platform: PlatformAntigravity,
Extra: map[string]any{
modelRateLimitsKey: map[string]any{
"claude-sonnet-4-5": map[string]any{
// claude-sonnet-4-5 在默认映射中映射到 claude-opus-4-6-thinking
"claude-opus-4-6-thinking": map[string]any{
"rate_limit_reset_at": future5m,
},
},
@@ -0,0 +1,51 @@
-- Migrate all Sonnet models target to Opus 4.6-thinking
--
-- Background:
-- We no longer use Sonnet models on Antigravity platform.
-- All Sonnet targets (claude-sonnet-4-5, claude-sonnet-4-5-thinking, claude-sonnet-4-6)
-- are replaced with claude-opus-4-6-thinking.
--
-- Strategy:
-- Directly overwrite the entire model_mapping with updated mappings
-- This ensures consistency with DefaultAntigravityModelMapping in constants.go
UPDATE accounts
SET credentials = jsonb_set(
credentials,
'{model_mapping}',
'{
"claude-opus-4-6-thinking": "claude-opus-4-6-thinking",
"claude-opus-4-6": "claude-opus-4-6-thinking",
"claude-opus-4-5-thinking": "claude-opus-4-6-thinking",
"claude-opus-4-5-20251101": "claude-opus-4-6-thinking",
"claude-sonnet-4-6": "claude-opus-4-6-thinking",
"claude-sonnet-4-5": "claude-opus-4-6-thinking",
"claude-sonnet-4-5-thinking": "claude-opus-4-6-thinking",
"claude-sonnet-4-5-20250929": "claude-opus-4-6-thinking",
"claude-haiku-4-5": "claude-opus-4-6-thinking",
"claude-haiku-4-5-20251001": "claude-opus-4-6-thinking",
"gemini-2.5-flash": "gemini-2.5-flash",
"gemini-2.5-flash-image": "gemini-2.5-flash-image",
"gemini-2.5-flash-image-preview": "gemini-2.5-flash-image",
"gemini-2.5-flash-lite": "gemini-2.5-flash-lite",
"gemini-2.5-flash-thinking": "gemini-2.5-flash-thinking",
"gemini-2.5-pro": "gemini-2.5-pro",
"gemini-3-flash": "gemini-3-flash",
"gemini-3-pro-high": "gemini-3-pro-high",
"gemini-3-pro-low": "gemini-3-pro-low",
"gemini-3-flash-preview": "gemini-3-flash",
"gemini-3-pro-preview": "gemini-3-pro-high",
"gemini-3.1-pro-high": "gemini-3.1-pro-high",
"gemini-3.1-pro-low": "gemini-3.1-pro-low",
"gemini-3.1-pro-preview": "gemini-3.1-pro-high",
"gemini-3.1-flash-image": "gemini-3.1-flash-image",
"gemini-3.1-flash-image-preview": "gemini-3.1-flash-image",
"gemini-3-pro-image": "gemini-3.1-flash-image",
"gemini-3-pro-image-preview": "gemini-3.1-flash-image",
"gpt-oss-120b-medium": "gpt-oss-120b-medium",
"tab_flash_lite_preview": "tab_flash_lite_preview"
}'::jsonb
)
WHERE platform = 'antigravity'
AND deleted_at IS NULL
AND credentials->'model_mapping' IS NOT NULL;
@@ -301,14 +301,11 @@ const geminiPresetMappings = [
// Antigravity 预设映射(支持通配符)
const antigravityPresetMappings = [
// Claude 通配符映射
{ label: 'Claude→Sonnet', from: 'claude-*', to: 'claude-sonnet-4-5', color: 'bg-blue-100 text-blue-700 hover:bg-blue-200 dark:bg-blue-900/30 dark:text-blue-400' },
{ label: 'Sonnet→Sonnet', from: 'claude-sonnet-*', to: 'claude-sonnet-4-5', color: 'bg-indigo-100 text-indigo-700 hover:bg-indigo-200 dark:bg-indigo-900/30 dark:text-indigo-400' },
// Claude 通配符映射(所有 Claude 统一指向 Opus)
{ label: 'Claude→Opus', from: 'claude-*', to: 'claude-opus-4-6-thinking', color: 'bg-purple-100 text-purple-700 hover:bg-purple-200 dark:bg-purple-900/30 dark:text-purple-400' },
{ label: 'Sonnet→Opus', from: 'claude-sonnet-*', to: 'claude-opus-4-6-thinking', color: 'bg-indigo-100 text-indigo-700 hover:bg-indigo-200 dark:bg-indigo-900/30 dark:text-indigo-400' },
{ label: 'Opus→Opus', from: 'claude-opus-*', to: 'claude-opus-4-6-thinking', color: 'bg-purple-100 text-purple-700 hover:bg-purple-200 dark:bg-purple-900/30 dark:text-purple-400' },
{ label: 'Haiku→Sonnet', from: 'claude-haiku-*', to: 'claude-sonnet-4-5', color: 'bg-emerald-100 text-emerald-700 hover:bg-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-400' },
{ label: 'Sonnet4→4.6', from: 'claude-sonnet-4-20250514', to: 'claude-sonnet-4-6', color: 'bg-sky-100 text-sky-700 hover:bg-sky-200 dark:bg-sky-900/30 dark:text-sky-400' },
{ label: 'Sonnet4.5→4.6', from: 'claude-sonnet-4-5-20250929', to: 'claude-sonnet-4-6', color: 'bg-cyan-100 text-cyan-700 hover:bg-cyan-200 dark:bg-cyan-900/30 dark:text-cyan-400' },
{ label: 'Sonnet3.5→4.6', from: 'claude-3-5-sonnet-20241022', to: 'claude-sonnet-4-6', color: 'bg-teal-100 text-teal-700 hover:bg-teal-200 dark:bg-teal-900/30 dark:text-teal-400' },
{ label: 'Haiku→Opus', from: 'claude-haiku-*', to: 'claude-opus-4-6-thinking', color: 'bg-emerald-100 text-emerald-700 hover:bg-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-400' },
{ label: 'Opus4.5→4.6', from: 'claude-opus-4-5-20251101', to: 'claude-opus-4-6-thinking', color: 'bg-violet-100 text-violet-700 hover:bg-violet-200 dark:bg-violet-900/30 dark:text-violet-400' },
// Gemini 3→3.1 映射
{ label: '3-Pro-Preview→3.1-Pro-High', from: 'gemini-3-pro-preview', to: 'gemini-3.1-pro-high', color: 'bg-amber-100 text-amber-700 hover:bg-amber-200 dark:bg-amber-900/30 dark:text-amber-400' },
@@ -325,8 +322,8 @@ const antigravityPresetMappings = [
{ label: '3-Flash透传', from: 'gemini-3-flash', to: 'gemini-3-flash', color: 'bg-lime-100 text-lime-700 hover:bg-lime-200 dark:bg-lime-900/30 dark:text-lime-400' },
{ label: '2.5-Flash-Lite透传', from: 'gemini-2.5-flash-lite', to: 'gemini-2.5-flash-lite', color: 'bg-green-100 text-green-700 hover:bg-green-200 dark:bg-green-900/30 dark:text-green-400' },
// 精确映射
{ label: 'Sonnet 4.6', from: 'claude-sonnet-4-6', to: 'claude-sonnet-4-6', color: 'bg-cyan-100 text-cyan-700 hover:bg-cyan-200 dark:bg-cyan-900/30 dark:text-cyan-400' },
{ label: 'Sonnet 4.5', from: 'claude-sonnet-4-5', to: 'claude-sonnet-4-5', color: 'bg-cyan-100 text-cyan-700 hover:bg-cyan-200 dark:bg-cyan-900/30 dark:text-cyan-400' },
{ label: 'Sonnet 4.6→Opus', from: 'claude-sonnet-4-6', to: 'claude-opus-4-6-thinking', color: 'bg-cyan-100 text-cyan-700 hover:bg-cyan-200 dark:bg-cyan-900/30 dark:text-cyan-400' },
{ label: 'Sonnet 4.5→Opus', from: 'claude-sonnet-4-5', to: 'claude-opus-4-6-thinking', color: 'bg-cyan-100 text-cyan-700 hover:bg-cyan-200 dark:bg-cyan-900/30 dark:text-cyan-400' },
{ label: 'Opus 4.6', from: 'claude-opus-4-6', to: 'claude-opus-4-6-thinking', color: 'bg-pink-100 text-pink-700 hover:bg-pink-200 dark:bg-pink-900/30 dark:text-pink-400' },
{ label: 'Opus 4.6-thinking', from: 'claude-opus-4-6-thinking', to: 'claude-opus-4-6-thinking', color: 'bg-pink-100 text-pink-700 hover:bg-pink-200 dark:bg-pink-900/30 dark:text-pink-400' }
]