package providers import "strings" // ModelProviderOption describes a canonical provider entry exposed to the Web UI. // It also serves as the backend-owned source of truth for shared provider metadata. type ModelProviderOption struct { ID string `json:"id"` DisplayName string `json:"display_name,omitempty"` IconSlug string `json:"icon_slug,omitempty"` Domain string `json:"domain,omitempty"` DefaultAPIBase string `json:"default_api_base"` EmptyAPIKeyAllowed bool `json:"empty_api_key_allowed"` CreateAllowed bool `json:"create_allowed"` DefaultModelAllowed bool `json:"default_model_allowed"` SupportsFetch bool `json:"supports_fetch,omitempty"` DefaultAuthMethod string `json:"default_auth_method,omitempty"` AuthMethodLocked bool `json:"auth_method_locked,omitempty"` Local bool `json:"local,omitempty"` Priority float64 `json:"priority,omitempty"` CommonModels []string `json:"common_models,omitempty"` Aliases []string `json:"aliases,omitempty"` httpAPI bool `json:"-"` } var modelProviderOptionsByName = map[string]ModelProviderOption{ "openai": { ID: "openai", DisplayName: "OpenAI", IconSlug: "openai", Domain: "openai.com", DefaultAPIBase: "https://api.openai.com/v1", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 100, CommonModels: []string{"gpt-5.4", "gpt-5.4-mini", "gpt-5.5"}, Aliases: []string{"gpt"}, httpAPI: true, }, "anthropic": { ID: "anthropic", DisplayName: "Anthropic", IconSlug: "anthropic", Domain: "anthropic.com", DefaultAPIBase: "https://api.anthropic.com/v1", CreateAllowed: true, DefaultModelAllowed: true, Priority: 95, CommonModels: []string{"claude-opus-4-7", "claude-sonnet-4-6", "claude-haiku-4-5"}, Aliases: []string{"claude"}, httpAPI: true, }, "anthropic-messages": { ID: "anthropic-messages", DisplayName: "Anthropic Messages", IconSlug: "anthropic", Domain: "anthropic.com", DefaultAPIBase: "https://api.anthropic.com/v1", CreateAllowed: true, DefaultModelAllowed: true, Priority: 94, CommonModels: []string{"claude-opus-4-7", "claude-sonnet-4-6", "claude-haiku-4-5"}, httpAPI: true, }, "gemini": { ID: "gemini", DisplayName: "Google Gemini", IconSlug: "googlegemini", Domain: "gemini.google.com", DefaultAPIBase: "https://generativelanguage.googleapis.com/v1beta", CreateAllowed: true, DefaultModelAllowed: true, Priority: 90, CommonModels: []string{"gemini-3.1-pro-preview", "gemini-3-flash-preview", "gemini-3.1-flash-lite"}, Aliases: []string{"google"}, httpAPI: true, }, "deepseek": { ID: "deepseek", DisplayName: "DeepSeek", IconSlug: "deepseek", Domain: "deepseek.com", DefaultAPIBase: "https://api.deepseek.com/v1", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 85, CommonModels: []string{"deepseek-v4-flash", "deepseek-v4-pro"}, httpAPI: true, }, "openrouter": { ID: "openrouter", DisplayName: "OpenRouter", IconSlug: "openrouter", Domain: "openrouter.ai", DefaultAPIBase: "https://openrouter.ai/api/v1", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 80, CommonModels: []string{ "openai/gpt-5.4", "anthropic/claude-opus-4.7", "google/gemini-3.1-pro-preview", "qwen/qwen3-coder-next", }, httpAPI: true, }, "qwen-portal": { ID: "qwen-portal", DisplayName: "Qwen", IconSlug: "alibabacloud", Domain: "qwenlm.ai", DefaultAPIBase: "https://dashscope.aliyuncs.com/compatible-mode/v1", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 75, CommonModels: []string{"qwen3.6-max-preview", "qwen3.6-plus", "qwen3.6-flash", "qwen3-coder-next"}, Aliases: []string{"qwen"}, httpAPI: true, }, "qwen-intl": { ID: "qwen-intl", DisplayName: "Qwen International", IconSlug: "alibabacloud", Domain: "alibabacloud.com", DefaultAPIBase: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 74, CommonModels: []string{"qwen3.6-max-preview", "qwen3.6-plus", "qwen3.6-flash", "qwen3-coder-next"}, Aliases: []string{"qwen-international", "dashscope-intl"}, httpAPI: true, }, "moonshot": { ID: "moonshot", DisplayName: "Moonshot", Domain: "moonshot.ai", DefaultAPIBase: "https://api.moonshot.cn/v1", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 70, CommonModels: []string{ "kimi-k2.5", "kimi-k2-thinking", "kimi-k2-thinking-turbo", "kimi-k2-turbo-preview", }, httpAPI: true, }, "volcengine": { ID: "volcengine", DisplayName: "Volcengine", IconSlug: "bytedance", Domain: "volcengine.com", DefaultAPIBase: "https://ark.cn-beijing.volces.com/api/v3", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 69, CommonModels: []string{ "doubao-seed-1-6-251015", "doubao-seed-1-6-flash-250828", "doubao-seed-1-6-thinking", }, httpAPI: true, }, "zhipu": { ID: "zhipu", DisplayName: "Zhipu AI", IconSlug: "zhipu", Domain: "zhipuai.cn", DefaultAPIBase: "https://open.bigmodel.cn/api/paas/v4", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 68, CommonModels: []string{"glm-5", "glm-4.7", "glm-4.5-air", "glm-4-flash-250414"}, Aliases: []string{"glm"}, httpAPI: true, }, "groq": { ID: "groq", DisplayName: "Groq", IconSlug: "groq", Domain: "groq.com", DefaultAPIBase: "https://api.groq.com/openai/v1", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 65, CommonModels: []string{ "openai/gpt-oss-120b", "openai/gpt-oss-20b", "llama-3.3-70b-versatile", "qwen/qwen3-32b", }, httpAPI: true, }, "mistral": { ID: "mistral", DisplayName: "Mistral AI", IconSlug: "mistralai", Domain: "mistral.ai", DefaultAPIBase: "https://api.mistral.ai/v1", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 64, CommonModels: []string{ "mistral-large-latest", "mistral-medium-3-5", "mistral-small-latest", "devstral-latest", }, httpAPI: true, }, "nvidia": { ID: "nvidia", DisplayName: "NVIDIA", IconSlug: "nvidia", Domain: "nvidia.com", DefaultAPIBase: "https://integrate.api.nvidia.com/v1", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 63, CommonModels: []string{ "openai/gpt-oss-120b", "openai/gpt-oss-20b", "qwen/qwen3-coder-480b-a35b-instruct", "qwen/qwen3-next-80b-a3b-thinking", }, httpAPI: true, }, "cerebras": { ID: "cerebras", DisplayName: "Cerebras", IconSlug: "cerebras", Domain: "cerebras.ai", DefaultAPIBase: "https://api.cerebras.ai/v1", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 62, CommonModels: []string{"gpt-oss-120b", "zai-glm-4.7"}, httpAPI: true, }, "azure": { ID: "azure", DisplayName: "Azure OpenAI", IconSlug: "microsoftazure", Domain: "azure.com", CreateAllowed: true, DefaultModelAllowed: true, Priority: 61, Aliases: []string{"azure-openai"}, httpAPI: true, }, "bedrock": { ID: "bedrock", DisplayName: "AWS Bedrock", IconSlug: "amazonwebservices", Domain: "aws.amazon.com", EmptyAPIKeyAllowed: true, CreateAllowed: true, DefaultModelAllowed: true, Priority: 60, }, "github-copilot": { ID: "github-copilot", DisplayName: "GitHub Copilot", IconSlug: "githubcopilot", Domain: "github.com", DefaultAPIBase: "localhost:4321", EmptyAPIKeyAllowed: true, CreateAllowed: true, DefaultModelAllowed: true, Local: true, Priority: 55, Aliases: []string{"copilot"}, }, "antigravity": { ID: "antigravity", DisplayName: "Google Code Assist", Domain: "antigravity.google", EmptyAPIKeyAllowed: true, CreateAllowed: true, DefaultModelAllowed: true, DefaultAuthMethod: "oauth", AuthMethodLocked: true, Priority: 54, Aliases: []string{"google-antigravity"}, }, "claude-cli": { ID: "claude-cli", DisplayName: "Claude CLI", IconSlug: "anthropic", Domain: "anthropic.com", EmptyAPIKeyAllowed: true, CreateAllowed: true, DefaultModelAllowed: true, Local: true, Priority: 53, Aliases: []string{"claudecli"}, }, "codex-cli": { ID: "codex-cli", DisplayName: "Codex CLI", IconSlug: "openai", Domain: "openai.com", EmptyAPIKeyAllowed: true, CreateAllowed: true, DefaultModelAllowed: true, Local: true, Priority: 52, Aliases: []string{"codexcli"}, }, "ollama": { ID: "ollama", DisplayName: "Ollama", IconSlug: "ollama", Domain: "ollama.com", DefaultAPIBase: "http://localhost:11434/v1", EmptyAPIKeyAllowed: true, CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Local: true, Priority: 50, httpAPI: true, }, "vllm": { ID: "vllm", DisplayName: "VLLM", Domain: "vllm.ai", DefaultAPIBase: "http://localhost:8000/v1", EmptyAPIKeyAllowed: true, CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Local: true, Priority: 49, httpAPI: true, }, "lmstudio": { ID: "lmstudio", DisplayName: "LM Studio", Domain: "lmstudio.ai", DefaultAPIBase: "http://localhost:1234/v1", EmptyAPIKeyAllowed: true, CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Local: true, Priority: 48, httpAPI: true, }, "gpt4free": { ID: "gpt4free", DisplayName: "GPT4Free", Domain: "g4f.dev", DefaultAPIBase: "http://localhost:1337/v1", EmptyAPIKeyAllowed: true, CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Local: true, Priority: 47.5, Aliases: []string{"g4f"}, httpAPI: true, }, "elevenlabs": { ID: "elevenlabs", DisplayName: "ElevenLabs ASR", IconSlug: "elevenlabs", Domain: "elevenlabs.io", DefaultAPIBase: "https://api.elevenlabs.io", CreateAllowed: true, DefaultModelAllowed: false, Priority: 47, httpAPI: true, }, "venice": { ID: "venice", DisplayName: "Venice AI", IconSlug: "venice", Domain: "venice.ai", DefaultAPIBase: "https://api.venice.ai/api/v1", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 45, httpAPI: true, }, "shengsuanyun": { ID: "shengsuanyun", DisplayName: "ShengsuanYun", Domain: "shengsuanyun.com", DefaultAPIBase: "https://router.shengsuanyun.com/api/v1", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 44, httpAPI: true, }, "siliconflow": { ID: "siliconflow", DisplayName: "SiliconFlow", Domain: "siliconflow.cn", DefaultAPIBase: "https://api.siliconflow.cn/v1", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 43.5, httpAPI: true, }, "vivgrid": { ID: "vivgrid", DisplayName: "Vivgrid", Domain: "vivgrid.com", DefaultAPIBase: "https://api.vivgrid.com/v1", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 43, httpAPI: true, }, "minimax": { ID: "minimax", DisplayName: "MiniMax", Domain: "minimaxi.com", DefaultAPIBase: "https://api.minimaxi.com/v1", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 42, httpAPI: true, }, "longcat": { ID: "longcat", DisplayName: "LongCat", Domain: "longcat.chat", DefaultAPIBase: "https://api.longcat.chat/openai", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 41, httpAPI: true, }, "modelscope": { ID: "modelscope", DisplayName: "ModelScope", Domain: "modelscope.cn", DefaultAPIBase: "https://api-inference.modelscope.cn/v1", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 40, httpAPI: true, }, "mimo": { ID: "mimo", DisplayName: "Xiaomi MiMo", IconSlug: "xiaomi", Domain: "xiaomi.com", DefaultAPIBase: "https://api.xiaomimimo.com/v1", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 39, httpAPI: true, }, "avian": { ID: "avian", DisplayName: "Avian", Domain: "avian.io", DefaultAPIBase: "https://api.avian.io/v1", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 38, httpAPI: true, }, "zai": { ID: "zai", DisplayName: "Z.ai", Domain: "z.ai", DefaultAPIBase: "https://api.z.ai/api/coding/paas/v4", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 37, CommonModels: []string{"glm-5", "glm-4.7", "glm-4.5-air", "glm-4-flash-250414"}, Aliases: []string{"z.ai", "z-ai"}, httpAPI: true, }, "alibaba-coding": { ID: "alibaba-coding", DisplayName: "Alibaba Coding Plan", IconSlug: "alibabacloud", Domain: "alibabacloud.com", DefaultAPIBase: "https://coding-intl.dashscope.aliyuncs.com/v1", CreateAllowed: true, DefaultModelAllowed: true, Priority: 36.5, CommonModels: []string{"qwen3.6-plus", "kimi-k2.5", "glm-5", "MiniMax-M2.5"}, Aliases: []string{"coding-plan", "qwen-coding"}, httpAPI: true, }, "alibaba-coding-anthropic": { ID: "alibaba-coding-anthropic", DisplayName: "Alibaba Coding Plan (Anthropic)", IconSlug: "alibabacloud", Domain: "alibabacloud.com", DefaultAPIBase: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic", CreateAllowed: true, DefaultModelAllowed: true, Priority: 36.25, CommonModels: []string{"qwen3.6-plus", "kimi-k2.5", "glm-5", "MiniMax-M2.5"}, Aliases: []string{"coding-plan-anthropic"}, httpAPI: true, }, "novita": { ID: "novita", DisplayName: "Novita AI", Domain: "novita.ai", DefaultAPIBase: "https://api.novita.ai/openai", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 36, httpAPI: true, }, "litellm": { ID: "litellm", DisplayName: "LiteLLM", Domain: "litellm.ai", DefaultAPIBase: "http://localhost:4000/v1", CreateAllowed: true, DefaultModelAllowed: true, SupportsFetch: true, Priority: 35, httpAPI: true, }, "qwen-us": { ID: "qwen-us", DisplayName: "Qwen US", IconSlug: "alibabacloud", Domain: "alibabacloud.com", DefaultAPIBase: "https://dashscope-us.aliyuncs.com/compatible-mode/v1", CreateAllowed: true, DefaultModelAllowed: true, Priority: 34, CommonModels: []string{"qwen3.6-max-preview", "qwen3.6-plus", "qwen3.6-flash", "qwen3-coder-next"}, Aliases: []string{"dashscope-us"}, httpAPI: true, }, } var normalizedModelProviderAliasesByName = buildModelProviderAliasMap() func buildModelProviderAliasMap() map[string]string { totalAliases := 0 for _, option := range modelProviderOptionsByName { totalAliases += len(option.Aliases) } aliases := make(map[string]string, len(modelProviderOptionsByName)+totalAliases) for provider, option := range modelProviderOptionsByName { aliases[provider] = provider for _, alias := range option.Aliases { normalized := strings.ToLower(strings.TrimSpace(alias)) if normalized == "" { continue } aliases[normalized] = provider } } return aliases } func modelProviderOptionForName(provider string) (ModelProviderOption, bool) { normalized := NormalizeProvider(provider) if normalized == "" { return ModelProviderOption{}, false } option, ok := modelProviderOptionsByName[normalized] return option, ok }