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
03dba58a
Commit
03dba58a
authored
Apr 17, 2026
by
shaw
Committed by
陈曦
Apr 17, 2026
Browse files
feat: 支持opus-4.7
parent
26b751ad
Changes
7
Show whitespace changes
Inline
Side-by-side
backend/internal/domain/constants.go
View file @
03dba58a
...
...
@@ -71,6 +71,7 @@ const (
// 与前端 useModelWhitelist.ts 中的 antigravityDefaultMappings 保持一致
var
DefaultAntigravityModelMapping
=
map
[
string
]
string
{
// Claude 白名单
"claude-opus-4-7"
:
"claude-opus-4-7"
,
// 官方模型
"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"
,
// 迁移旧模型
...
...
@@ -120,6 +121,7 @@ var DefaultAntigravityModelMapping = map[string]string{
// aws_region 自动调整为匹配的区域前缀(如 eu.、apac.、jp. 等)
var
DefaultBedrockModelMapping
=
map
[
string
]
string
{
// Claude Opus
"claude-opus-4-7"
:
"us.anthropic.claude-opus-4-7-v1"
,
"claude-opus-4-6-thinking"
:
"us.anthropic.claude-opus-4-6-v1"
,
"claude-opus-4-6"
:
"us.anthropic.claude-opus-4-6-v1"
,
"claude-opus-4-5-thinking"
:
"us.anthropic.claude-opus-4-5-20251101-v1:0"
,
...
...
backend/internal/pkg/antigravity/claude_types.go
View file @
03dba58a
...
...
@@ -154,6 +154,7 @@ var claudeModels = []modelDef{
{
ID
:
"claude-sonnet-4-5-thinking"
,
DisplayName
:
"Claude Sonnet 4.5 Thinking"
,
CreatedAt
:
"2025-09-29T00:00:00Z"
},
{
ID
:
"claude-opus-4-6"
,
DisplayName
:
"Claude Opus 4.6"
,
CreatedAt
:
"2026-02-05T00:00:00Z"
},
{
ID
:
"claude-opus-4-6-thinking"
,
DisplayName
:
"Claude Opus 4.6 Thinking"
,
CreatedAt
:
"2026-02-05T00:00:00Z"
},
{
ID
:
"claude-opus-4-7"
,
DisplayName
:
"Claude Opus 4.7"
,
CreatedAt
:
"2026-04-17T00:00:00Z"
},
{
ID
:
"claude-sonnet-4-6"
,
DisplayName
:
"Claude Sonnet 4.6"
,
CreatedAt
:
"2026-02-17T00:00:00Z"
},
}
...
...
backend/internal/pkg/antigravity/request_transformer.go
View file @
03dba58a
...
...
@@ -582,8 +582,12 @@ func maxOutputTokensLimit(model string) int {
return
maxOutputTokensUpperBound
}
func
isAntigravityOpus46Model
(
model
string
)
bool
{
return
strings
.
HasPrefix
(
strings
.
ToLower
(
model
),
"claude-opus-4-6"
)
// isAntigravityOpusHighTierModel 判断是否为高阶 Opus 模型(4.6+),
// 用于 adaptive thinking 时覆写为高预算。
func
isAntigravityOpusHighTierModel
(
model
string
)
bool
{
lower
:=
strings
.
ToLower
(
model
)
return
strings
.
HasPrefix
(
lower
,
"claude-opus-4-6"
)
||
strings
.
HasPrefix
(
lower
,
"claude-opus-4-7"
)
}
func
buildGenerationConfig
(
req
*
ClaudeRequest
)
*
GeminiGenerationConfig
{
...
...
@@ -605,12 +609,12 @@ func buildGenerationConfig(req *ClaudeRequest) *GeminiGenerationConfig {
}
// - thinking.type=enabled:budget_tokens>0 用显式预算
// - thinking.type=adaptive:
仅
在 Antigravity 的 Opus
4.6
上覆写为 (24576)
// - thinking.type=adaptive:在 Antigravity 的
高阶
Opus
(
4.6
+)
上覆写为 (24576)
budget
:=
-
1
if
req
.
Thinking
.
BudgetTokens
>
0
{
budget
=
req
.
Thinking
.
BudgetTokens
}
if
req
.
Thinking
.
Type
==
"adaptive"
&&
isAntigravityOpus
46
Model
(
req
.
Model
)
{
if
req
.
Thinking
.
Type
==
"adaptive"
&&
isAntigravityOpus
HighTier
Model
(
req
.
Model
)
{
budget
=
ClaudeAdaptiveHighThinkingBudgetTokens
}
...
...
backend/internal/pkg/claude/constants.go
View file @
03dba58a
...
...
@@ -83,6 +83,12 @@ var DefaultModels = []Model{
DisplayName
:
"Claude Opus 4.6"
,
CreatedAt
:
"2026-02-06T00:00:00Z"
,
},
{
ID
:
"claude-opus-4-7"
,
Type
:
"model"
,
DisplayName
:
"Claude Opus 4.7"
,
CreatedAt
:
"2026-04-17T00:00:00Z"
,
},
{
ID
:
"claude-sonnet-4-6"
,
Type
:
"model"
,
...
...
backend/internal/service/billing_service.go
View file @
03dba58a
...
...
@@ -191,6 +191,9 @@ func (s *BillingService) initFallbackPricing() {
// Claude 4.6 Opus (与4.5同价)
s
.
fallbackPrices
[
"claude-opus-4.6"
]
=
s
.
fallbackPrices
[
"claude-opus-4.5"
]
// Claude 4.7 Opus (暂与4.6同价,待官方定价更新)
s
.
fallbackPrices
[
"claude-opus-4.7"
]
=
s
.
fallbackPrices
[
"claude-opus-4.6"
]
// Gemini 3.1 Pro
s
.
fallbackPrices
[
"gemini-3.1-pro"
]
=
&
ModelPricing
{
InputPricePerToken
:
2e-6
,
// $2 per MTok
...
...
@@ -278,6 +281,9 @@ func (s *BillingService) getFallbackPricing(model string) *ModelPricing {
// 按模型系列匹配
if
strings
.
Contains
(
modelLower
,
"opus"
)
{
if
strings
.
Contains
(
modelLower
,
"4.7"
)
||
strings
.
Contains
(
modelLower
,
"4-7"
)
{
return
s
.
fallbackPrices
[
"claude-opus-4.7"
]
}
if
strings
.
Contains
(
modelLower
,
"4.6"
)
||
strings
.
Contains
(
modelLower
,
"4-6"
)
{
return
s
.
fallbackPrices
[
"claude-opus-4.6"
]
}
...
...
backend/internal/service/pricing_service.go
View file @
03dba58a
...
...
@@ -656,65 +656,95 @@ func (s *PricingService) extractBaseName(model string) string {
// matchByModelFamily 基于模型系列匹配
func
(
s
*
PricingService
)
matchByModelFamily
(
model
string
)
*
LiteLLMModelPricing
{
// Claude模型系列匹配规则
familyPatterns
:=
map
[
string
][]
string
{
"opus-4.6"
:
{
"claude-opus-4.6"
,
"claude-opus-4-6"
},
"opus-4.5"
:
{
"claude-opus-4.5"
,
"claude-opus-4-5"
},
"opus-4"
:
{
"claude-opus-4"
,
"claude-3-opus"
},
"sonnet-4.5"
:
{
"claude-sonnet-4.5"
,
"claude-sonnet-4-5"
},
"sonnet-4"
:
{
"claude-sonnet-4"
,
"claude-3-5-sonnet"
},
"sonnet-3.5"
:
{
"claude-3-5-sonnet"
,
"claude-3.5-sonnet"
},
"sonnet-3"
:
{
"claude-3-sonnet"
},
"haiku-3.5"
:
{
"claude-3-5-haiku"
,
"claude-3.5-haiku"
},
"haiku-3"
:
{
"claude-3-haiku"
},
}
// 确定模型属于哪个系列
var
matchedFamily
string
for
family
,
patterns
:=
range
familyPatterns
{
for
_
,
pattern
:=
range
patterns
{
// modelFamily 定义一个模型系列的匹配和定价查找规则。
type
modelFamily
struct
{
name
string
// 系列名称
match
[]
string
// 用于将模型归类到此系列的模式(strings.Contains 匹配)
pricing
[]
string
// 用于在定价数据中查找价格的模式(nil 则复用 match;可包含低版本 fallback)
}
// 按特异性降序排列:高版本号在前,避免 "claude-opus-4"(opus-4 系列)
// 因子串关系误匹配 "claude-opus-4-7"(opus-4.7 系列)。
// 注意:原 map 实现存在 Go map 迭代随机性导致的同类 bug,此处改为有序切片修复。
families
:=
[]
modelFamily
{
{
name
:
"opus-4.7"
,
match
:
[]
string
{
"claude-opus-4-7"
,
"claude-opus-4.7"
},
pricing
:
[]
string
{
"claude-opus-4-7"
,
"claude-opus-4.7"
,
"claude-opus-4-6"
}},
{
name
:
"opus-4.6"
,
match
:
[]
string
{
"claude-opus-4-6"
,
"claude-opus-4.6"
}},
{
name
:
"opus-4.5"
,
match
:
[]
string
{
"claude-opus-4-5"
,
"claude-opus-4.5"
}},
{
name
:
"opus-4"
,
match
:
[]
string
{
"claude-opus-4"
,
"claude-3-opus"
}},
{
name
:
"sonnet-4.5"
,
match
:
[]
string
{
"claude-sonnet-4-5"
,
"claude-sonnet-4.5"
}},
{
name
:
"sonnet-4"
,
match
:
[]
string
{
"claude-sonnet-4"
,
"claude-3-5-sonnet"
}},
{
name
:
"sonnet-3.5"
,
match
:
[]
string
{
"claude-3-5-sonnet"
,
"claude-3.5-sonnet"
}},
{
name
:
"sonnet-3"
,
match
:
[]
string
{
"claude-3-sonnet"
}},
{
name
:
"haiku-3.5"
,
match
:
[]
string
{
"claude-3-5-haiku"
,
"claude-3.5-haiku"
}},
{
name
:
"haiku-3"
,
match
:
[]
string
{
"claude-3-haiku"
}},
}
// Phase 1: 按有序切片归类(最具体的系列优先匹配)
var
matched
*
modelFamily
for
i
:=
range
families
{
for
_
,
pattern
:=
range
families
[
i
]
.
match
{
if
strings
.
Contains
(
model
,
pattern
)
||
strings
.
Contains
(
model
,
strings
.
ReplaceAll
(
pattern
,
"-"
,
""
))
{
matched
Family
=
famil
y
matched
=
&
famil
ies
[
i
]
break
}
}
if
matched
Family
!=
""
{
if
matched
!=
nil
{
break
}
}
if
matchedFamily
==
""
{
// 简单的系列匹配
if
strings
.
Contains
(
model
,
"opus"
)
{
if
strings
.
Contains
(
model
,
"4.5"
)
||
strings
.
Contains
(
model
,
"4-5"
)
{
matchedFamily
=
"opus-4.5"
}
else
{
matchedFamily
=
"opus-4"
}
}
else
if
strings
.
Contains
(
model
,
"sonnet"
)
{
if
strings
.
Contains
(
model
,
"4.5"
)
||
strings
.
Contains
(
model
,
"4-5"
)
{
matchedFamily
=
"sonnet-4.5"
}
else
if
strings
.
Contains
(
model
,
"3-5"
)
||
strings
.
Contains
(
model
,
"3.5"
)
{
matchedFamily
=
"sonnet-3.5"
}
else
{
matchedFamily
=
"sonnet-4"
// Phase 2: 二次兜底——当模型 ID 不含已知模式串时,按关键字粗分
if
matched
==
nil
{
var
fallbackName
string
switch
{
case
strings
.
Contains
(
model
,
"opus"
)
:
switch
{
case
strings
.
Contains
(
model
,
"4.7"
)
||
strings
.
Contains
(
model
,
"4-7"
)
:
fallbackName
=
"opus-4.7"
case
strings
.
Contains
(
model
,
"4.6"
)
||
strings
.
Contains
(
model
,
"4-6"
)
:
fallbackName
=
"opus-4.6"
case
strings
.
Contains
(
model
,
"4.5"
)
||
strings
.
Contains
(
model
,
"4-5"
)
:
fallbackName
=
"opus-4.5"
default
:
fallbackName
=
"opus-4"
}
case
strings
.
Contains
(
model
,
"sonnet"
)
:
switch
{
case
strings
.
Contains
(
model
,
"4.5"
)
||
strings
.
Contains
(
model
,
"4-5"
)
:
fallbackName
=
"sonnet-4.5"
case
strings
.
Contains
(
model
,
"3-5"
)
||
strings
.
Contains
(
model
,
"3.5"
)
:
fallbackName
=
"sonnet-3.5"
default
:
fallbackName
=
"sonnet-4"
}
case
strings
.
Contains
(
model
,
"haiku"
)
:
switch
{
case
strings
.
Contains
(
model
,
"3-5"
)
||
strings
.
Contains
(
model
,
"3.5"
)
:
fallbackName
=
"haiku-3.5"
default
:
fallbackName
=
"haiku-3"
}
}
if
fallbackName
!=
""
{
for
i
:=
range
families
{
if
families
[
i
]
.
name
==
fallbackName
{
matched
=
&
families
[
i
]
break
}
}
else
if
strings
.
Contains
(
model
,
"haiku"
)
{
if
strings
.
Contains
(
model
,
"3-5"
)
||
strings
.
Contains
(
model
,
"3.5"
)
{
matchedFamily
=
"haiku-3.5"
}
else
{
matchedFamily
=
"haiku-3"
}
}
}
if
matched
Family
==
""
{
if
matched
==
nil
{
return
nil
}
// 在价格数据中查找该系列的模型
patterns
:=
familyPatterns
[
matchedFamily
]
for
_
,
pattern
:=
range
patterns
{
// Phase 3: 在定价数据中查找该系列的价格
lookups
:=
matched
.
pricing
if
lookups
==
nil
{
lookups
=
matched
.
match
}
for
_
,
pattern
:=
range
lookups
{
for
key
,
pricing
:=
range
s
.
pricingData
{
keyLower
:=
strings
.
ToLower
(
key
)
if
strings
.
Contains
(
keyLower
,
pattern
)
{
...
...
frontend/src/composables/useModelWhitelist.ts
View file @
03dba58a
...
...
@@ -43,6 +43,7 @@ export const claudeModels = [
'
claude-sonnet-4-5-20250929
'
,
'
claude-haiku-4-5-20251001
'
,
'
claude-opus-4-5-20251101
'
,
'
claude-opus-4-6
'
,
'
claude-opus-4-7
'
,
'
claude-sonnet-4-6
'
,
'
claude-2.1
'
,
'
claude-2.0
'
,
'
claude-instant-1.2
'
]
...
...
@@ -66,6 +67,7 @@ const antigravityModels = [
// Claude 4.5+ 系列
'
claude-opus-4-6
'
,
'
claude-opus-4-6-thinking
'
,
'
claude-opus-4-7
'
,
'
claude-opus-4-5-thinking
'
,
'
claude-sonnet-4-6
'
,
'
claude-sonnet-4-5
'
,
...
...
@@ -250,6 +252,7 @@ const anthropicPresetMappings = [
{
label
:
'
Sonnet 4.6
'
,
from
:
'
claude-sonnet-4-6
'
,
to
:
'
claude-sonnet-4-6
'
,
color
:
'
bg-indigo-100 text-indigo-700 hover:bg-indigo-200 dark:bg-indigo-900/30 dark:text-indigo-400
'
},
{
label
:
'
Opus 4.5
'
,
from
:
'
claude-opus-4-5-20251101
'
,
to
:
'
claude-opus-4-5-20251101
'
,
color
:
'
bg-purple-100 text-purple-700 hover:bg-purple-200 dark:bg-purple-900/30 dark:text-purple-400
'
},
{
label
:
'
Opus 4.6
'
,
from
:
'
claude-opus-4-6
'
,
to
:
'
claude-opus-4-6
'
,
color
:
'
bg-purple-100 text-purple-700 hover:bg-purple-200 dark:bg-purple-900/30 dark:text-purple-400
'
},
{
label
:
'
Opus 4.7
'
,
from
:
'
claude-opus-4-7
'
,
to
:
'
claude-opus-4-7
'
,
color
:
'
bg-purple-100 text-purple-700 hover:bg-purple-200 dark:bg-purple-900/30 dark:text-purple-400
'
},
{
label
:
'
Haiku 3.5
'
,
from
:
'
claude-3-5-haiku-20241022
'
,
to
:
'
claude-3-5-haiku-20241022
'
,
color
:
'
bg-green-100 text-green-700 hover:bg-green-200 dark:bg-green-900/30 dark:text-green-400
'
},
{
label
:
'
Haiku 4.5
'
,
from
:
'
claude-haiku-4-5-20251001
'
,
to
:
'
claude-haiku-4-5-20251001
'
,
color
:
'
bg-emerald-100 text-emerald-700 hover:bg-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-400
'
},
{
label
:
'
Opus->Sonnet
'
,
from
:
'
claude-opus-4-6
'
,
to
:
'
claude-sonnet-4-5-20250929
'
,
color
:
'
bg-amber-100 text-amber-700 hover:bg-amber-200 dark:bg-amber-900/30 dark:text-amber-400
'
}
...
...
@@ -309,12 +312,14 @@ const antigravityPresetMappings = [
{
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
:
'
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
'
}
{
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
'
},
{
label
:
'
Opus 4.7
'
,
from
:
'
claude-opus-4-7
'
,
to
:
'
claude-opus-4-7
'
,
color
:
'
bg-pink-100 text-pink-700 hover:bg-pink-200 dark:bg-pink-900/30 dark:text-pink-400
'
}
]
// Bedrock 预设映射(与后端 DefaultBedrockModelMapping 保持一致)
const
bedrockPresetMappings
=
[
{
label
:
'
Opus 4.6
'
,
from
:
'
claude-opus-4-6
'
,
to
:
'
us.anthropic.claude-opus-4-6-v1
'
,
color
:
'
bg-pink-100 text-pink-700 hover:bg-pink-200 dark:bg-pink-900/30 dark:text-pink-400
'
},
{
label
:
'
Opus 4.7
'
,
from
:
'
claude-opus-4-7
'
,
to
:
'
us.anthropic.claude-opus-4-7-v1
'
,
color
:
'
bg-pink-100 text-pink-700 hover:bg-pink-200 dark:bg-pink-900/30 dark:text-pink-400
'
},
{
label
:
'
Sonnet 4.6
'
,
from
:
'
claude-sonnet-4-6
'
,
to
:
'
us.anthropic.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
:
'
Opus 4.5
'
,
from
:
'
claude-opus-4-5-thinking
'
,
to
:
'
us.anthropic.claude-opus-4-5-20251101-v1:0
'
,
color
:
'
bg-pink-100 text-pink-700 hover:bg-pink-200 dark:bg-pink-900/30 dark:text-pink-400
'
},
{
label
:
'
Sonnet 4.5
'
,
from
:
'
claude-sonnet-4-5
'
,
to
:
'
us.anthropic.claude-sonnet-4-5-20250929-v1:0
'
,
color
:
'
bg-cyan-100 text-cyan-700 hover:bg-cyan-200 dark:bg-cyan-900/30 dark:text-cyan-400
'
},
...
...
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