feat(config): add default Kiro model aliases for standard Claude model names

Kiro models are exposed with kiro- prefix (e.g., kiro-claude-sonnet-4-5),
which prevents clients like Claude Code from using standard model names
(e.g., claude-sonnet-4-20250514).

This change injects default oauth-model-alias entries for the kiro channel
when no user-configured aliases exist, following the same pattern as the
existing Antigravity defaults. The aliases map standard Claude model names
(both with and without date suffixes) to their kiro-prefixed counterparts.

Default aliases added:
- claude-sonnet-4-5-20250929 / claude-sonnet-4-5 → kiro-claude-sonnet-4-5
- claude-sonnet-4-20250514 / claude-sonnet-4 → kiro-claude-sonnet-4
- claude-opus-4-6 → kiro-claude-opus-4-6
- claude-opus-4-5-20251101 / claude-opus-4-5 → kiro-claude-opus-4-5
- claude-haiku-4-5-20251001 / claude-haiku-4-5 → kiro-claude-haiku-4-5

All aliases use fork: true to preserve the original kiro-* names.
User-configured kiro aliases are respected and not overridden.

Closes router-for-me/CLIProxyAPIPlus#208
This commit is contained in:
y
2026-02-10 19:01:07 +08:00
parent e17d4f8d98
commit c3f1cdd7e5
3 changed files with 132 additions and 1 deletions

View File

@@ -736,8 +736,32 @@ func payloadRawString(value any) ([]byte, bool) {
// SanitizeOAuthModelAlias normalizes and deduplicates global OAuth model name aliases.
// It trims whitespace, normalizes channel keys to lower-case, drops empty entries,
// allows multiple aliases per upstream name, and ensures aliases are unique within each channel.
// It also injects default aliases for channels that have built-in defaults (e.g., kiro)
// when no user-configured aliases exist for those channels.
func (cfg *Config) SanitizeOAuthModelAlias() {
if cfg == nil || len(cfg.OAuthModelAlias) == 0 {
if cfg == nil {
return
}
// Inject default Kiro aliases if no user-configured kiro aliases exist
if cfg.OAuthModelAlias == nil {
cfg.OAuthModelAlias = make(map[string][]OAuthModelAlias)
}
if _, hasKiro := cfg.OAuthModelAlias["kiro"]; !hasKiro {
// Check case-insensitive too
found := false
for k := range cfg.OAuthModelAlias {
if strings.EqualFold(strings.TrimSpace(k), "kiro") {
found = true
break
}
}
if !found {
cfg.OAuthModelAlias["kiro"] = defaultKiroAliases()
}
}
if len(cfg.OAuthModelAlias) == 0 {
return
}
out := make(map[string][]OAuthModelAlias, len(cfg.OAuthModelAlias))

View File

@@ -20,6 +20,28 @@ var antigravityModelConversionTable = map[string]string{
"gemini-claude-opus-4-6-thinking": "claude-opus-4-6-thinking",
}
// defaultKiroAliases returns the default oauth-model-alias configuration
// for the kiro channel. Maps kiro-prefixed model names to standard Claude model
// names so that clients like Claude Code can use standard names directly.
func defaultKiroAliases() []OAuthModelAlias {
return []OAuthModelAlias{
// Sonnet 4.5
{Name: "kiro-claude-sonnet-4-5", Alias: "claude-sonnet-4-5-20250929", Fork: true},
{Name: "kiro-claude-sonnet-4-5", Alias: "claude-sonnet-4-5", Fork: true},
// Sonnet 4
{Name: "kiro-claude-sonnet-4", Alias: "claude-sonnet-4-20250514", Fork: true},
{Name: "kiro-claude-sonnet-4", Alias: "claude-sonnet-4", Fork: true},
// Opus 4.6
{Name: "kiro-claude-opus-4-6", Alias: "claude-opus-4-6", Fork: true},
// Opus 4.5
{Name: "kiro-claude-opus-4-5", Alias: "claude-opus-4-5-20251101", Fork: true},
{Name: "kiro-claude-opus-4-5", Alias: "claude-opus-4-5", Fork: true},
// Haiku 4.5
{Name: "kiro-claude-haiku-4-5", Alias: "claude-haiku-4-5-20251001", Fork: true},
{Name: "kiro-claude-haiku-4-5", Alias: "claude-haiku-4-5", Fork: true},
}
}
// defaultAntigravityAliases returns the default oauth-model-alias configuration
// for the antigravity channel when neither field exists.
func defaultAntigravityAliases() []OAuthModelAlias {

View File

@@ -54,3 +54,88 @@ func TestSanitizeOAuthModelAlias_AllowsMultipleAliasesForSameName(t *testing.T)
}
}
}
func TestSanitizeOAuthModelAlias_InjectsDefaultKiroAliases(t *testing.T) {
// When no kiro aliases are configured, defaults should be injected
cfg := &Config{
OAuthModelAlias: map[string][]OAuthModelAlias{
"codex": {
{Name: "gpt-5", Alias: "g5"},
},
},
}
cfg.SanitizeOAuthModelAlias()
kiroAliases := cfg.OAuthModelAlias["kiro"]
if len(kiroAliases) == 0 {
t.Fatal("expected default kiro aliases to be injected")
}
// Check that standard Claude model names are present
aliasSet := make(map[string]bool)
for _, a := range kiroAliases {
aliasSet[a.Alias] = true
}
expectedAliases := []string{
"claude-sonnet-4-5-20250929",
"claude-sonnet-4-5",
"claude-sonnet-4-20250514",
"claude-sonnet-4",
"claude-opus-4-6",
"claude-opus-4-5-20251101",
"claude-opus-4-5",
"claude-haiku-4-5-20251001",
"claude-haiku-4-5",
}
for _, expected := range expectedAliases {
if !aliasSet[expected] {
t.Fatalf("expected default kiro alias %q to be present", expected)
}
}
// All should have fork=true
for _, a := range kiroAliases {
if !a.Fork {
t.Fatalf("expected all default kiro aliases to have fork=true, got fork=false for %q", a.Alias)
}
}
// Codex aliases should still be preserved
if len(cfg.OAuthModelAlias["codex"]) != 1 {
t.Fatal("expected codex aliases to be preserved")
}
}
func TestSanitizeOAuthModelAlias_DoesNotOverrideUserKiroAliases(t *testing.T) {
// When user has configured kiro aliases, defaults should NOT be injected
cfg := &Config{
OAuthModelAlias: map[string][]OAuthModelAlias{
"kiro": {
{Name: "kiro-claude-sonnet-4", Alias: "my-custom-sonnet", Fork: true},
},
},
}
cfg.SanitizeOAuthModelAlias()
kiroAliases := cfg.OAuthModelAlias["kiro"]
if len(kiroAliases) != 1 {
t.Fatalf("expected 1 user-configured kiro alias, got %d", len(kiroAliases))
}
if kiroAliases[0].Alias != "my-custom-sonnet" {
t.Fatalf("expected user alias to be preserved, got %q", kiroAliases[0].Alias)
}
}
func TestSanitizeOAuthModelAlias_InjectsDefaultKiroWhenEmpty(t *testing.T) {
// When OAuthModelAlias is nil, kiro defaults should still be injected
cfg := &Config{}
cfg.SanitizeOAuthModelAlias()
kiroAliases := cfg.OAuthModelAlias["kiro"]
if len(kiroAliases) == 0 {
t.Fatal("expected default kiro aliases to be injected when OAuthModelAlias is nil")
}
}