Unverified Commit 4514f3fc authored by YanzheL's avatar YanzheL
Browse files

fix(gemini): resolve customtools alias in mapping lookup

parent 095bef95
......@@ -515,18 +515,27 @@ func ensureAntigravityDefaultPassthroughs(mapping map[string]string, models []st
}
}
// IsModelSupported 检查模型是否在 model_mapping 中(支持通配符)
// 如果未配置 mapping,返回 true(允许所有模型)
func (a *Account) IsModelSupported(requestedModel string) bool {
mapping := a.GetModelMapping()
if len(mapping) == 0 {
return true // 无映射 = 允许所有
func normalizeRequestedModelForLookup(platform, requestedModel string) string {
trimmed := strings.TrimSpace(requestedModel)
if trimmed == "" {
return ""
}
if platform != PlatformGemini && platform != PlatformAntigravity {
return trimmed
}
if trimmed == "gemini-3.1-pro-preview-customtools" {
return "gemini-3.1-pro-preview"
}
return trimmed
}
func mappingSupportsRequestedModel(mapping map[string]string, requestedModel string) bool {
if requestedModel == "" {
return false
}
// 精确匹配
if _, exists := mapping[requestedModel]; exists {
return true
}
// 通配符匹配
for pattern := range mapping {
if matchWildcard(pattern, requestedModel) {
return true
......@@ -535,6 +544,30 @@ func (a *Account) IsModelSupported(requestedModel string) bool {
return false
}
func resolveRequestedModelInMapping(mapping map[string]string, requestedModel string) (mappedModel string, matched bool) {
if requestedModel == "" {
return "", false
}
if mappedModel, exists := mapping[requestedModel]; exists {
return mappedModel, true
}
return matchWildcardMappingResult(mapping, requestedModel)
}
// IsModelSupported 检查模型是否在 model_mapping 中(支持通配符)
// 如果未配置 mapping,返回 true(允许所有模型)
func (a *Account) IsModelSupported(requestedModel string) bool {
mapping := a.GetModelMapping()
if len(mapping) == 0 {
return true // 无映射 = 允许所有
}
if mappingSupportsRequestedModel(mapping, requestedModel) {
return true
}
normalized := normalizeRequestedModelForLookup(a.Platform, requestedModel)
return normalized != requestedModel && mappingSupportsRequestedModel(mapping, normalized)
}
// GetMappedModel 获取映射后的模型名(支持通配符,最长优先匹配)
// 如果未配置 mapping,返回原始模型名
func (a *Account) GetMappedModel(requestedModel string) string {
......@@ -549,12 +582,16 @@ func (a *Account) ResolveMappedModel(requestedModel string) (mappedModel string,
if len(mapping) == 0 {
return requestedModel, false
}
// 精确匹配优先
if mappedModel, exists := mapping[requestedModel]; exists {
if mappedModel, matched := resolveRequestedModelInMapping(mapping, requestedModel); matched {
return mappedModel, true
}
// 通配符匹配(最长优先)
return matchWildcardMappingResult(mapping, requestedModel)
normalized := normalizeRequestedModelForLookup(a.Platform, requestedModel)
if normalized != requestedModel {
if mappedModel, matched := resolveRequestedModelInMapping(mapping, normalized); matched {
return mappedModel, true
}
}
return requestedModel, false
}
func (a *Account) GetBaseURL() string {
......
......@@ -133,6 +133,7 @@ func TestMatchWildcardMappingResult(t *testing.T) {
func TestAccountIsModelSupported(t *testing.T) {
tests := []struct {
name string
platform string
credentials map[string]any
requestedModel string
expected bool
......@@ -184,6 +185,17 @@ func TestAccountIsModelSupported(t *testing.T) {
requestedModel: "claude-opus-4-5-thinking",
expected: true,
},
{
name: "gemini customtools alias matches normalized mapping",
platform: PlatformGemini,
credentials: map[string]any{
"model_mapping": map[string]any{
"gemini-3.1-pro-preview": "gemini-3.1-pro-preview",
},
},
requestedModel: "gemini-3.1-pro-preview-customtools",
expected: true,
},
{
name: "wildcard match not supported",
credentials: map[string]any{
......@@ -199,6 +211,7 @@ func TestAccountIsModelSupported(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
account := &Account{
Platform: tt.platform,
Credentials: tt.credentials,
}
result := account.IsModelSupported(tt.requestedModel)
......@@ -212,6 +225,7 @@ func TestAccountIsModelSupported(t *testing.T) {
func TestAccountGetMappedModel(t *testing.T) {
tests := []struct {
name string
platform string
credentials map[string]any
requestedModel string
expected string
......@@ -223,6 +237,13 @@ func TestAccountGetMappedModel(t *testing.T) {
requestedModel: "claude-sonnet-4-5",
expected: "claude-sonnet-4-5",
},
{
name: "no mapping preserves gemini customtools model",
platform: PlatformGemini,
credentials: nil,
requestedModel: "gemini-3.1-pro-preview-customtools",
expected: "gemini-3.1-pro-preview-customtools",
},
// 精确匹配
{
......@@ -250,6 +271,29 @@ func TestAccountGetMappedModel(t *testing.T) {
},
// 无匹配返回原始模型
{
name: "gemini customtools alias resolves through normalized mapping",
platform: PlatformGemini,
credentials: map[string]any{
"model_mapping": map[string]any{
"gemini-3.1-pro-preview": "gemini-3.1-pro-preview",
},
},
requestedModel: "gemini-3.1-pro-preview-customtools",
expected: "gemini-3.1-pro-preview",
},
{
name: "gemini customtools exact mapping wins over normalized fallback",
platform: PlatformGemini,
credentials: map[string]any{
"model_mapping": map[string]any{
"gemini-3.1-pro-preview": "gemini-3.1-pro-preview",
"gemini-3.1-pro-preview-customtools": "gemini-3.1-pro-preview-customtools",
},
},
requestedModel: "gemini-3.1-pro-preview-customtools",
expected: "gemini-3.1-pro-preview-customtools",
},
{
name: "no match returns original",
credentials: map[string]any{
......@@ -265,6 +309,7 @@ func TestAccountGetMappedModel(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
account := &Account{
Platform: tt.platform,
Credentials: tt.credentials,
}
result := account.GetMappedModel(tt.requestedModel)
......@@ -278,6 +323,7 @@ func TestAccountGetMappedModel(t *testing.T) {
func TestAccountResolveMappedModel(t *testing.T) {
tests := []struct {
name string
platform string
credentials map[string]any
requestedModel string
expectedModel string
......@@ -312,6 +358,31 @@ func TestAccountResolveMappedModel(t *testing.T) {
expectedModel: "gpt-5.4",
expectedMatch: true,
},
{
name: "gemini customtools alias reports normalized match",
platform: PlatformGemini,
credentials: map[string]any{
"model_mapping": map[string]any{
"gemini-3.1-pro-preview": "gemini-3.1-pro-preview",
},
},
requestedModel: "gemini-3.1-pro-preview-customtools",
expectedModel: "gemini-3.1-pro-preview",
expectedMatch: true,
},
{
name: "gemini customtools exact mapping reports exact match",
platform: PlatformGemini,
credentials: map[string]any{
"model_mapping": map[string]any{
"gemini-3.1-pro-preview": "gemini-3.1-pro-preview",
"gemini-3.1-pro-preview-customtools": "gemini-3.1-pro-preview-customtools",
},
},
requestedModel: "gemini-3.1-pro-preview-customtools",
expectedModel: "gemini-3.1-pro-preview-customtools",
expectedMatch: true,
},
{
name: "missing mapping reports unmatched",
credentials: map[string]any{
......@@ -328,6 +399,7 @@ func TestAccountResolveMappedModel(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
account := &Account{
Platform: tt.platform,
Credentials: tt.credentials,
}
mappedModel, matched := account.ResolveMappedModel(tt.requestedModel)
......
......@@ -268,6 +268,12 @@ func TestMapAntigravityModel_WildcardTargetEqualsRequest(t *testing.T) {
requestedModel: "gemini-2.5-flash",
expected: "gemini-2.5-flash",
},
{
name: "customtools alias falls back to normalized preview mapping",
modelMapping: map[string]any{"gemini-3.1-pro-preview": "gemini-3.1-pro-high"},
requestedModel: "gemini-3.1-pro-preview-customtools",
expected: "gemini-3.1-pro-high",
},
}
for _, tt := range tests {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment