mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-16 07:33:06 +08:00
feat(gateway): adapt Claude Haiku 5.5
Closes #7919. Wire claude-haiku-5-5 (released 2026-10-07) across model registry, effort catalog, pricing, billing, validation and Codex descriptors, following the opus-5-5/sonnet-5-5 template and the official migration guide + overview specs. - registry: DefaultModels entry (fixed ID, no date suffix per guide) - effort: full low/medium/high/xhigh/max family + IsHaiku55 + claude-haiku-5.5 dotted normalization (official default: medium) - pricing catalog: 1M/128k limits, base (<=100k) prices and *_above_100k_tokens absolute prices; the existing ladder derivation yields threshold=100000 with uniform 5x multipliers, matching the official two-tier table exactly (cache tiers follow input x5) - billing/pricing fallbacks carry the same tier so a missing catalog entry can never silently bill >100k prompts at base rate - validation: adaptive-only thinking (enabled always 400; disabled 400 at xhigh/max), sonnet-style sampling locks, temp+top_p combo rejected, forced tool_choice explicitly allowed (differs from opus/sonnet) - oauth mimicry: skip temperature:1 top-up when top_p is present on sampling-locked models (sonnet-5-5 included), otherwise the gateway manufactures the temp+top_p 400 itself - toolset beta filter + Codex 1M context cover haiku-5-5 - Bedrock/Antigravity mappings intentionally left out (no 5.5 entries exist there at all, same as opus-5-5); Vertex passes the fixed ID through untouched
This commit is contained in:
@@ -223,6 +223,12 @@ var DefaultModels = []Model{
|
||||
DisplayName: "Claude Haiku 4.5",
|
||||
CreatedAt: "2025-10-01T00:00:00Z",
|
||||
},
|
||||
{
|
||||
ID: "claude-haiku-5-5",
|
||||
Type: "model",
|
||||
DisplayName: "Claude Haiku 5.5",
|
||||
CreatedAt: "2026-10-07T00:00:00Z",
|
||||
},
|
||||
}
|
||||
|
||||
// DefaultModelIDs 返回默认模型的 ID 列表
|
||||
|
||||
@@ -43,3 +43,16 @@ func TestDefaultModelsContainsSonnet55(t *testing.T) {
|
||||
}
|
||||
t.Fatal("claude-sonnet-5-5 missing from DefaultModels")
|
||||
}
|
||||
|
||||
func TestDefaultModelsContainsHaiku55(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, model := range DefaultModels {
|
||||
if model.ID == "claude-haiku-5-5" {
|
||||
require.Equal(t, "Claude Haiku 5.5", model.DisplayName)
|
||||
require.Equal(t, "2026-10-07T00:00:00Z", model.CreatedAt)
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Fatal("claude-haiku-5-5 missing from DefaultModels")
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ var effortFamilies = []struct {
|
||||
{family: "claude-opus-4-5", levels: effortLowMediumHigh},
|
||||
{family: "claude-opus-5-5", levels: effortLowMediumHighXHighMax},
|
||||
{family: "claude-opus-5", levels: effortLowMediumHighXHighMax},
|
||||
{family: "claude-haiku-5-5", levels: effortLowMediumHighXHighMax},
|
||||
}
|
||||
|
||||
// EffortLevelsForModel returns the output_config.effort values accepted by a
|
||||
@@ -51,6 +52,11 @@ func IsSonnet55(model string) bool {
|
||||
return normalizeEffortModelID(model) == "claude-sonnet-5-5"
|
||||
}
|
||||
|
||||
// IsHaiku55 identifies the fixed Haiku 5.5 ID after provider/local suffix normalization.
|
||||
func IsHaiku55(model string) bool {
|
||||
return normalizeEffortModelID(model) == "claude-haiku-5-5"
|
||||
}
|
||||
|
||||
func normalizeEffortModelID(model string) string {
|
||||
id := strings.ToLower(strings.TrimSpace(model))
|
||||
id = strings.TrimPrefix(id, "models/")
|
||||
@@ -70,6 +76,9 @@ func normalizeEffortModelID(model string) string {
|
||||
if id == "claude-sonnet-5.5" {
|
||||
id = "claude-sonnet-5-5"
|
||||
}
|
||||
if id == "claude-haiku-5.5" {
|
||||
id = "claude-haiku-5-5"
|
||||
}
|
||||
if mapped, ok := ModelIDReverseOverrides[id]; ok {
|
||||
id = mapped
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ func TestEffortLevelsForModel(t *testing.T) {
|
||||
{model: "claude-opus-5", want: []string{"low", "medium", "high", "xhigh", "max"}},
|
||||
{model: "anthropic/claude-opus-5.5", want: []string{"low", "medium", "high", "xhigh", "max"}},
|
||||
{model: "claude-sonnet-5-5", want: []string{"low", "medium", "high", "xhigh", "max"}},
|
||||
{model: "claude-haiku-5-5", want: []string{"low", "medium", "high", "xhigh", "max"}},
|
||||
{model: "anthropic/claude-haiku-5.5", want: []string{"low", "medium", "high", "xhigh", "max"}},
|
||||
{model: "us.anthropic.claude-haiku-5-5", want: []string{"low", "medium", "high", "xhigh", "max"}},
|
||||
{model: "us.anthropic.claude-sonnet-5-5", want: []string{"low", "medium", "high", "xhigh", "max"}},
|
||||
{model: "claude-opus-4-5-20251101", want: []string{"low", "medium", "high"}},
|
||||
{model: "claude-haiku-4-5-20251001", want: nil},
|
||||
@@ -57,3 +60,19 @@ func TestIsSonnet55(t *testing.T) {
|
||||
require.False(t, IsSonnet55(model), model)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsHaiku55(t *testing.T) {
|
||||
t.Parallel()
|
||||
for _, model := range []string{
|
||||
"claude-haiku-5-5",
|
||||
"anthropic/claude-haiku-5.5",
|
||||
"anthropic.claude-haiku-5-5",
|
||||
"us.anthropic.claude-haiku-5-5",
|
||||
"global.anthropic.claude-haiku-5-5-thinking",
|
||||
} {
|
||||
require.True(t, IsHaiku55(model), model)
|
||||
}
|
||||
for _, model := range []string{"claude-haiku-5", "claude-haiku-4-5", "claude-haiku-4-5-20251001", "claude-sonnet-5-5", "claude-opus-5-5"} {
|
||||
require.False(t, IsHaiku55(model), model)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user