add new providers and update provider configuration structure

This commit is contained in:
Luke Milby 2026-02-19 15:53:57 -05:00
parent 5431f35b0d
commit f76231d8a1
3 changed files with 132 additions and 129 deletions

View file

@ -411,6 +411,9 @@ func DefaultConfig() *Config {
"nvidia": &ProviderConfig{}, "nvidia": &ProviderConfig{},
"moonshot": &ProviderConfig{}, "moonshot": &ProviderConfig{},
"shengsuanyun": &ProviderConfig{}, "shengsuanyun": &ProviderConfig{},
"deepseek": &ProviderConfig{},
"ollama": &ProviderConfig{},
"github_copilot": &ProviderConfig{},
}, },
Gateway: GatewayConfig{ Gateway: GatewayConfig{
Host: "0.0.0.0", Host: "0.0.0.0",

View file

@ -76,97 +76,97 @@ func resolveProviderSelection(cfg *config.Config) (providerSelection, error) {
if providerName != "" { if providerName != "" {
switch providerName { switch providerName {
case "groq": case "groq":
if cfg.Providers.Groq.APIKey != "" { if cfg.Providers["groq"].APIKey != "" {
sel.apiKey = cfg.Providers.Groq.APIKey sel.apiKey = cfg.Providers["groq"].APIKey
sel.apiBase = cfg.Providers.Groq.APIBase sel.apiBase = cfg.Providers["groq"].APIBase
sel.proxy = cfg.Providers.Groq.Proxy sel.proxy = cfg.Providers["groq"].Proxy
if sel.apiBase == "" { if sel.apiBase == "" {
sel.apiBase = "https://api.groq.com/openai/v1" sel.apiBase = "https://api.groq.com/openai/v1"
} }
} }
case "openai", "gpt": case "openai", "gpt":
if cfg.Providers.OpenAI.APIKey != "" || cfg.Providers.OpenAI.AuthMethod != "" { if cfg.Providers["openai"].APIKey != "" || cfg.Providers["openai"].AuthMethod != "" {
sel.enableWebSearch = cfg.Providers.OpenAI.WebSearch sel.enableWebSearch = cfg.Providers["openai"].WebSearch
if cfg.Providers.OpenAI.AuthMethod == "codex-cli" { if cfg.Providers["openai"].AuthMethod == "codex-cli" {
sel.providerType = providerTypeCodexCLIToken sel.providerType = providerTypeCodexCLIToken
return sel, nil return sel, nil
} }
if cfg.Providers.OpenAI.AuthMethod == "oauth" || cfg.Providers.OpenAI.AuthMethod == "token" { if cfg.Providers["openai"].AuthMethod == "oauth" || cfg.Providers["openai"].AuthMethod == "token" {
sel.providerType = providerTypeCodexAuth sel.providerType = providerTypeCodexAuth
return sel, nil return sel, nil
} }
sel.apiKey = cfg.Providers.OpenAI.APIKey sel.apiKey = cfg.Providers["openai"].APIKey
sel.apiBase = cfg.Providers.OpenAI.APIBase sel.apiBase = cfg.Providers["openai"].APIBase
sel.proxy = cfg.Providers.OpenAI.Proxy sel.proxy = cfg.Providers["openai"].Proxy
if sel.apiBase == "" { if sel.apiBase == "" {
sel.apiBase = "https://api.openai.com/v1" sel.apiBase = "https://api.openai.com/v1"
} }
} }
case "anthropic", "claude": case "anthropic", "claude":
if cfg.Providers.Anthropic.APIKey != "" || cfg.Providers.Anthropic.AuthMethod != "" { if cfg.Providers["anthropic"].APIKey != "" || cfg.Providers["anthropic"].AuthMethod != "" {
if cfg.Providers.Anthropic.AuthMethod == "oauth" || cfg.Providers.Anthropic.AuthMethod == "token" { if cfg.Providers["anthropic"].AuthMethod == "oauth" || cfg.Providers["anthropic"].AuthMethod == "token" {
sel.apiBase = cfg.Providers.Anthropic.APIBase sel.apiBase = cfg.Providers["anthropic"].APIBase
if sel.apiBase == "" { if sel.apiBase == "" {
sel.apiBase = defaultAnthropicAPIBase sel.apiBase = defaultAnthropicAPIBase
} }
sel.providerType = providerTypeClaudeAuth sel.providerType = providerTypeClaudeAuth
return sel, nil return sel, nil
} }
sel.apiKey = cfg.Providers.Anthropic.APIKey sel.apiKey = cfg.Providers["anthropic"].APIKey
sel.apiBase = cfg.Providers.Anthropic.APIBase sel.apiBase = cfg.Providers["anthropic"].APIBase
sel.proxy = cfg.Providers.Anthropic.Proxy sel.proxy = cfg.Providers["anthropic"].Proxy
if sel.apiBase == "" { if sel.apiBase == "" {
sel.apiBase = defaultAnthropicAPIBase sel.apiBase = defaultAnthropicAPIBase
} }
} }
case "openrouter": case "openrouter":
if cfg.Providers.OpenRouter.APIKey != "" { if cfg.Providers["openrouter"].APIKey != "" {
sel.apiKey = cfg.Providers.OpenRouter.APIKey sel.apiKey = cfg.Providers["openrouter"].APIKey
sel.proxy = cfg.Providers.OpenRouter.Proxy sel.proxy = cfg.Providers["openrouter"].Proxy
if cfg.Providers.OpenRouter.APIBase != "" { if cfg.Providers["openrouter"].APIBase != "" {
sel.apiBase = cfg.Providers.OpenRouter.APIBase sel.apiBase = cfg.Providers["openrouter"].APIBase
} else { } else {
sel.apiBase = "https://openrouter.ai/api/v1" sel.apiBase = "https://openrouter.ai/api/v1"
} }
} }
case "zhipu", "glm": case "zhipu", "glm":
if cfg.Providers.Zhipu.APIKey != "" { if cfg.Providers["zhipu"].APIKey != "" {
sel.apiKey = cfg.Providers.Zhipu.APIKey sel.apiKey = cfg.Providers["zhipu"].APIKey
sel.apiBase = cfg.Providers.Zhipu.APIBase sel.apiBase = cfg.Providers["zhipu"].APIBase
sel.proxy = cfg.Providers.Zhipu.Proxy sel.proxy = cfg.Providers["zhipu"].Proxy
if sel.apiBase == "" { if sel.apiBase == "" {
sel.apiBase = "https://open.bigmodel.cn/api/paas/v4" sel.apiBase = "https://open.bigmodel.cn/api/paas/v4"
} }
} }
case "gemini", "google": case "gemini", "google":
if cfg.Providers.Gemini.APIKey != "" { if cfg.Providers["gemini"].APIKey != "" {
sel.apiKey = cfg.Providers.Gemini.APIKey sel.apiKey = cfg.Providers["gemini"].APIKey
sel.apiBase = cfg.Providers.Gemini.APIBase sel.apiBase = cfg.Providers["gemini"].APIBase
sel.proxy = cfg.Providers.Gemini.Proxy sel.proxy = cfg.Providers["gemini"].Proxy
if sel.apiBase == "" { if sel.apiBase == "" {
sel.apiBase = "https://generativelanguage.googleapis.com/v1beta" sel.apiBase = "https://generativelanguage.googleapis.com/v1beta"
} }
} }
case "vllm": case "vllm":
if cfg.Providers.VLLM.APIBase != "" { if cfg.Providers["vllm"].APIBase != "" {
sel.apiKey = cfg.Providers.VLLM.APIKey sel.apiKey = cfg.Providers["vllm"].APIKey
sel.apiBase = cfg.Providers.VLLM.APIBase sel.apiBase = cfg.Providers["vllm"].APIBase
sel.proxy = cfg.Providers.VLLM.Proxy sel.proxy = cfg.Providers["vllm"].Proxy
} }
case "shengsuanyun": case "shengsuanyun":
if cfg.Providers.ShengSuanYun.APIKey != "" { if cfg.Providers["shengsuanyun"].APIKey != "" {
sel.apiKey = cfg.Providers.ShengSuanYun.APIKey sel.apiKey = cfg.Providers["shengsuanyun"].APIKey
sel.apiBase = cfg.Providers.ShengSuanYun.APIBase sel.apiBase = cfg.Providers["shengsuanyun"].APIBase
sel.proxy = cfg.Providers.ShengSuanYun.Proxy sel.proxy = cfg.Providers["shengsuanyun"].Proxy
if sel.apiBase == "" { if sel.apiBase == "" {
sel.apiBase = "https://router.shengsuanyun.com/api/v1" sel.apiBase = "https://router.shengsuanyun.com/api/v1"
} }
} }
case "nvidia": case "nvidia":
if cfg.Providers.Nvidia.APIKey != "" { if cfg.Providers["nvidia"].APIKey != "" {
sel.apiKey = cfg.Providers.Nvidia.APIKey sel.apiKey = cfg.Providers["nvidia"].APIKey
sel.apiBase = cfg.Providers.Nvidia.APIBase sel.apiBase = cfg.Providers["nvidia"].APIBase
sel.proxy = cfg.Providers.Nvidia.Proxy sel.proxy = cfg.Providers["nvidia"].Proxy
if sel.apiBase == "" { if sel.apiBase == "" {
sel.apiBase = "https://integrate.api.nvidia.com/v1" sel.apiBase = "https://integrate.api.nvidia.com/v1"
} }
@ -188,10 +188,10 @@ func resolveProviderSelection(cfg *config.Config) (providerSelection, error) {
sel.workspace = workspace sel.workspace = workspace
return sel, nil return sel, nil
case "deepseek": case "deepseek":
if cfg.Providers.DeepSeek.APIKey != "" { if cfg.Providers["deepseek"].APIKey != "" {
sel.apiKey = cfg.Providers.DeepSeek.APIKey sel.apiKey = cfg.Providers["deepseek"].APIKey
sel.apiBase = cfg.Providers.DeepSeek.APIBase sel.apiBase = cfg.Providers["deepseek"].APIBase
sel.proxy = cfg.Providers.DeepSeek.Proxy sel.proxy = cfg.Providers["deepseek"].Proxy
if sel.apiBase == "" { if sel.apiBase == "" {
sel.apiBase = "https://api.deepseek.com/v1" sel.apiBase = "https://api.deepseek.com/v1"
} }
@ -201,12 +201,12 @@ func resolveProviderSelection(cfg *config.Config) (providerSelection, error) {
} }
case "github_copilot", "copilot": case "github_copilot", "copilot":
sel.providerType = providerTypeGitHubCopilot sel.providerType = providerTypeGitHubCopilot
if cfg.Providers.GitHubCopilot.APIBase != "" { if cfg.Providers["github_copilot"].APIBase != "" {
sel.apiBase = cfg.Providers.GitHubCopilot.APIBase sel.apiBase = cfg.Providers["github_copilot"].APIBase
} else { } else {
sel.apiBase = "localhost:4321" sel.apiBase = "localhost:4321"
} }
sel.connectMode = cfg.Providers.GitHubCopilot.ConnectMode sel.connectMode = cfg.Providers["github_copilot"].ConnectMode
return sel, nil return sel, nil
} }
} }
@ -214,10 +214,10 @@ func resolveProviderSelection(cfg *config.Config) (providerSelection, error) {
// Fallback: infer provider from model and configured keys. // Fallback: infer provider from model and configured keys.
if sel.apiKey == "" && sel.apiBase == "" { if sel.apiKey == "" && sel.apiBase == "" {
switch { switch {
case (strings.Contains(lowerModel, "kimi") || strings.Contains(lowerModel, "moonshot") || strings.HasPrefix(model, "moonshot/")) && cfg.Providers.Moonshot.APIKey != "": case (strings.Contains(lowerModel, "kimi") || strings.Contains(lowerModel, "moonshot") || strings.HasPrefix(model, "moonshot/")) && cfg.Providers["moonshot"].APIKey != "":
sel.apiKey = cfg.Providers.Moonshot.APIKey sel.apiKey = cfg.Providers["moonshot"].APIKey
sel.apiBase = cfg.Providers.Moonshot.APIBase sel.apiBase = cfg.Providers["moonshot"].APIBase
sel.proxy = cfg.Providers.Moonshot.Proxy sel.proxy = cfg.Providers["moonshot"].Proxy
if sel.apiBase == "" { if sel.apiBase == "" {
sel.apiBase = "https://api.moonshot.cn/v1" sel.apiBase = "https://api.moonshot.cn/v1"
} }
@ -227,91 +227,91 @@ func resolveProviderSelection(cfg *config.Config) (providerSelection, error) {
strings.HasPrefix(model, "meta-llama/") || strings.HasPrefix(model, "meta-llama/") ||
strings.HasPrefix(model, "deepseek/") || strings.HasPrefix(model, "deepseek/") ||
strings.HasPrefix(model, "google/"): strings.HasPrefix(model, "google/"):
sel.apiKey = cfg.Providers.OpenRouter.APIKey sel.apiKey = cfg.Providers["openrouter"].APIKey
sel.proxy = cfg.Providers.OpenRouter.Proxy sel.proxy = cfg.Providers["openrouter"].Proxy
if cfg.Providers.OpenRouter.APIBase != "" { if cfg.Providers["openrouter"].APIBase != "" {
sel.apiBase = cfg.Providers.OpenRouter.APIBase sel.apiBase = cfg.Providers["openrouter"].APIBase
} else { } else {
sel.apiBase = "https://openrouter.ai/api/v1" sel.apiBase = "https://openrouter.ai/api/v1"
} }
case (strings.Contains(lowerModel, "claude") || strings.HasPrefix(model, "anthropic/")) && case (strings.Contains(lowerModel, "claude") || strings.HasPrefix(model, "anthropic/")) &&
(cfg.Providers.Anthropic.APIKey != "" || cfg.Providers.Anthropic.AuthMethod != ""): (cfg.Providers["anthropic"].APIKey != "" || cfg.Providers["anthropic"].AuthMethod != ""):
if cfg.Providers.Anthropic.AuthMethod == "oauth" || cfg.Providers.Anthropic.AuthMethod == "token" { if cfg.Providers["anthropic"].AuthMethod == "oauth" || cfg.Providers["anthropic"].AuthMethod == "token" {
sel.apiBase = cfg.Providers.Anthropic.APIBase sel.apiBase = cfg.Providers["anthropic"].APIBase
if sel.apiBase == "" { if sel.apiBase == "" {
sel.apiBase = defaultAnthropicAPIBase sel.apiBase = defaultAnthropicAPIBase
} }
sel.providerType = providerTypeClaudeAuth sel.providerType = providerTypeClaudeAuth
return sel, nil return sel, nil
} }
sel.apiKey = cfg.Providers.Anthropic.APIKey sel.apiKey = cfg.Providers["anthropic"].APIKey
sel.apiBase = cfg.Providers.Anthropic.APIBase sel.apiBase = cfg.Providers["anthropic"].APIBase
sel.proxy = cfg.Providers.Anthropic.Proxy sel.proxy = cfg.Providers["anthropic"].Proxy
if sel.apiBase == "" { if sel.apiBase == "" {
sel.apiBase = defaultAnthropicAPIBase sel.apiBase = defaultAnthropicAPIBase
} }
case (strings.Contains(lowerModel, "gpt") || strings.HasPrefix(model, "openai/")) && case (strings.Contains(lowerModel, "gpt") || strings.HasPrefix(model, "openai/")) &&
(cfg.Providers.OpenAI.APIKey != "" || cfg.Providers.OpenAI.AuthMethod != ""): (cfg.Providers["openai"].APIKey != "" || cfg.Providers["openai"].AuthMethod != ""):
sel.enableWebSearch = cfg.Providers.OpenAI.WebSearch sel.enableWebSearch = cfg.Providers["openai"].WebSearch
if cfg.Providers.OpenAI.AuthMethod == "codex-cli" { if cfg.Providers["openai"].AuthMethod == "codex-cli" {
sel.providerType = providerTypeCodexCLIToken sel.providerType = providerTypeCodexCLIToken
return sel, nil return sel, nil
} }
if cfg.Providers.OpenAI.AuthMethod == "oauth" || cfg.Providers.OpenAI.AuthMethod == "token" { if cfg.Providers["openai"].AuthMethod == "oauth" || cfg.Providers["openai"].AuthMethod == "token" {
sel.providerType = providerTypeCodexAuth sel.providerType = providerTypeCodexAuth
return sel, nil return sel, nil
} }
sel.apiKey = cfg.Providers.OpenAI.APIKey sel.apiKey = cfg.Providers["openai"].APIKey
sel.apiBase = cfg.Providers.OpenAI.APIBase sel.apiBase = cfg.Providers["openai"].APIBase
sel.proxy = cfg.Providers.OpenAI.Proxy sel.proxy = cfg.Providers["openai"].Proxy
if sel.apiBase == "" { if sel.apiBase == "" {
sel.apiBase = "https://api.openai.com/v1" sel.apiBase = "https://api.openai.com/v1"
} }
case (strings.Contains(lowerModel, "gemini") || strings.HasPrefix(model, "google/")) && cfg.Providers.Gemini.APIKey != "": case (strings.Contains(lowerModel, "gemini") || strings.HasPrefix(model, "google/")) && cfg.Providers["gemini"].APIKey != "":
sel.apiKey = cfg.Providers.Gemini.APIKey sel.apiKey = cfg.Providers["gemini"].APIKey
sel.apiBase = cfg.Providers.Gemini.APIBase sel.apiBase = cfg.Providers["gemini"].APIBase
sel.proxy = cfg.Providers.Gemini.Proxy sel.proxy = cfg.Providers["gemini"].Proxy
if sel.apiBase == "" { if sel.apiBase == "" {
sel.apiBase = "https://generativelanguage.googleapis.com/v1beta" sel.apiBase = "https://generativelanguage.googleapis.com/v1beta"
} }
case (strings.Contains(lowerModel, "glm") || strings.Contains(lowerModel, "zhipu") || strings.Contains(lowerModel, "zai")) && cfg.Providers.Zhipu.APIKey != "": case (strings.Contains(lowerModel, "glm") || strings.Contains(lowerModel, "zhipu") || strings.Contains(lowerModel, "zai")) && cfg.Providers["zhipu"].APIKey != "":
sel.apiKey = cfg.Providers.Zhipu.APIKey sel.apiKey = cfg.Providers["zhipu"].APIKey
sel.apiBase = cfg.Providers.Zhipu.APIBase sel.apiBase = cfg.Providers["zhipu"].APIBase
sel.proxy = cfg.Providers.Zhipu.Proxy sel.proxy = cfg.Providers["zhipu"].Proxy
if sel.apiBase == "" { if sel.apiBase == "" {
sel.apiBase = "https://open.bigmodel.cn/api/paas/v4" sel.apiBase = "https://open.bigmodel.cn/api/paas/v4"
} }
case (strings.Contains(lowerModel, "groq") || strings.HasPrefix(model, "groq/")) && cfg.Providers.Groq.APIKey != "": case (strings.Contains(lowerModel, "groq") || strings.HasPrefix(model, "groq/")) && cfg.Providers["groq"].APIKey != "":
sel.apiKey = cfg.Providers.Groq.APIKey sel.apiKey = cfg.Providers["groq"].APIKey
sel.apiBase = cfg.Providers.Groq.APIBase sel.apiBase = cfg.Providers["groq"].APIBase
sel.proxy = cfg.Providers.Groq.Proxy sel.proxy = cfg.Providers["groq"].Proxy
if sel.apiBase == "" { if sel.apiBase == "" {
sel.apiBase = "https://api.groq.com/openai/v1" sel.apiBase = "https://api.groq.com/openai/v1"
} }
case (strings.Contains(lowerModel, "nvidia") || strings.HasPrefix(model, "nvidia/")) && cfg.Providers.Nvidia.APIKey != "": case (strings.Contains(lowerModel, "nvidia") || strings.HasPrefix(model, "nvidia/")) && cfg.Providers["nvidia"].APIKey != "":
sel.apiKey = cfg.Providers.Nvidia.APIKey sel.apiKey = cfg.Providers["nvidia"].APIKey
sel.apiBase = cfg.Providers.Nvidia.APIBase sel.apiBase = cfg.Providers["nvidia"].APIBase
sel.proxy = cfg.Providers.Nvidia.Proxy sel.proxy = cfg.Providers["nvidia"].Proxy
if sel.apiBase == "" { if sel.apiBase == "" {
sel.apiBase = "https://integrate.api.nvidia.com/v1" sel.apiBase = "https://integrate.api.nvidia.com/v1"
} }
case (strings.Contains(lowerModel, "ollama") || strings.HasPrefix(model, "ollama/")) && cfg.Providers.Ollama.APIKey != "": case (strings.Contains(lowerModel, "ollama") || strings.HasPrefix(model, "ollama/")) && cfg.Providers["ollama"].APIKey != "":
sel.apiKey = cfg.Providers.Ollama.APIKey sel.apiKey = cfg.Providers["ollama"].APIKey
sel.apiBase = cfg.Providers.Ollama.APIBase sel.apiBase = cfg.Providers["ollama"].APIBase
sel.proxy = cfg.Providers.Ollama.Proxy sel.proxy = cfg.Providers["ollama"].Proxy
if sel.apiBase == "" { if sel.apiBase == "" {
sel.apiBase = "http://localhost:11434/v1" sel.apiBase = "http://localhost:11434/v1"
} }
case cfg.Providers.VLLM.APIBase != "": case cfg.Providers["vllm"].APIBase != "":
sel.apiKey = cfg.Providers.VLLM.APIKey sel.apiKey = cfg.Providers["vllm"].APIKey
sel.apiBase = cfg.Providers.VLLM.APIBase sel.apiBase = cfg.Providers["vllm"].APIBase
sel.proxy = cfg.Providers.VLLM.Proxy sel.proxy = cfg.Providers["vllm"].Proxy
default: default:
if cfg.Providers.OpenRouter.APIKey != "" { if cfg.Providers["openrouter"].APIKey != "" {
sel.apiKey = cfg.Providers.OpenRouter.APIKey sel.apiKey = cfg.Providers["openrouter"].APIKey
sel.proxy = cfg.Providers.OpenRouter.Proxy sel.proxy = cfg.Providers["openrouter"].Proxy
if cfg.Providers.OpenRouter.APIBase != "" { if cfg.Providers["openrouter"].APIBase != "" {
sel.apiBase = cfg.Providers.OpenRouter.APIBase sel.apiBase = cfg.Providers["openrouter"].APIBase
} else { } else {
sel.apiBase = "https://openrouter.ai/api/v1" sel.apiBase = "https://openrouter.ai/api/v1"
} }

View file

@ -38,8 +38,8 @@ func TestResolveProviderSelection(t *testing.T) {
setup: func(cfg *config.Config) { setup: func(cfg *config.Config) {
cfg.Agents.Defaults.Provider = "deepseek" cfg.Agents.Defaults.Provider = "deepseek"
cfg.Agents.Defaults.Model = "deepseek/deepseek-chat" cfg.Agents.Defaults.Model = "deepseek/deepseek-chat"
cfg.Providers.DeepSeek.APIKey = "deepseek-key" cfg.Providers["deepseek"].APIKey = "deepseek-key"
cfg.Providers.DeepSeek.Proxy = "http://127.0.0.1:7890" cfg.Providers["deepseek"].Proxy = "http://127.0.0.1:7890"
}, },
wantType: providerTypeHTTPCompat, wantType: providerTypeHTTPCompat,
wantAPIBase: "https://api.deepseek.com/v1", wantAPIBase: "https://api.deepseek.com/v1",
@ -49,8 +49,8 @@ func TestResolveProviderSelection(t *testing.T) {
name: "explicit shengsuanyun provider uses defaults", name: "explicit shengsuanyun provider uses defaults",
setup: func(cfg *config.Config) { setup: func(cfg *config.Config) {
cfg.Agents.Defaults.Provider = "shengsuanyun" cfg.Agents.Defaults.Provider = "shengsuanyun"
cfg.Providers.ShengSuanYun.APIKey = "ssy-key" cfg.Providers["shengsuanyun"].APIKey = "ssy-key"
cfg.Providers.ShengSuanYun.Proxy = "http://127.0.0.1:7890" cfg.Providers["shengsuanyun"].Proxy = "http://127.0.0.1:7890"
}, },
wantType: providerTypeHTTPCompat, wantType: providerTypeHTTPCompat,
wantAPIBase: "https://router.shengsuanyun.com/api/v1", wantAPIBase: "https://router.shengsuanyun.com/api/v1",
@ -60,8 +60,8 @@ func TestResolveProviderSelection(t *testing.T) {
name: "explicit nvidia provider uses defaults", name: "explicit nvidia provider uses defaults",
setup: func(cfg *config.Config) { setup: func(cfg *config.Config) {
cfg.Agents.Defaults.Provider = "nvidia" cfg.Agents.Defaults.Provider = "nvidia"
cfg.Providers.Nvidia.APIKey = "nvapi-test" cfg.Providers["nvidia"].APIKey = "nvapi-test"
cfg.Providers.Nvidia.Proxy = "http://127.0.0.1:7890" cfg.Providers["nvidia"].Proxy = "http://127.0.0.1:7890"
}, },
wantType: providerTypeHTTPCompat, wantType: providerTypeHTTPCompat,
wantAPIBase: "https://integrate.api.nvidia.com/v1", wantAPIBase: "https://integrate.api.nvidia.com/v1",
@ -71,7 +71,7 @@ func TestResolveProviderSelection(t *testing.T) {
name: "openrouter model uses openrouter defaults", name: "openrouter model uses openrouter defaults",
setup: func(cfg *config.Config) { setup: func(cfg *config.Config) {
cfg.Agents.Defaults.Model = "openrouter/auto" cfg.Agents.Defaults.Model = "openrouter/auto"
cfg.Providers.OpenRouter.APIKey = "sk-or-test" cfg.Providers["openrouter"].APIKey = "sk-or-test"
}, },
wantType: providerTypeHTTPCompat, wantType: providerTypeHTTPCompat,
wantAPIBase: "https://openrouter.ai/api/v1", wantAPIBase: "https://openrouter.ai/api/v1",
@ -80,7 +80,7 @@ func TestResolveProviderSelection(t *testing.T) {
name: "anthropic oauth routes to claude auth provider", name: "anthropic oauth routes to claude auth provider",
setup: func(cfg *config.Config) { setup: func(cfg *config.Config) {
cfg.Agents.Defaults.Model = "claude-sonnet-4-5-20250929" cfg.Agents.Defaults.Model = "claude-sonnet-4-5-20250929"
cfg.Providers.Anthropic.AuthMethod = "oauth" cfg.Providers["anthropic"].AuthMethod = "oauth"
}, },
wantType: providerTypeClaudeAuth, wantType: providerTypeClaudeAuth,
}, },
@ -88,7 +88,7 @@ func TestResolveProviderSelection(t *testing.T) {
name: "openai oauth routes to codex auth provider", name: "openai oauth routes to codex auth provider",
setup: func(cfg *config.Config) { setup: func(cfg *config.Config) {
cfg.Agents.Defaults.Model = "gpt-4o" cfg.Agents.Defaults.Model = "gpt-4o"
cfg.Providers.OpenAI.AuthMethod = "oauth" cfg.Providers["openai"].AuthMethod = "oauth"
}, },
wantType: providerTypeCodexAuth, wantType: providerTypeCodexAuth,
}, },
@ -96,7 +96,7 @@ func TestResolveProviderSelection(t *testing.T) {
name: "openai codex-cli auth routes to codex cli token provider", name: "openai codex-cli auth routes to codex cli token provider",
setup: func(cfg *config.Config) { setup: func(cfg *config.Config) {
cfg.Agents.Defaults.Model = "gpt-4o" cfg.Agents.Defaults.Model = "gpt-4o"
cfg.Providers.OpenAI.AuthMethod = "codex-cli" cfg.Providers["openai"].AuthMethod = "codex-cli"
}, },
wantType: providerTypeCodexCLIToken, wantType: providerTypeCodexCLIToken,
}, },
@ -112,7 +112,7 @@ func TestResolveProviderSelection(t *testing.T) {
name: "zhipu model uses zhipu base default", name: "zhipu model uses zhipu base default",
setup: func(cfg *config.Config) { setup: func(cfg *config.Config) {
cfg.Agents.Defaults.Model = "glm-4.7" cfg.Agents.Defaults.Model = "glm-4.7"
cfg.Providers.Zhipu.APIKey = "zhipu-key" cfg.Providers["zhipu"].APIKey = "zhipu-key"
}, },
wantType: providerTypeHTTPCompat, wantType: providerTypeHTTPCompat,
wantAPIBase: "https://open.bigmodel.cn/api/paas/v4", wantAPIBase: "https://open.bigmodel.cn/api/paas/v4",
@ -121,7 +121,7 @@ func TestResolveProviderSelection(t *testing.T) {
name: "groq model uses groq base default", name: "groq model uses groq base default",
setup: func(cfg *config.Config) { setup: func(cfg *config.Config) {
cfg.Agents.Defaults.Model = "groq/llama-3.3-70b" cfg.Agents.Defaults.Model = "groq/llama-3.3-70b"
cfg.Providers.Groq.APIKey = "gsk-key" cfg.Providers["groq"].APIKey = "gsk-key"
}, },
wantType: providerTypeHTTPCompat, wantType: providerTypeHTTPCompat,
wantAPIBase: "https://api.groq.com/openai/v1", wantAPIBase: "https://api.groq.com/openai/v1",
@ -130,7 +130,7 @@ func TestResolveProviderSelection(t *testing.T) {
name: "ollama model uses ollama base default", name: "ollama model uses ollama base default",
setup: func(cfg *config.Config) { setup: func(cfg *config.Config) {
cfg.Agents.Defaults.Model = "ollama/qwen2.5:14b" cfg.Agents.Defaults.Model = "ollama/qwen2.5:14b"
cfg.Providers.Ollama.APIKey = "ollama-key" cfg.Providers["ollama"].APIKey = "ollama-key"
}, },
wantType: providerTypeHTTPCompat, wantType: providerTypeHTTPCompat,
wantAPIBase: "http://localhost:11434/v1", wantAPIBase: "http://localhost:11434/v1",
@ -139,8 +139,8 @@ func TestResolveProviderSelection(t *testing.T) {
name: "moonshot model keeps proxy and default base", name: "moonshot model keeps proxy and default base",
setup: func(cfg *config.Config) { setup: func(cfg *config.Config) {
cfg.Agents.Defaults.Model = "moonshot/kimi-k2.5" cfg.Agents.Defaults.Model = "moonshot/kimi-k2.5"
cfg.Providers.Moonshot.APIKey = "moonshot-key" cfg.Providers["moonshot"].APIKey = "moonshot-key"
cfg.Providers.Moonshot.Proxy = "http://127.0.0.1:7890" cfg.Providers["moonshot"].Proxy = "http://127.0.0.1:7890"
}, },
wantType: providerTypeHTTPCompat, wantType: providerTypeHTTPCompat,
wantAPIBase: "https://api.moonshot.cn/v1", wantAPIBase: "https://api.moonshot.cn/v1",
@ -197,7 +197,7 @@ func TestResolveProviderSelection(t *testing.T) {
func TestCreateProviderReturnsHTTPProviderForOpenRouter(t *testing.T) { func TestCreateProviderReturnsHTTPProviderForOpenRouter(t *testing.T) {
cfg := config.DefaultConfig() cfg := config.DefaultConfig()
cfg.Agents.Defaults.Model = "openrouter/auto" cfg.Agents.Defaults.Model = "openrouter/auto"
cfg.Providers.OpenRouter.APIKey = "sk-or-test" cfg.Providers["openrouter"].APIKey = "sk-or-test"
provider, err := CreateProvider(cfg) provider, err := CreateProvider(cfg)
if err != nil { if err != nil {
@ -226,7 +226,7 @@ func TestCreateProviderReturnsCodexCliProviderForCodexCode(t *testing.T) {
func TestCreateProviderReturnsCodexProviderForCodexCliAuthMethod(t *testing.T) { func TestCreateProviderReturnsCodexProviderForCodexCliAuthMethod(t *testing.T) {
cfg := config.DefaultConfig() cfg := config.DefaultConfig()
cfg.Agents.Defaults.Provider = "openai" cfg.Agents.Defaults.Provider = "openai"
cfg.Providers.OpenAI.AuthMethod = "codex-cli" cfg.Providers["openai"].AuthMethod = "codex-cli"
provider, err := CreateProvider(cfg) provider, err := CreateProvider(cfg)
if err != nil { if err != nil {
@ -253,8 +253,8 @@ func TestCreateProviderReturnsClaudeProviderForAnthropicOAuth(t *testing.T) {
cfg := config.DefaultConfig() cfg := config.DefaultConfig()
cfg.Agents.Defaults.Provider = "anthropic" cfg.Agents.Defaults.Provider = "anthropic"
cfg.Providers.Anthropic.AuthMethod = "oauth" cfg.Providers["anthropic"].AuthMethod = "oauth"
cfg.Providers.Anthropic.APIBase = "https://proxy.example.com/v1" cfg.Providers["anthropic"].APIBase = "https://proxy.example.com/v1"
provider, err := CreateProvider(cfg) provider, err := CreateProvider(cfg)
if err != nil { if err != nil {
@ -286,7 +286,7 @@ func TestCreateProviderReturnsCodexProviderForOpenAIOAuth(t *testing.T) {
cfg := config.DefaultConfig() cfg := config.DefaultConfig()
cfg.Agents.Defaults.Provider = "openai" cfg.Agents.Defaults.Provider = "openai"
cfg.Providers.OpenAI.AuthMethod = "oauth" cfg.Providers["openai"].AuthMethod = "oauth"
provider, err := CreateProvider(cfg) provider, err := CreateProvider(cfg)
if err != nil { if err != nil {