fix: normalize antigravity gemini 3.1 pro routing

This commit is contained in:
zhaoteng45
2026-07-03 17:22:49 +00:00
parent 2649573b99
commit df2cedeead
6 changed files with 180 additions and 6 deletions
+8 -3
View File
@@ -68,6 +68,9 @@ const (
SubscriptionStatusSuspended = "suspended"
)
// AntigravityGemini31ProAgentModel is the upstream route for Gemini 3.1 Pro High.
const AntigravityGemini31ProAgentModel = "gemini-pro-agent"
// DefaultAntigravityModelMapping 是 Antigravity 平台的默认模型映射
// 当账号未配置 model_mapping 时使用此默认值
// 与前端 useModelWhitelist.ts 中的 antigravityDefaultMappings 保持一致
@@ -103,10 +106,12 @@ var DefaultAntigravityModelMapping = map[string]string{
"gemini-3-flash-preview": "gemini-3-flash",
"gemini-3-pro-preview": "gemini-3-pro-high",
// Gemini 3.1 白名单
"gemini-3.1-pro-high": "gemini-3.1-pro-high",
"gemini-3.1-pro-low": "gemini-3.1-pro-low",
AntigravityGemini31ProAgentModel: AntigravityGemini31ProAgentModel,
"gemini-3.1-pro": AntigravityGemini31ProAgentModel,
"gemini-3.1-pro-high": AntigravityGemini31ProAgentModel,
"gemini-3.1-pro-low": "gemini-3.1-pro-low",
// Gemini 3.1 preview 映射
"gemini-3.1-pro-preview": "gemini-3.1-pro-high",
"gemini-3.1-pro-preview": AntigravityGemini31ProAgentModel,
// Gemini 3.1 image 白名单
"gemini-3.1-flash-image": "gemini-3.1-flash-image",
// Gemini 3.1 image preview 映射
+22
View File
@@ -43,6 +43,28 @@ func TestDefaultAntigravityModelMapping_ContainsNewClaudeModels(t *testing.T) {
}
}
func TestDefaultAntigravityModelMapping_Gemini31ProAliases(t *testing.T) {
t.Parallel()
cases := map[string]string{
AntigravityGemini31ProAgentModel: AntigravityGemini31ProAgentModel,
"gemini-3.1-pro": AntigravityGemini31ProAgentModel,
"gemini-3.1-pro-high": AntigravityGemini31ProAgentModel,
"gemini-3.1-pro-preview": AntigravityGemini31ProAgentModel,
"gemini-3.1-pro-low": "gemini-3.1-pro-low",
}
for from, want := range cases {
got, ok := DefaultAntigravityModelMapping[from]
if !ok {
t.Fatalf("expected mapping for %q to exist", from)
}
if got != want {
t.Fatalf("unexpected mapping for %q: got %q want %q", from, got, want)
}
}
}
func TestDefaultBedrockModelMapping_ContainsNewClaudeModels(t *testing.T) {
t.Parallel()
+56
View File
@@ -580,6 +580,7 @@ func (a *Account) resolveModelMapping(rawMapping map[string]any) map[string]stri
"gemini-3.1-pro-high",
"gemini-3.1-pro-low",
})
applyAntigravityGemini31ProAliases(result)
}
return result
}
@@ -646,6 +647,61 @@ func ensureAntigravityDefaultPassthroughs(mapping map[string]string, models []st
}
}
func applyAntigravityGemini31ProAliases(mapping map[string]string) {
target := strings.TrimSpace(mapping[domain.AntigravityGemini31ProAgentModel])
if target == "" {
return
}
aliases := []struct {
model string
legacyTargets map[string]struct{}
}{
{
model: "gemini-3.1-pro",
legacyTargets: map[string]struct{}{
"gemini-3.1-pro": {},
},
},
{
model: "gemini-3.1-pro-high",
legacyTargets: map[string]struct{}{
"gemini-3.1-pro-high": {},
},
},
{
model: "gemini-3.1-pro-preview",
legacyTargets: map[string]struct{}{
"gemini-3.1-pro-preview": {},
"gemini-3.1-pro-high": {},
},
},
}
for _, alias := range aliases {
current, exists := mapping[alias.model]
if exists {
if _, legacy := alias.legacyTargets[current]; legacy {
mapping[alias.model] = target
}
continue
}
if mappingHasWildcardForModel(mapping, alias.model) {
continue
}
mapping[alias.model] = target
}
}
func mappingHasWildcardForModel(mapping map[string]string, model string) bool {
for pattern := range mapping {
if matchWildcard(pattern, model) {
return true
}
}
return false
}
func normalizeRequestedModelForLookup(platform, requestedModel string) string {
trimmed := strings.TrimSpace(requestedModel)
if trimmed == "" {
@@ -4,6 +4,8 @@ package service
import (
"testing"
"github.com/Wei-Shaw/sub2api/internal/domain"
)
func TestMatchWildcard(t *testing.T) {
@@ -320,6 +322,86 @@ func TestAccountGetMappedModel(t *testing.T) {
}
}
func TestAccountGetModelMapping_AntigravityNormalizesGemini31ProAliases(t *testing.T) {
t.Parallel()
account := &Account{
Platform: PlatformAntigravity,
Credentials: map[string]any{
"model_mapping": map[string]any{
domain.AntigravityGemini31ProAgentModel: domain.AntigravityGemini31ProAgentModel,
"gemini-3.1-pro-high": "gemini-3.1-pro-high",
"gemini-3.1-pro-preview": "gemini-3.1-pro-high",
},
},
}
mapping := account.GetModelMapping()
if got := mapping["gemini-3.1-pro"]; got != domain.AntigravityGemini31ProAgentModel {
t.Fatalf("expected gemini-3.1-pro to map to %q, got %q", domain.AntigravityGemini31ProAgentModel, got)
}
if got := mapping["gemini-3.1-pro-high"]; got != domain.AntigravityGemini31ProAgentModel {
t.Fatalf("expected gemini-3.1-pro-high to map to %q, got %q", domain.AntigravityGemini31ProAgentModel, got)
}
if got := mapping["gemini-3.1-pro-preview"]; got != domain.AntigravityGemini31ProAgentModel {
t.Fatalf("expected gemini-3.1-pro-preview to map to %q, got %q", domain.AntigravityGemini31ProAgentModel, got)
}
}
func TestAccountGetModelMapping_AntigravityPreservesGemini31ProOverrides(t *testing.T) {
t.Parallel()
account := &Account{
Platform: PlatformAntigravity,
Credentials: map[string]any{
"model_mapping": map[string]any{
domain.AntigravityGemini31ProAgentModel: domain.AntigravityGemini31ProAgentModel,
"gemini-3.1-pro-high": "custom-high",
"gemini-3.1-pro-preview": "custom-preview",
},
},
}
mapping := account.GetModelMapping()
if got := mapping["gemini-3.1-pro-high"]; got != "custom-high" {
t.Fatalf("expected gemini-3.1-pro-high override to be preserved, got %q", got)
}
if got := mapping["gemini-3.1-pro-preview"]; got != "custom-preview" {
t.Fatalf("expected gemini-3.1-pro-preview override to be preserved, got %q", got)
}
if got := mapping["gemini-3.1-pro"]; got != domain.AntigravityGemini31ProAgentModel {
t.Fatalf("expected gemini-3.1-pro alias to default to %q, got %q", domain.AntigravityGemini31ProAgentModel, got)
}
}
func TestAccountGetModelMapping_AntigravityGemini31ProAliasesRespectWildcard(t *testing.T) {
t.Parallel()
account := &Account{
Platform: PlatformAntigravity,
Credentials: map[string]any{
"model_mapping": map[string]any{
domain.AntigravityGemini31ProAgentModel: domain.AntigravityGemini31ProAgentModel,
"gemini-3.1-*": "custom-wildcard",
},
},
}
mapping := account.GetModelMapping()
if got := mapping["gemini-3.1-pro"]; got != "" {
t.Fatalf("expected gemini-3.1-pro exact alias to stay unset when wildcard exists, got %q", got)
}
if got := mapping["gemini-3.1-pro-high"]; got != "" {
t.Fatalf("expected gemini-3.1-pro-high exact alias to stay unset when wildcard exists, got %q", got)
}
if got := mapping["gemini-3.1-pro-preview"]; got != "" {
t.Fatalf("expected gemini-3.1-pro-preview exact alias to stay unset when wildcard exists, got %q", got)
}
}
func TestAccountResolveMappedModel(t *testing.T) {
tests := []struct {
name string