Merge pull request #5920 from wucm667/fix/issue-5884-antigravity-sonnet46

fix(antigravity): define Sonnet 4.5 to 4.6 compatibility routing
This commit is contained in:
Wesley Liddick
2026-08-25 11:01:34 +08:00
committed by GitHub
6 changed files with 100 additions and 18 deletions
+3 -3
View File
@@ -105,11 +105,11 @@ var DefaultAntigravityModelMapping = map[string]string{
"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-5": "claude-sonnet-4-5", // 显式 canonical 选择透传
"claude-sonnet-4-5-thinking": "claude-sonnet-4-6", // 迁移旧兼容别名
// Claude 详细版本 ID 映射
"claude-opus-4-5-20251101": "claude-opus-4-6-thinking", // 迁移旧模型
"claude-sonnet-4-5-20250929": "claude-sonnet-4-5",
"claude-sonnet-4-5-20250929": "claude-sonnet-4-6", // 迁移旧模型
// Claude Haiku → Sonnet(无 Haiku 支持)
"claude-haiku-4-5": "claude-sonnet-4-6",
"claude-haiku-4-5-20251001": "claude-sonnet-4-6",
+15
View File
@@ -43,6 +43,21 @@ func TestDefaultAntigravityModelMapping_ContainsNewClaudeModels(t *testing.T) {
}
}
func TestDefaultAntigravityModelMapping_PreservesExplicitSonnet45AndMigratesLegacyAliases(t *testing.T) {
t.Parallel()
cases := map[string]string{
"claude-sonnet-4-5": "claude-sonnet-4-5",
"claude-sonnet-4-5-thinking": "claude-sonnet-4-6",
"claude-sonnet-4-5-20250929": "claude-sonnet-4-6",
}
for model, want := range cases {
if got := DefaultAntigravityModelMapping[model]; got != want {
t.Fatalf("expected model %q to map to %q, got %q", model, want, got)
}
}
}
func TestDefaultAntigravityModelMapping_Gemini31ProAliases(t *testing.T) {
t.Parallel()
@@ -43,8 +43,9 @@ import (
var sseDataPrefix = regexp.MustCompile(`^data:\s*`)
const (
testClaudeAPIURL = "https://api.anthropic.com/v1/messages?beta=true"
chatgptCodexAPIURL = "https://chatgpt.com/backend-api/codex/responses"
testClaudeAPIURL = "https://api.anthropic.com/v1/messages?beta=true"
chatgptCodexAPIURL = "https://chatgpt.com/backend-api/codex/responses"
defaultAntigravityTestModel = "claude-sonnet-4-6"
)
// TestEvent represents a SSE event for account testing
@@ -2311,11 +2312,7 @@ func (s *AccountTestService) routeAntigravityTest(c *gin.Context, account *Accou
func (s *AccountTestService) testAntigravityAccountConnection(c *gin.Context, account *Account, modelID string) error {
ctx := c.Request.Context()
// 默认模型:Claude 使用 claude-sonnet-4-5,Gemini 使用 gemini-3-pro-preview
testModelID := modelID
if testModelID == "" {
testModelID = "claude-sonnet-4-5"
}
testModelID := antigravityConnectionTestModel(modelID)
if s.antigravityGatewayService == nil {
return s.sendErrorAndEnd(c, "Antigravity gateway service not configured")
@@ -2346,6 +2343,13 @@ func (s *AccountTestService) testAntigravityAccountConnection(c *gin.Context, ac
return nil
}
func antigravityConnectionTestModel(modelID string) string {
if modelID == "" {
return defaultAntigravityTestModel
}
return modelID
}
// buildGeminiAPIKeyRequest builds request for Gemini API Key accounts
func (s *AccountTestService) buildGeminiAPIKeyRequest(ctx context.Context, account *Account, modelID string, payload []byte) (*http.Request, error) {
apiKey := account.GetCredential("api_key")
@@ -0,0 +1,16 @@
//go:build unit
package service
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestAntigravityConnectionTestModel(t *testing.T) {
t.Parallel()
require.Equal(t, "claude-sonnet-4-6", antigravityConnectionTestModel(""))
require.Equal(t, "gemini-3.1-pro-preview", antigravityConnectionTestModel("gemini-3.1-pro-preview"))
}
@@ -69,10 +69,10 @@ func TestAntigravityGatewayService_GetMappedModel(t *testing.T) {
expected: "claude-sonnet-4-6",
},
{
name: "默认映射 - claude-sonnet-4-5-20250929 → claude-sonnet-4-5",
name: "默认映射 - claude-sonnet-4-5-20250929 → claude-sonnet-4-6",
requestedModel: "claude-sonnet-4-5-20250929",
accountMapping: nil,
expected: "claude-sonnet-4-5",
expected: "claude-sonnet-4-6",
},
// 3. 默认映射中的透传(映射到自己)
@@ -89,7 +89,7 @@ func TestAntigravityGatewayService_GetMappedModel(t *testing.T) {
expected: "claude-sonnet-4-6",
},
{
name: "默认映射透传 - claude-sonnet-4-5",
name: "显式 canonical 选择 - claude-sonnet-4-5 透传",
requestedModel: "claude-sonnet-4-5",
accountMapping: nil,
expected: "claude-sonnet-4-5",
@@ -113,10 +113,19 @@ 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-sonnet-4-6",
requestedModel: "claude-sonnet-4-5-thinking",
accountMapping: nil,
expected: "claude-sonnet-4-5-thinking",
expected: "claude-sonnet-4-6",
},
{
name: "账户显式目标只映射一步 - custom-sonnet → claude-sonnet-4-5",
requestedModel: "custom-sonnet",
accountMapping: map[string]string{
"custom-sonnet": "claude-sonnet-4-5",
"claude-sonnet-4-5": "claude-sonnet-4-6",
},
expected: "claude-sonnet-4-5",
},
{
name: "默认映射透传 - gemini-2.5-flash",
@@ -844,17 +844,28 @@ func TestSetAntigravityModelRateLimits_GeminiWritesFamilyScope(t *testing.T) {
require.Equal(t, antigravityGeminiModelRateLimitKey, repo.modelRateLimitCalls[1].modelKey)
}
func TestSetAntigravityModelRateLimits_ClaudeDoesNotWriteGeminiScope(t *testing.T) {
func TestSetAntigravityModelRateLimits_DoesNotDoubleMapCustomChain(t *testing.T) {
repo := &stubAntigravityAccountRepo{}
svc := &AntigravityGatewayService{}
account := &Account{ID: 790, Platform: PlatformAntigravity}
account := &Account{
ID: 790,
Platform: PlatformAntigravity,
Credentials: map[string]any{
"model_mapping": map[string]any{
"custom-sonnet": "claude-sonnet-4-5",
"claude-sonnet-4-5": "claude-sonnet-4-6",
},
},
}
resetAt := time.Now().Add(30 * time.Second)
canonicalModel := resolveFinalAntigravityModelKey(context.Background(), account, "custom-sonnet")
require.Equal(t, "claude-sonnet-4-5", canonicalModel)
success := svc.setAntigravityModelRateLimits(
context.Background(),
repo,
account,
"claude-sonnet-4-5",
canonicalModel,
"[test]",
429,
resetAt,
@@ -866,6 +877,33 @@ func TestSetAntigravityModelRateLimits_ClaudeDoesNotWriteGeminiScope(t *testing.
require.Equal(t, "claude-sonnet-4-5", repo.modelRateLimitCalls[0].modelKey)
}
func TestSetModelRateLimitAndClearSession_UsesUpstreamReportedModelMetadata(t *testing.T) {
repo := &stubAntigravityAccountRepo{}
svc := &AntigravityGatewayService{accountRepo: repo}
account := &Account{
ID: 791,
Platform: PlatformAntigravity,
Credentials: map[string]any{
"model_mapping": map[string]any{
"claude-sonnet-4-5": "claude-sonnet-4-6",
},
},
}
svc.setModelRateLimitAndClearSession(&handleModelRateLimitParams{
ctx: context.Background(),
prefix: "[test]",
account: account,
statusCode: 429,
}, &antigravitySmartRetryInfo{
RetryDelay: 30 * time.Second,
ModelName: "claude-sonnet-4-5",
})
require.Len(t, repo.modelRateLimitCalls, 1)
require.Equal(t, "claude-sonnet-4-5", repo.modelRateLimitCalls[0].modelKey)
}
func TestAntigravityRetryLoop_PreCheck_SwitchesWhenRateLimited(t *testing.T) {
upstream := &recordingOKUpstream{}
account := &Account{