Merge pull request #782 from router-for-me/modelmappings
refactor(config): rename model-name-mappings to oauth-model-mappings
This commit is contained in:
@@ -156,9 +156,9 @@ ws-auth: false
|
|||||||
# headers:
|
# headers:
|
||||||
# X-Custom-Header: "custom-value"
|
# X-Custom-Header: "custom-value"
|
||||||
# models: # optional: map aliases to upstream model names
|
# models: # optional: map aliases to upstream model names
|
||||||
# - name: "gemini-2.0-flash" # upstream model name
|
# - name: "gemini-2.5-flash" # upstream model name
|
||||||
# alias: "vertex-flash" # client-visible alias
|
# alias: "vertex-flash" # client-visible alias
|
||||||
# - name: "gemini-1.5-pro"
|
# - name: "gemini-2.5-pro"
|
||||||
# alias: "vertex-pro"
|
# alias: "vertex-pro"
|
||||||
|
|
||||||
# Amp Integration
|
# Amp Integration
|
||||||
@@ -188,38 +188,42 @@ ws-auth: false
|
|||||||
# # Useful when Amp CLI requests models you don't have access to (e.g., Claude Opus 4.5)
|
# # Useful when Amp CLI requests models you don't have access to (e.g., Claude Opus 4.5)
|
||||||
# # but you have a similar model available (e.g., Claude Sonnet 4).
|
# # but you have a similar model available (e.g., Claude Sonnet 4).
|
||||||
# model-mappings:
|
# model-mappings:
|
||||||
# - from: "claude-opus-4.5" # Model requested by Amp CLI
|
# - from: "claude-opus-4-5-20251101" # Model requested by Amp CLI
|
||||||
# to: "claude-sonnet-4" # Route to this available model instead
|
# to: "gemini-claude-opus-4-5-thinking" # Route to this available model instead
|
||||||
# - from: "gpt-5"
|
# - from: "claude-sonnet-4-5-20250929"
|
||||||
# to: "gemini-2.5-pro"
|
# to: "gemini-claude-sonnet-4-5-thinking"
|
||||||
# - from: "claude-3-opus-20240229"
|
# - from: "claude-haiku-4-5-20251001"
|
||||||
# to: "claude-3-5-sonnet-20241022"
|
# to: "gemini-2.5-flash"
|
||||||
|
|
||||||
# Global model name mappings (per channel)
|
# Global OAuth model name mappings (per channel)
|
||||||
# These mappings rename model IDs for both model listing and request routing.
|
# These mappings rename model IDs for both model listing and request routing.
|
||||||
# NOTE: Mappings do not apply to codex-api-key, claude-api-key, openai-compatibility, vertex-api-key, or ampcode.
|
# Supported channels: gemini-cli, vertex, aistudio, antigravity, claude, codex, qwen, iflow.
|
||||||
# model-name-mappings:
|
# NOTE: Mappings do not apply to gemini-api-key, codex-api-key, claude-api-key, openai-compatibility, vertex-api-key, or ampcode.
|
||||||
# gemini:
|
# oauth-model-mappings:
|
||||||
# - from: "gemini-2.5-pro" # original model name under this channel
|
# gemini-cli:
|
||||||
# to: "gpt-5" # client-visible alias
|
# - name: "gemini-2.5-pro" # original model name under this channel
|
||||||
# apikey-gemini:
|
# alias: "g2.5p" # client-visible alias
|
||||||
# - from: "gemini-2.5-pro"
|
|
||||||
# to: "gpt-5"
|
|
||||||
# claude:
|
|
||||||
# - from: "claude-sonnet-4"
|
|
||||||
# to: "gpt-4o"
|
|
||||||
# vertex:
|
# vertex:
|
||||||
# - from: "gemini-2.5-pro"
|
# - name: "gemini-2.5-pro"
|
||||||
# to: "gpt-5"
|
# alias: "g2.5p"
|
||||||
# qwen:
|
# aistudio:
|
||||||
# - from: "qwen3-coder-plus"
|
# - name: "gemini-2.5-pro"
|
||||||
# to: "gpt-4o-mini"
|
# alias: "g2.5p"
|
||||||
# iflow:
|
|
||||||
# - from: "glm-4.7"
|
|
||||||
# to: "gpt-5.1-mini"
|
|
||||||
# antigravity:
|
# antigravity:
|
||||||
# - from: "gemini-3-pro-preview"
|
# - name: "gemini-3-pro-preview"
|
||||||
# to: "gpt-5"
|
# alias: "g3p"
|
||||||
|
# claude:
|
||||||
|
# - name: "claude-sonnet-4-5-20250929"
|
||||||
|
# alias: "cs4.5"
|
||||||
|
# codex:
|
||||||
|
# - name: "gpt-5"
|
||||||
|
# alias: "g5"
|
||||||
|
# qwen:
|
||||||
|
# - name: "qwen3-coder-plus"
|
||||||
|
# alias: "qwen-plus"
|
||||||
|
# iflow:
|
||||||
|
# - name: "glm-4.7"
|
||||||
|
# alias: "glm-god"
|
||||||
|
|
||||||
# OAuth provider excluded models
|
# OAuth provider excluded models
|
||||||
# oauth-excluded-models:
|
# oauth-excluded-models:
|
||||||
|
|||||||
@@ -91,12 +91,13 @@ type Config struct {
|
|||||||
// OAuthExcludedModels defines per-provider global model exclusions applied to OAuth/file-backed auth entries.
|
// OAuthExcludedModels defines per-provider global model exclusions applied to OAuth/file-backed auth entries.
|
||||||
OAuthExcludedModels map[string][]string `yaml:"oauth-excluded-models,omitempty" json:"oauth-excluded-models,omitempty"`
|
OAuthExcludedModels map[string][]string `yaml:"oauth-excluded-models,omitempty" json:"oauth-excluded-models,omitempty"`
|
||||||
|
|
||||||
// ModelNameMappings defines global per-channel model name mappings.
|
// OAuthModelMappings defines global model name mappings for OAuth/file-backed auth channels.
|
||||||
// These mappings affect both model listing and model routing for supported channels.
|
// These mappings affect both model listing and model routing for supported channels:
|
||||||
|
// gemini-cli, vertex, aistudio, antigravity, claude, codex, qwen, iflow.
|
||||||
//
|
//
|
||||||
// NOTE: This does not apply to existing per-credential model alias features under:
|
// NOTE: This does not apply to existing per-credential model alias features under:
|
||||||
// codex-api-key, claude-api-key, openai-compatibility, vertex-api-key, and ampcode.
|
// gemini-api-key, codex-api-key, claude-api-key, openai-compatibility, vertex-api-key, and ampcode.
|
||||||
ModelNameMappings map[string][]ModelNameMapping `yaml:"model-name-mappings,omitempty" json:"model-name-mappings,omitempty"`
|
OAuthModelMappings map[string][]ModelNameMapping `yaml:"oauth-model-mappings,omitempty" json:"oauth-model-mappings,omitempty"`
|
||||||
|
|
||||||
// Payload defines default and override rules for provider payload parameters.
|
// Payload defines default and override rules for provider payload parameters.
|
||||||
Payload PayloadConfig `yaml:"payload" json:"payload"`
|
Payload PayloadConfig `yaml:"payload" json:"payload"`
|
||||||
@@ -145,10 +146,10 @@ type RoutingConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ModelNameMapping defines a model ID rename mapping for a specific channel.
|
// ModelNameMapping defines a model ID rename mapping for a specific channel.
|
||||||
// It maps the original model name (From) to the client-visible alias (To).
|
// It maps the original model name (Name) to the client-visible alias (Alias).
|
||||||
type ModelNameMapping struct {
|
type ModelNameMapping struct {
|
||||||
From string `yaml:"from" json:"from"`
|
Name string `yaml:"name" json:"name"`
|
||||||
To string `yaml:"to" json:"to"`
|
Alias string `yaml:"alias" json:"alias"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AmpModelMapping defines a model name mapping for Amp CLI requests.
|
// AmpModelMapping defines a model name mapping for Amp CLI requests.
|
||||||
@@ -475,8 +476,8 @@ func LoadConfigOptional(configFile string, optional bool) (*Config, error) {
|
|||||||
// Normalize OAuth provider model exclusion map.
|
// Normalize OAuth provider model exclusion map.
|
||||||
cfg.OAuthExcludedModels = NormalizeOAuthExcludedModels(cfg.OAuthExcludedModels)
|
cfg.OAuthExcludedModels = NormalizeOAuthExcludedModels(cfg.OAuthExcludedModels)
|
||||||
|
|
||||||
// Normalize global model name mappings.
|
// Normalize global OAuth model name mappings.
|
||||||
cfg.SanitizeModelNameMappings()
|
cfg.SanitizeOAuthModelMappings()
|
||||||
|
|
||||||
if cfg.legacyMigrationPending {
|
if cfg.legacyMigrationPending {
|
||||||
fmt.Println("Detected legacy configuration keys, attempting to persist the normalized config...")
|
fmt.Println("Detected legacy configuration keys, attempting to persist the normalized config...")
|
||||||
@@ -494,48 +495,48 @@ func LoadConfigOptional(configFile string, optional bool) (*Config, error) {
|
|||||||
return &cfg, nil
|
return &cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SanitizeModelNameMappings normalizes and deduplicates global model name mappings.
|
// SanitizeOAuthModelMappings normalizes and deduplicates global OAuth model name mappings.
|
||||||
// It trims whitespace, normalizes channel keys to lower-case, drops empty entries,
|
// It trims whitespace, normalizes channel keys to lower-case, drops empty entries,
|
||||||
// and ensures (From, To) pairs are unique within each channel.
|
// and ensures (From, To) pairs are unique within each channel.
|
||||||
func (cfg *Config) SanitizeModelNameMappings() {
|
func (cfg *Config) SanitizeOAuthModelMappings() {
|
||||||
if cfg == nil || len(cfg.ModelNameMappings) == 0 {
|
if cfg == nil || len(cfg.OAuthModelMappings) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
out := make(map[string][]ModelNameMapping, len(cfg.ModelNameMappings))
|
out := make(map[string][]ModelNameMapping, len(cfg.OAuthModelMappings))
|
||||||
for rawChannel, mappings := range cfg.ModelNameMappings {
|
for rawChannel, mappings := range cfg.OAuthModelMappings {
|
||||||
channel := strings.ToLower(strings.TrimSpace(rawChannel))
|
channel := strings.ToLower(strings.TrimSpace(rawChannel))
|
||||||
if channel == "" || len(mappings) == 0 {
|
if channel == "" || len(mappings) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
seenFrom := make(map[string]struct{}, len(mappings))
|
seenName := make(map[string]struct{}, len(mappings))
|
||||||
seenTo := make(map[string]struct{}, len(mappings))
|
seenAlias := make(map[string]struct{}, len(mappings))
|
||||||
clean := make([]ModelNameMapping, 0, len(mappings))
|
clean := make([]ModelNameMapping, 0, len(mappings))
|
||||||
for _, mapping := range mappings {
|
for _, mapping := range mappings {
|
||||||
from := strings.TrimSpace(mapping.From)
|
name := strings.TrimSpace(mapping.Name)
|
||||||
to := strings.TrimSpace(mapping.To)
|
alias := strings.TrimSpace(mapping.Alias)
|
||||||
if from == "" || to == "" {
|
if name == "" || alias == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if strings.EqualFold(from, to) {
|
if strings.EqualFold(name, alias) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
fromKey := strings.ToLower(from)
|
nameKey := strings.ToLower(name)
|
||||||
toKey := strings.ToLower(to)
|
aliasKey := strings.ToLower(alias)
|
||||||
if _, ok := seenFrom[fromKey]; ok {
|
if _, ok := seenName[nameKey]; ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, ok := seenTo[toKey]; ok {
|
if _, ok := seenAlias[aliasKey]; ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
seenFrom[fromKey] = struct{}{}
|
seenName[nameKey] = struct{}{}
|
||||||
seenTo[toKey] = struct{}{}
|
seenAlias[aliasKey] = struct{}{}
|
||||||
clean = append(clean, ModelNameMapping{From: from, To: to})
|
clean = append(clean, ModelNameMapping{Name: name, Alias: alias})
|
||||||
}
|
}
|
||||||
if len(clean) > 0 {
|
if len(clean) > 0 {
|
||||||
out[channel] = clean
|
out[channel] = clean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cfg.ModelNameMappings = out
|
cfg.OAuthModelMappings = out
|
||||||
}
|
}
|
||||||
|
|
||||||
// SanitizeOpenAICompatibility removes OpenAI-compatibility provider entries that are
|
// SanitizeOpenAICompatibility removes OpenAI-compatibility provider entries that are
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ func (w *Watcher) reloadConfig() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
authDirChanged := oldConfig == nil || oldConfig.AuthDir != newConfig.AuthDir
|
authDirChanged := oldConfig == nil || oldConfig.AuthDir != newConfig.AuthDir
|
||||||
forceAuthRefresh := oldConfig != nil && (oldConfig.ForceModelPrefix != newConfig.ForceModelPrefix || !reflect.DeepEqual(oldConfig.ModelNameMappings, newConfig.ModelNameMappings))
|
forceAuthRefresh := oldConfig != nil && (oldConfig.ForceModelPrefix != newConfig.ForceModelPrefix || !reflect.DeepEqual(oldConfig.OAuthModelMappings, newConfig.OAuthModelMappings))
|
||||||
|
|
||||||
log.Infof("config successfully reloaded, triggering client reload")
|
log.Infof("config successfully reloaded, triggering client reload")
|
||||||
w.reloadClients(authDirChanged, affectedOAuthProviders, forceAuthRefresh)
|
w.reloadClients(authDirChanged, affectedOAuthProviders, forceAuthRefresh)
|
||||||
|
|||||||
@@ -413,7 +413,7 @@ func (m *Manager) executeWithProvider(ctx context.Context, provider string, req
|
|||||||
}
|
}
|
||||||
execReq := req
|
execReq := req
|
||||||
execReq.Model, execReq.Metadata = rewriteModelForAuth(routeModel, req.Metadata, auth)
|
execReq.Model, execReq.Metadata = rewriteModelForAuth(routeModel, req.Metadata, auth)
|
||||||
execReq.Metadata = m.applyGlobalModelNameMappingMetadata(auth, execReq.Model, execReq.Metadata)
|
execReq.Metadata = m.applyOAuthModelMappingMetadata(auth, execReq.Model, execReq.Metadata)
|
||||||
resp, errExec := executor.Execute(execCtx, auth, execReq, opts)
|
resp, errExec := executor.Execute(execCtx, auth, execReq, opts)
|
||||||
result := Result{AuthID: auth.ID, Provider: provider, Model: routeModel, Success: errExec == nil}
|
result := Result{AuthID: auth.ID, Provider: provider, Model: routeModel, Success: errExec == nil}
|
||||||
if errExec != nil {
|
if errExec != nil {
|
||||||
@@ -475,7 +475,7 @@ func (m *Manager) executeCountWithProvider(ctx context.Context, provider string,
|
|||||||
}
|
}
|
||||||
execReq := req
|
execReq := req
|
||||||
execReq.Model, execReq.Metadata = rewriteModelForAuth(routeModel, req.Metadata, auth)
|
execReq.Model, execReq.Metadata = rewriteModelForAuth(routeModel, req.Metadata, auth)
|
||||||
execReq.Metadata = m.applyGlobalModelNameMappingMetadata(auth, execReq.Model, execReq.Metadata)
|
execReq.Metadata = m.applyOAuthModelMappingMetadata(auth, execReq.Model, execReq.Metadata)
|
||||||
resp, errExec := executor.CountTokens(execCtx, auth, execReq, opts)
|
resp, errExec := executor.CountTokens(execCtx, auth, execReq, opts)
|
||||||
result := Result{AuthID: auth.ID, Provider: provider, Model: routeModel, Success: errExec == nil}
|
result := Result{AuthID: auth.ID, Provider: provider, Model: routeModel, Success: errExec == nil}
|
||||||
if errExec != nil {
|
if errExec != nil {
|
||||||
@@ -537,7 +537,7 @@ func (m *Manager) executeStreamWithProvider(ctx context.Context, provider string
|
|||||||
}
|
}
|
||||||
execReq := req
|
execReq := req
|
||||||
execReq.Model, execReq.Metadata = rewriteModelForAuth(routeModel, req.Metadata, auth)
|
execReq.Model, execReq.Metadata = rewriteModelForAuth(routeModel, req.Metadata, auth)
|
||||||
execReq.Metadata = m.applyGlobalModelNameMappingMetadata(auth, execReq.Model, execReq.Metadata)
|
execReq.Metadata = m.applyOAuthModelMappingMetadata(auth, execReq.Model, execReq.Metadata)
|
||||||
chunks, errStream := executor.ExecuteStream(execCtx, auth, execReq, opts)
|
chunks, errStream := executor.ExecuteStream(execCtx, auth, execReq, opts)
|
||||||
if errStream != nil {
|
if errStream != nil {
|
||||||
rerr := &Error{Message: errStream.Error()}
|
rerr := &Error{Message: errStream.Error()}
|
||||||
|
|||||||
@@ -26,19 +26,19 @@ func compileModelNameMappingTable(mappings map[string][]internalconfig.ModelName
|
|||||||
}
|
}
|
||||||
rev := make(map[string]string, len(entries))
|
rev := make(map[string]string, len(entries))
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
from := strings.TrimSpace(entry.From)
|
name := strings.TrimSpace(entry.Name)
|
||||||
to := strings.TrimSpace(entry.To)
|
alias := strings.TrimSpace(entry.Alias)
|
||||||
if from == "" || to == "" {
|
if name == "" || alias == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if strings.EqualFold(from, to) {
|
if strings.EqualFold(name, alias) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
aliasKey := strings.ToLower(to)
|
aliasKey := strings.ToLower(alias)
|
||||||
if _, exists := rev[aliasKey]; exists {
|
if _, exists := rev[aliasKey]; exists {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
rev[aliasKey] = from
|
rev[aliasKey] = name
|
||||||
}
|
}
|
||||||
if len(rev) > 0 {
|
if len(rev) > 0 {
|
||||||
out.reverse[channel] = rev
|
out.reverse[channel] = rev
|
||||||
@@ -50,10 +50,10 @@ func compileModelNameMappingTable(mappings map[string][]internalconfig.ModelName
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetGlobalModelNameMappings updates the global model name mapping table used during execution.
|
// SetOAuthModelMappings updates the OAuth model name mapping table used during execution.
|
||||||
// The mapping is applied per-auth channel to resolve the upstream model name while keeping the
|
// The mapping is applied per-auth channel to resolve the upstream model name while keeping the
|
||||||
// client-visible model name unchanged for translation/response formatting.
|
// client-visible model name unchanged for translation/response formatting.
|
||||||
func (m *Manager) SetGlobalModelNameMappings(mappings map[string][]internalconfig.ModelNameMapping) {
|
func (m *Manager) SetOAuthModelMappings(mappings map[string][]internalconfig.ModelNameMapping) {
|
||||||
if m == nil {
|
if m == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -65,8 +65,8 @@ func (m *Manager) SetGlobalModelNameMappings(mappings map[string][]internalconfi
|
|||||||
m.modelNameMappings.Store(table)
|
m.modelNameMappings.Store(table)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) applyGlobalModelNameMappingMetadata(auth *Auth, requestedModel string, metadata map[string]any) map[string]any {
|
func (m *Manager) applyOAuthModelMappingMetadata(auth *Auth, requestedModel string, metadata map[string]any) map[string]any {
|
||||||
original := m.resolveGlobalUpstreamModelForAuth(auth, requestedModel)
|
original := m.resolveOAuthUpstreamModel(auth, requestedModel)
|
||||||
if original == "" {
|
if original == "" {
|
||||||
return metadata
|
return metadata
|
||||||
}
|
}
|
||||||
@@ -88,11 +88,11 @@ func (m *Manager) applyGlobalModelNameMappingMetadata(auth *Auth, requestedModel
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) resolveGlobalUpstreamModelForAuth(auth *Auth, requestedModel string) string {
|
func (m *Manager) resolveOAuthUpstreamModel(auth *Auth, requestedModel string) string {
|
||||||
if m == nil || auth == nil {
|
if m == nil || auth == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
channel := globalModelMappingChannelForAuth(auth)
|
channel := modelMappingChannel(auth)
|
||||||
if channel == "" {
|
if channel == "" {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -116,7 +116,10 @@ func (m *Manager) resolveGlobalUpstreamModelForAuth(auth *Auth, requestedModel s
|
|||||||
return original
|
return original
|
||||||
}
|
}
|
||||||
|
|
||||||
func globalModelMappingChannelForAuth(auth *Auth) string {
|
// modelMappingChannel extracts the OAuth model mapping channel from an Auth object.
|
||||||
|
// It determines the provider and auth kind from the Auth's attributes and delegates
|
||||||
|
// to OAuthModelMappingChannel for the actual channel resolution.
|
||||||
|
func modelMappingChannel(auth *Auth) string {
|
||||||
if auth == nil {
|
if auth == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
@@ -130,32 +133,38 @@ func globalModelMappingChannelForAuth(auth *Auth) string {
|
|||||||
authKind = "apikey"
|
authKind = "apikey"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return globalModelMappingChannel(provider, authKind)
|
return OAuthModelMappingChannel(provider, authKind)
|
||||||
}
|
}
|
||||||
|
|
||||||
func globalModelMappingChannel(provider, authKind string) string {
|
// OAuthModelMappingChannel returns the OAuth model mapping channel name for a given provider
|
||||||
|
// and auth kind. Returns empty string if the provider/authKind combination doesn't support
|
||||||
|
// OAuth model mappings (e.g., API key authentication).
|
||||||
|
//
|
||||||
|
// Supported channels: gemini-cli, vertex, aistudio, antigravity, claude, codex, qwen, iflow.
|
||||||
|
func OAuthModelMappingChannel(provider, authKind string) string {
|
||||||
|
provider = strings.ToLower(strings.TrimSpace(provider))
|
||||||
|
authKind = strings.ToLower(strings.TrimSpace(authKind))
|
||||||
switch provider {
|
switch provider {
|
||||||
case "gemini":
|
case "gemini":
|
||||||
if authKind == "apikey" {
|
// gemini provider uses gemini-api-key config, not oauth-model-mappings.
|
||||||
return "apikey-gemini"
|
// OAuth-based gemini auth is converted to "gemini-cli" by the synthesizer.
|
||||||
}
|
|
||||||
return "gemini"
|
|
||||||
case "codex":
|
|
||||||
if authKind == "apikey" {
|
|
||||||
return ""
|
return ""
|
||||||
}
|
|
||||||
return "codex"
|
|
||||||
case "claude":
|
|
||||||
if authKind == "apikey" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return "claude"
|
|
||||||
case "vertex":
|
case "vertex":
|
||||||
if authKind == "apikey" {
|
if authKind == "apikey" {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return "vertex"
|
return "vertex"
|
||||||
case "antigravity", "qwen", "iflow":
|
case "claude":
|
||||||
|
if authKind == "apikey" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return "claude"
|
||||||
|
case "codex":
|
||||||
|
if authKind == "apikey" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return "codex"
|
||||||
|
case "gemini-cli", "aistudio", "antigravity", "qwen", "iflow":
|
||||||
return provider
|
return provider
|
||||||
default:
|
default:
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
@@ -215,7 +215,7 @@ func (b *Builder) Build() (*Service, error) {
|
|||||||
}
|
}
|
||||||
// Attach a default RoundTripper provider so providers can opt-in per-auth transports.
|
// Attach a default RoundTripper provider so providers can opt-in per-auth transports.
|
||||||
coreManager.SetRoundTripperProvider(newDefaultRoundTripperProvider())
|
coreManager.SetRoundTripperProvider(newDefaultRoundTripperProvider())
|
||||||
coreManager.SetGlobalModelNameMappings(b.cfg.ModelNameMappings)
|
coreManager.SetOAuthModelMappings(b.cfg.OAuthModelMappings)
|
||||||
|
|
||||||
service := &Service{
|
service := &Service{
|
||||||
cfg: b.cfg,
|
cfg: b.cfg,
|
||||||
|
|||||||
@@ -553,7 +553,7 @@ func (s *Service) Run(ctx context.Context) error {
|
|||||||
s.cfg = newCfg
|
s.cfg = newCfg
|
||||||
s.cfgMu.Unlock()
|
s.cfgMu.Unlock()
|
||||||
if s.coreManager != nil {
|
if s.coreManager != nil {
|
||||||
s.coreManager.SetGlobalModelNameMappings(newCfg.ModelNameMappings)
|
s.coreManager.SetOAuthModelMappings(newCfg.OAuthModelMappings)
|
||||||
}
|
}
|
||||||
s.rebindExecutors()
|
s.rebindExecutors()
|
||||||
}
|
}
|
||||||
@@ -844,7 +844,7 @@ func (s *Service) registerModelsForAuth(a *coreauth.Auth) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
models = applyGlobalModelNameMappings(s.cfg, provider, authKind, models)
|
models = applyOAuthModelMappings(s.cfg, provider, authKind, models)
|
||||||
if len(models) > 0 {
|
if len(models) > 0 {
|
||||||
key := provider
|
key := provider
|
||||||
if key == "" {
|
if key == "" {
|
||||||
@@ -1154,37 +1154,6 @@ func buildVertexCompatConfigModels(entry *config.VertexCompatKey) []*ModelInfo {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
func globalModelMappingChannel(provider, authKind string) string {
|
|
||||||
provider = strings.ToLower(strings.TrimSpace(provider))
|
|
||||||
authKind = strings.ToLower(strings.TrimSpace(authKind))
|
|
||||||
switch provider {
|
|
||||||
case "gemini":
|
|
||||||
if authKind == "apikey" {
|
|
||||||
return "apikey-gemini"
|
|
||||||
}
|
|
||||||
return "gemini"
|
|
||||||
case "codex":
|
|
||||||
if authKind == "apikey" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return "codex"
|
|
||||||
case "claude":
|
|
||||||
if authKind == "apikey" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return "claude"
|
|
||||||
case "vertex":
|
|
||||||
if authKind == "apikey" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return "vertex"
|
|
||||||
case "antigravity", "qwen", "iflow":
|
|
||||||
return provider
|
|
||||||
default:
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func rewriteModelInfoName(name, oldID, newID string) string {
|
func rewriteModelInfoName(name, oldID, newID string) string {
|
||||||
trimmed := strings.TrimSpace(name)
|
trimmed := strings.TrimSpace(name)
|
||||||
if trimmed == "" {
|
if trimmed == "" {
|
||||||
@@ -1208,33 +1177,33 @@ func rewriteModelInfoName(name, oldID, newID string) string {
|
|||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyGlobalModelNameMappings(cfg *config.Config, provider, authKind string, models []*ModelInfo) []*ModelInfo {
|
func applyOAuthModelMappings(cfg *config.Config, provider, authKind string, models []*ModelInfo) []*ModelInfo {
|
||||||
if cfg == nil || len(models) == 0 {
|
if cfg == nil || len(models) == 0 {
|
||||||
return models
|
return models
|
||||||
}
|
}
|
||||||
channel := globalModelMappingChannel(provider, authKind)
|
channel := coreauth.OAuthModelMappingChannel(provider, authKind)
|
||||||
if channel == "" || len(cfg.ModelNameMappings) == 0 {
|
if channel == "" || len(cfg.OAuthModelMappings) == 0 {
|
||||||
return models
|
return models
|
||||||
}
|
}
|
||||||
mappings := cfg.ModelNameMappings[channel]
|
mappings := cfg.OAuthModelMappings[channel]
|
||||||
if len(mappings) == 0 {
|
if len(mappings) == 0 {
|
||||||
return models
|
return models
|
||||||
}
|
}
|
||||||
forward := make(map[string]string, len(mappings))
|
forward := make(map[string]string, len(mappings))
|
||||||
for i := range mappings {
|
for i := range mappings {
|
||||||
from := strings.TrimSpace(mappings[i].From)
|
name := strings.TrimSpace(mappings[i].Name)
|
||||||
to := strings.TrimSpace(mappings[i].To)
|
alias := strings.TrimSpace(mappings[i].Alias)
|
||||||
if from == "" || to == "" {
|
if name == "" || alias == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if strings.EqualFold(from, to) {
|
if strings.EqualFold(name, alias) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
key := strings.ToLower(from)
|
key := strings.ToLower(name)
|
||||||
if _, exists := forward[key]; exists {
|
if _, exists := forward[key]; exists {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
forward[key] = to
|
forward[key] = alias
|
||||||
}
|
}
|
||||||
if len(forward) == 0 {
|
if len(forward) == 0 {
|
||||||
return models
|
return models
|
||||||
|
|||||||
Reference in New Issue
Block a user