Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
4514f3fc
Unverified
Commit
4514f3fc
authored
Apr 01, 2026
by
YanzheL
Browse files
fix(gemini): resolve customtools alias in mapping lookup
parent
095bef95
Changes
3
Hide whitespace changes
Inline
Side-by-side
backend/internal/service/account.go
View file @
4514f3fc
...
@@ -515,18 +515,27 @@ func ensureAntigravityDefaultPassthroughs(mapping map[string]string, models []st
...
@@ -515,18 +515,27 @@ func ensureAntigravityDefaultPassthroughs(mapping map[string]string, models []st
}
}
}
}
// IsModelSupported 检查模型是否在 model_mapping 中(支持通配符)
func
normalizeRequestedModelForLookup
(
platform
,
requestedModel
string
)
string
{
// 如果未配置 mapping,返回 true(允许所有模型)
trimmed
:=
strings
.
TrimSpace
(
requestedModel
)
func
(
a
*
Account
)
IsModelSupported
(
requestedModel
string
)
bool
{
if
trimmed
==
""
{
mapping
:=
a
.
GetModelMapping
()
return
""
if
len
(
mapping
)
==
0
{
}
return
true
// 无映射 = 允许所有
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
{
if
_
,
exists
:=
mapping
[
requestedModel
];
exists
{
return
true
return
true
}
}
// 通配符匹配
for
pattern
:=
range
mapping
{
for
pattern
:=
range
mapping
{
if
matchWildcard
(
pattern
,
requestedModel
)
{
if
matchWildcard
(
pattern
,
requestedModel
)
{
return
true
return
true
...
@@ -535,6 +544,30 @@ func (a *Account) IsModelSupported(requestedModel string) bool {
...
@@ -535,6 +544,30 @@ func (a *Account) IsModelSupported(requestedModel string) bool {
return
false
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 获取映射后的模型名(支持通配符,最长优先匹配)
// GetMappedModel 获取映射后的模型名(支持通配符,最长优先匹配)
// 如果未配置 mapping,返回原始模型名
// 如果未配置 mapping,返回原始模型名
func
(
a
*
Account
)
GetMappedModel
(
requestedModel
string
)
string
{
func
(
a
*
Account
)
GetMappedModel
(
requestedModel
string
)
string
{
...
@@ -549,12 +582,16 @@ func (a *Account) ResolveMappedModel(requestedModel string) (mappedModel string,
...
@@ -549,12 +582,16 @@ func (a *Account) ResolveMappedModel(requestedModel string) (mappedModel string,
if
len
(
mapping
)
==
0
{
if
len
(
mapping
)
==
0
{
return
requestedModel
,
false
return
requestedModel
,
false
}
}
// 精确匹配优先
if
mappedModel
,
matched
:=
resolveRequestedModelInMapping
(
mapping
,
requestedModel
);
matched
{
if
mappedModel
,
exists
:=
mapping
[
requestedModel
];
exists
{
return
mappedModel
,
true
return
mappedModel
,
true
}
}
// 通配符匹配(最长优先)
normalized
:=
normalizeRequestedModelForLookup
(
a
.
Platform
,
requestedModel
)
return
matchWildcardMappingResult
(
mapping
,
requestedModel
)
if
normalized
!=
requestedModel
{
if
mappedModel
,
matched
:=
resolveRequestedModelInMapping
(
mapping
,
normalized
);
matched
{
return
mappedModel
,
true
}
}
return
requestedModel
,
false
}
}
func
(
a
*
Account
)
GetBaseURL
()
string
{
func
(
a
*
Account
)
GetBaseURL
()
string
{
...
...
backend/internal/service/account_wildcard_test.go
View file @
4514f3fc
...
@@ -133,6 +133,7 @@ func TestMatchWildcardMappingResult(t *testing.T) {
...
@@ -133,6 +133,7 @@ func TestMatchWildcardMappingResult(t *testing.T) {
func
TestAccountIsModelSupported
(
t
*
testing
.
T
)
{
func
TestAccountIsModelSupported
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
tests
:=
[]
struct
{
name
string
name
string
platform
string
credentials
map
[
string
]
any
credentials
map
[
string
]
any
requestedModel
string
requestedModel
string
expected
bool
expected
bool
...
@@ -184,6 +185,17 @@ func TestAccountIsModelSupported(t *testing.T) {
...
@@ -184,6 +185,17 @@ func TestAccountIsModelSupported(t *testing.T) {
requestedModel
:
"claude-opus-4-5-thinking"
,
requestedModel
:
"claude-opus-4-5-thinking"
,
expected
:
true
,
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"
,
name
:
"wildcard match not supported"
,
credentials
:
map
[
string
]
any
{
credentials
:
map
[
string
]
any
{
...
@@ -199,6 +211,7 @@ func TestAccountIsModelSupported(t *testing.T) {
...
@@ -199,6 +211,7 @@ func TestAccountIsModelSupported(t *testing.T) {
for
_
,
tt
:=
range
tests
{
for
_
,
tt
:=
range
tests
{
t
.
Run
(
tt
.
name
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
tt
.
name
,
func
(
t
*
testing
.
T
)
{
account
:=
&
Account
{
account
:=
&
Account
{
Platform
:
tt
.
platform
,
Credentials
:
tt
.
credentials
,
Credentials
:
tt
.
credentials
,
}
}
result
:=
account
.
IsModelSupported
(
tt
.
requestedModel
)
result
:=
account
.
IsModelSupported
(
tt
.
requestedModel
)
...
@@ -212,6 +225,7 @@ func TestAccountIsModelSupported(t *testing.T) {
...
@@ -212,6 +225,7 @@ func TestAccountIsModelSupported(t *testing.T) {
func
TestAccountGetMappedModel
(
t
*
testing
.
T
)
{
func
TestAccountGetMappedModel
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
tests
:=
[]
struct
{
name
string
name
string
platform
string
credentials
map
[
string
]
any
credentials
map
[
string
]
any
requestedModel
string
requestedModel
string
expected
string
expected
string
...
@@ -223,6 +237,13 @@ func TestAccountGetMappedModel(t *testing.T) {
...
@@ -223,6 +237,13 @@ func TestAccountGetMappedModel(t *testing.T) {
requestedModel
:
"claude-sonnet-4-5"
,
requestedModel
:
"claude-sonnet-4-5"
,
expected
:
"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) {
...
@@ -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"
,
name
:
"no match returns original"
,
credentials
:
map
[
string
]
any
{
credentials
:
map
[
string
]
any
{
...
@@ -265,6 +309,7 @@ func TestAccountGetMappedModel(t *testing.T) {
...
@@ -265,6 +309,7 @@ func TestAccountGetMappedModel(t *testing.T) {
for
_
,
tt
:=
range
tests
{
for
_
,
tt
:=
range
tests
{
t
.
Run
(
tt
.
name
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
tt
.
name
,
func
(
t
*
testing
.
T
)
{
account
:=
&
Account
{
account
:=
&
Account
{
Platform
:
tt
.
platform
,
Credentials
:
tt
.
credentials
,
Credentials
:
tt
.
credentials
,
}
}
result
:=
account
.
GetMappedModel
(
tt
.
requestedModel
)
result
:=
account
.
GetMappedModel
(
tt
.
requestedModel
)
...
@@ -278,6 +323,7 @@ func TestAccountGetMappedModel(t *testing.T) {
...
@@ -278,6 +323,7 @@ func TestAccountGetMappedModel(t *testing.T) {
func
TestAccountResolveMappedModel
(
t
*
testing
.
T
)
{
func
TestAccountResolveMappedModel
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
tests
:=
[]
struct
{
name
string
name
string
platform
string
credentials
map
[
string
]
any
credentials
map
[
string
]
any
requestedModel
string
requestedModel
string
expectedModel
string
expectedModel
string
...
@@ -312,6 +358,31 @@ func TestAccountResolveMappedModel(t *testing.T) {
...
@@ -312,6 +358,31 @@ func TestAccountResolveMappedModel(t *testing.T) {
expectedModel
:
"gpt-5.4"
,
expectedModel
:
"gpt-5.4"
,
expectedMatch
:
true
,
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"
,
name
:
"missing mapping reports unmatched"
,
credentials
:
map
[
string
]
any
{
credentials
:
map
[
string
]
any
{
...
@@ -328,6 +399,7 @@ func TestAccountResolveMappedModel(t *testing.T) {
...
@@ -328,6 +399,7 @@ func TestAccountResolveMappedModel(t *testing.T) {
for
_
,
tt
:=
range
tests
{
for
_
,
tt
:=
range
tests
{
t
.
Run
(
tt
.
name
,
func
(
t
*
testing
.
T
)
{
t
.
Run
(
tt
.
name
,
func
(
t
*
testing
.
T
)
{
account
:=
&
Account
{
account
:=
&
Account
{
Platform
:
tt
.
platform
,
Credentials
:
tt
.
credentials
,
Credentials
:
tt
.
credentials
,
}
}
mappedModel
,
matched
:=
account
.
ResolveMappedModel
(
tt
.
requestedModel
)
mappedModel
,
matched
:=
account
.
ResolveMappedModel
(
tt
.
requestedModel
)
...
...
backend/internal/service/antigravity_model_mapping_test.go
View file @
4514f3fc
...
@@ -268,6 +268,12 @@ func TestMapAntigravityModel_WildcardTargetEqualsRequest(t *testing.T) {
...
@@ -268,6 +268,12 @@ func TestMapAntigravityModel_WildcardTargetEqualsRequest(t *testing.T) {
requestedModel
:
"gemini-2.5-flash"
,
requestedModel
:
"gemini-2.5-flash"
,
expected
:
"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
{
for
_
,
tt
:=
range
tests
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment