Files
2026-07-13 13:00:08 +08:00

891 lines
30 KiB
Go

package config
import (
"sort"
"strings"
"reasonix/internal/provider"
)
// ProviderPreset is a curated, editable provider starter template. Presets are
// not secret-bearing: API key values still live only in Reasonix home .env.
type ProviderPreset struct {
ID string
Label string
Description string
KeyEnv string
Entries []ProviderEntry
}
const ProviderPresetVersion = 1
// CuratedProviderPresets returns one-click provider templates for common
// OpenAI-compatible and Anthropic-compatible coding-plan services. These are
// intentionally editable after installation; they reduce setup friction without
// turning fast-moving third-party catalogs into hard runtime dependencies.
func CuratedProviderPresets() []ProviderPreset {
presets := cloneProviderPresets(curatedProviderPresets)
sort.SliceStable(presets, func(i, j int) bool {
return providerPresetDisplayRank(presets[i].ID) < providerPresetDisplayRank(presets[j].ID)
})
return presets
}
// CuratedProviderPreset returns a single provider preset by id.
func CuratedProviderPreset(id string) (ProviderPreset, bool) {
id = strings.ToLower(strings.TrimSpace(id))
for _, p := range curatedProviderPresets {
if p.ID == id {
return cloneProviderPreset(p), true
}
}
return ProviderPreset{}, false
}
func providerPresetDisplayRank(id string) int {
switch {
case id == "glm-cn" || id == "zai-global" || strings.HasPrefix(id, "glm-coding-plan-") || strings.HasPrefix(id, "zai-coding-plan-"):
return 0
case strings.HasPrefix(id, "longcat-"):
return 1
case strings.HasPrefix(id, "kimi-"):
return 2
case strings.HasPrefix(id, "minimax-"):
return 3
default:
return 4
}
}
var (
kimiAPIModels = []string{"kimi-k2.7-code", "kimi-k2.7-code-highspeed", "kimi-k2.6", "kimi-k2.5"}
kimiAPIVisionModels = []string{"kimi-k2.7-code", "kimi-k2.7-code-highspeed", "kimi-k2.6", "kimi-k2.5"}
kimiCodingModels = []string{"kimi-for-coding"}
longCat20Models = []string{"LongCat-2.0"}
mimoV25Models = []string{"mimo-v2.5-pro", "mimo-v2.5"}
mimoV25VisionModels = []string{"mimo-v2.5"}
minimaxMSeriesModels = []string{"MiniMax-M3", "MiniMax-M2.7", "MiniMax-M2.7-highspeed"}
minimaxMSeriesVisionModels = []string{"MiniMax-M3"}
glmAPIModels = []string{"glm-5.2", "glm-5.1", "glm-5", "glm-5-turbo", "glm-5v-turbo", "glm-4.7", "glm-4.7-flash", "glm-4.7-flashx", "glm-4.6", "glm-4.5", "glm-4.5-air", "glm-4.5-flash"}
glmAPIVisionModels = []string{"glm-5v-turbo"}
glmCodingModels = []string{"glm-5.2", "glm-5.1", "glm-5", "glm-4.7"}
glmAnthropicModels = []string{"glm-5.2[1m]", "glm-5.2", "glm-5.1", "glm-5", "glm-4.7", "glm-4.5-air"}
qwenAPIModels = []string{"qwen3.7-plus", "qwen3.7-max", "qwen3.6-plus", "qwen3.5-plus", "qwen3-max-2026-01-23", "qwen3-coder-next", "qwen3-coder-plus", "MiniMax-M2.5", "glm-5", "glm-4.7", "kimi-k2.5"}
qwenAPIVisionModels = []string{"qwen3.7-plus", "qwen3.6-plus", "qwen3.5-plus", "kimi-k2.5"}
qwenPlanModels = []string{"qwen3.7-plus", "qwen3.6-plus", "kimi-k2.5", "glm-5", "MiniMax-M2.5", "qwen3.5-plus", "qwen3-max-2026-01-23", "qwen3-coder-next", "qwen3-coder-plus", "glm-4.7"}
qwenPlanVisionModels = []string{"qwen3.7-plus", "qwen3.6-plus", "qwen3.5-plus", "kimi-k2.5"}
stepfunPlanModels = []string{"step-3.7-flash", "step-3.5-flash", "step-3.5-flash-2603"}
opencodeGoModels = []string{"glm-5.2", "glm-5.1", "kimi-k2.7-code", "kimi-k2.6", "deepseek-v4-pro", "deepseek-v4-flash", "mimo-v2.5-pro", "mimo-v2.5"}
opencodeGoAnthropicModels = []string{"qwen3.7-plus", "qwen3.7-max", "qwen3.6-plus", "minimax-m3", "minimax-m2.7", "minimax-m2.5"}
opencodeZenAnthropicModels = []string{"claude-sonnet-4-6", "claude-opus-4-8", "claude-haiku-4-5", "qwen3.6-plus", "qwen3.5-plus", "qwen3.6-plus-free"}
opencodeZenAnthropicVisionModels = []string{"claude-sonnet-4-6", "claude-opus-4-8", "claude-haiku-4-5"}
novitaModels = []string{"zai-org/glm-5.2", "moonshotai/kimi-k2.7-code", "minimax/minimax-m3", "deepseek/deepseek-v4-pro", "deepseek/deepseek-v4-flash", "qwen/qwen3.7-max", "qwen/qwen3.6-plus", "zai-org/glm-5v-turbo"}
gmiModels = []string{"zai-org/GLM-5.2-FP8", "deepseek-ai/DeepSeek-V4-Pro", "deepseek-ai/DeepSeek-V4-Flash", "moonshotai/Kimi-K2.7-Code", "anthropic/claude-sonnet-4.6", "openai/gpt-5.5"}
vercelModels = []string{"anthropic/claude-sonnet-4.6", "anthropic/claude-opus-4.8", "openai/gpt-5.4", "openai/gpt-5.4-pro", "moonshotai/kimi-k2.7-code", "zai/glm-5.2", "deepseek/deepseek-v4-pro"}
huggingFaceModels = []string{"zai-org/GLM-5.2", "deepseek-ai/DeepSeek-V3.2", "Qwen/Qwen3.5-72B-Instruct"}
nvidiaModels = []string{"nvidia/nemotron-3-nano-30b-a3b", "nvidia/nemotron-3-super-120b-a12b", "nvidia/nemotron-3-ultra-550b-a55b", "deepseek-ai/deepseek-v4-pro", "qwen/qwen3.5-397b-a17b"}
ollamaCloudModels = []string{"glm-5.2", "kimi-k2.7-code", "deepseek-v4-pro", "deepseek-v4-flash", "minimax-m3", "nemotron-3-nano:30b", "qwen3-coder-next"}
)
var curatedProviderPresets = []ProviderPreset{
{
ID: "longcat-openai",
Label: "LongCat OpenAI",
Description: "LongCat Platform OpenAI-compatible endpoint for LongCat-2.0.",
KeyEnv: "LONGCAT_API_KEY",
Entries: []ProviderEntry{{
Name: "longcat-openai",
Kind: "openai",
BaseURL: "https://api.longcat.chat/openai/v1",
ModelsURL: "https://api.longcat.chat/openai/v1/models",
Models: longCat20Models,
Default: "LongCat-2.0",
APIKeyEnv: "LONGCAT_API_KEY",
ContextWindow: 131072,
Prices: longCat20Prices(longCat20Models),
Thinking: "enabled",
SupportedEfforts: []string{"enabled", "disabled"},
DefaultEffort: "enabled",
}},
},
{
ID: "longcat-anthropic",
Label: "LongCat Anthropic",
Description: "LongCat Platform Anthropic-compatible Messages endpoint for LongCat-2.0.",
KeyEnv: "LONGCAT_API_KEY",
Entries: []ProviderEntry{{
Name: "longcat-anthropic",
Kind: "anthropic",
BaseURL: "https://api.longcat.chat/anthropic",
ModelsURL: "https://api.longcat.chat/anthropic/v1/models",
Models: longCat20Models,
Default: "LongCat-2.0",
APIKeyEnv: "LONGCAT_API_KEY",
AuthHeader: true,
Thinking: "enabled",
SupportedEfforts: []string{"enabled", "disabled"},
DefaultEffort: "enabled",
ContextWindow: 131072,
Prices: longCat20Prices(longCat20Models),
}},
},
{
ID: "kimi-cn",
Label: "Kimi CN API",
Description: "Moonshot Kimi China OpenAI-compatible API.",
KeyEnv: "KIMI_API_KEY",
Entries: []ProviderEntry{{
Name: "kimi-cn",
Kind: "openai",
BaseURL: "https://api.moonshot.cn/v1",
Models: kimiAPIModels,
VisionModels: kimiAPIVisionModels,
Default: "kimi-k2.7-code",
APIKeyEnv: "KIMI_API_KEY",
BalanceURL: "https://api.moonshot.cn/v1/users/me/balance",
ContextWindow: 262144,
ReasoningProtocol: ReasoningProtocolNone,
}},
},
{
ID: "kimi-global",
Label: "Kimi Global API",
Description: "Moonshot Kimi international OpenAI-compatible API.",
KeyEnv: "MOONSHOT_API_KEY",
Entries: []ProviderEntry{{
Name: "kimi-global",
Kind: "openai",
BaseURL: "https://api.moonshot.ai/v1",
Models: kimiAPIModels,
VisionModels: kimiAPIVisionModels,
Default: "kimi-k2.7-code",
APIKeyEnv: "MOONSHOT_API_KEY",
BalanceURL: "https://api.moonshot.ai/v1/users/me/balance",
ContextWindow: 262144,
ReasoningProtocol: ReasoningProtocolNone,
}},
},
{
ID: "kimi-coding-plan",
Label: "Kimi Coding Plan",
Description: "Kimi Coding Plan via its dedicated Anthropic-compatible endpoint.",
KeyEnv: "KIMI_CODING_API_KEY",
Entries: []ProviderEntry{{
Name: "kimi-coding-plan",
Kind: "anthropic",
BaseURL: "https://api.kimi.com/coding/",
Models: kimiCodingModels,
VisionModels: kimiCodingModels,
Default: "kimi-for-coding",
APIKeyEnv: "KIMI_CODING_API_KEY",
Headers: map[string]string{"User-Agent": "claude-code/0.1.0"},
Thinking: "adaptive",
ContextWindow: 262144,
}},
},
{
ID: "mimo-api",
Label: "MiMo API",
Description: "Xiaomi MiMo direct API with text and vision-capable models.",
KeyEnv: "MIMO_API_KEY",
Entries: []ProviderEntry{{
Name: "mimo-api",
Kind: "openai",
BaseURL: "https://api.xiaomimimo.com/v1",
Models: mimoV25Models,
VisionModels: mimoV25VisionModels,
Default: "mimo-v2.5-pro",
APIKeyEnv: "MIMO_API_KEY",
ContextWindow: 1048576,
Prices: mimoDomesticPrices(mimoV25Models),
NoProxy: true,
}},
},
{
ID: "mimo-anthropic",
Label: "MiMo Anthropic",
Description: "Xiaomi MiMo direct Anthropic-compatible endpoint.",
KeyEnv: "MIMO_API_KEY",
Entries: []ProviderEntry{{
Name: "mimo-anthropic",
Kind: "anthropic",
BaseURL: "https://api.xiaomimimo.com/anthropic",
Models: mimoV25Models,
VisionModels: mimoV25VisionModels,
Default: "mimo-v2.5-pro",
APIKeyEnv: "MIMO_API_KEY",
Thinking: "adaptive",
ContextWindow: 1048576,
Prices: mimoDomesticPrices(mimoV25Models),
NoProxy: true,
}},
},
{
ID: "mimo-token-plan-cn",
Label: "MiMo Token Plan CN",
Description: "Xiaomi MiMo token-plan China endpoint.",
KeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
Entries: []ProviderEntry{{
Name: "mimo-token-plan-cn",
Kind: "openai",
BaseURL: "https://token-plan-cn.xiaomimimo.com/v1",
Models: mimoV25Models,
VisionModels: mimoV25VisionModels,
Default: "mimo-v2.5-pro",
APIKeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
ContextWindow: 1048576,
Prices: mimoDomesticPrices(mimoV25Models),
NoProxy: true,
}},
},
{
ID: "mimo-token-plan-cn-anthropic",
Label: "MiMo Token Plan CN Anthropic",
Description: "Xiaomi MiMo token-plan China Anthropic-compatible endpoint.",
KeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
Entries: []ProviderEntry{{
Name: "mimo-token-plan-cn-anthropic",
Kind: "anthropic",
BaseURL: "https://token-plan-cn.xiaomimimo.com/anthropic",
Models: mimoV25Models,
VisionModels: mimoV25VisionModels,
Default: "mimo-v2.5-pro",
APIKeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
Thinking: "adaptive",
ContextWindow: 1048576,
Prices: mimoDomesticPrices(mimoV25Models),
NoProxy: true,
}},
},
{
ID: "mimo-token-plan-sgp",
Label: "MiMo Token Plan SGP",
Description: "Xiaomi MiMo token-plan Singapore endpoint.",
KeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
Entries: []ProviderEntry{{
Name: "mimo-token-plan-sgp",
Kind: "openai",
BaseURL: "https://token-plan-sgp.xiaomimimo.com/v1",
Models: mimoV25Models,
VisionModels: mimoV25VisionModels,
Default: "mimo-v2.5-pro",
APIKeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
ContextWindow: 1048576,
Prices: mimoDomesticPrices(mimoV25Models),
}},
},
{
ID: "mimo-token-plan-sgp-anthropic",
Label: "MiMo Token Plan SGP Anthropic",
Description: "Xiaomi MiMo token-plan Singapore Anthropic-compatible endpoint.",
KeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
Entries: []ProviderEntry{{
Name: "mimo-token-plan-sgp-anthropic",
Kind: "anthropic",
BaseURL: "https://token-plan-sgp.xiaomimimo.com/anthropic",
Models: mimoV25Models,
VisionModels: mimoV25VisionModels,
Default: "mimo-v2.5-pro",
APIKeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
Thinking: "adaptive",
ContextWindow: 1048576,
Prices: mimoDomesticPrices(mimoV25Models),
}},
},
{
ID: "mimo-token-plan-ams",
Label: "MiMo Token Plan AMS",
Description: "Xiaomi MiMo token-plan Amsterdam endpoint.",
KeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
Entries: []ProviderEntry{{
Name: "mimo-token-plan-ams",
Kind: "openai",
BaseURL: "https://token-plan-ams.xiaomimimo.com/v1",
Models: mimoV25Models,
VisionModels: mimoV25VisionModels,
Default: "mimo-v2.5-pro",
APIKeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
ContextWindow: 1048576,
Prices: mimoDomesticPrices(mimoV25Models),
}},
},
{
ID: "mimo-token-plan-ams-anthropic",
Label: "MiMo Token Plan AMS Anthropic",
Description: "Xiaomi MiMo token-plan Amsterdam Anthropic-compatible endpoint.",
KeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
Entries: []ProviderEntry{{
Name: "mimo-token-plan-ams-anthropic",
Kind: "anthropic",
BaseURL: "https://token-plan-ams.xiaomimimo.com/anthropic",
Models: mimoV25Models,
VisionModels: mimoV25VisionModels,
Default: "mimo-v2.5-pro",
APIKeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
Thinking: "adaptive",
ContextWindow: 1048576,
Prices: mimoDomesticPrices(mimoV25Models),
}},
},
{
ID: "minimax-cn-api",
Label: "MiniMax CN API",
Description: "MiniMax China OpenAI-compatible M-series API endpoint.",
KeyEnv: "MINIMAX_API_KEY",
Entries: []ProviderEntry{{
Name: "minimax-cn-api",
Kind: "openai",
BaseURL: "https://api.minimaxi.com/v1",
Models: minimaxMSeriesModels,
VisionModels: minimaxMSeriesVisionModels,
Default: "MiniMax-M3",
APIKeyEnv: "MINIMAX_API_KEY",
ContextWindow: 1048576,
ExtraBody: map[string]any{"reasoning_split": true},
}},
},
{
ID: "minimax-global-api",
Label: "MiniMax Global API",
Description: "MiniMax international OpenAI-compatible M-series API endpoint.",
KeyEnv: "MINIMAX_API_KEY",
Entries: []ProviderEntry{{
Name: "minimax-global-api",
Kind: "openai",
BaseURL: "https://api.minimax.io/v1",
Models: minimaxMSeriesModels,
VisionModels: minimaxMSeriesVisionModels,
Default: "MiniMax-M3",
APIKeyEnv: "MINIMAX_API_KEY",
ContextWindow: 1048576,
ExtraBody: map[string]any{"reasoning_split": true},
}},
},
{
ID: "minimax-cn-anthropic",
Label: "MiniMax CN Anthropic",
Description: "MiniMax China Anthropic-compatible M-series endpoint.",
KeyEnv: "MINIMAX_PLAN_API_KEY",
Entries: []ProviderEntry{{
Name: "minimax-cn-anthropic",
Kind: "anthropic",
BaseURL: "https://api.minimaxi.com/anthropic",
Models: minimaxMSeriesModels,
VisionModels: minimaxMSeriesVisionModels,
Default: "MiniMax-M3",
APIKeyEnv: "MINIMAX_PLAN_API_KEY",
AuthHeader: true,
ContextWindow: 1048576,
}},
},
{
ID: "minimax-global-anthropic",
Label: "MiniMax Global Anthropic",
Description: "MiniMax international Anthropic-compatible endpoint with Bearer auth.",
KeyEnv: "MINIMAX_API_KEY",
Entries: []ProviderEntry{{
Name: "minimax-global-anthropic",
Kind: "anthropic",
BaseURL: "https://api.minimax.io/anthropic",
Models: minimaxMSeriesModels,
VisionModels: minimaxMSeriesVisionModels,
Default: "MiniMax-M3",
APIKeyEnv: "MINIMAX_API_KEY",
AuthHeader: true,
ContextWindow: 1048576,
}},
},
{
ID: "glm-cn",
Label: "GLM CN API",
Description: "Zhipu GLM China OpenAI-compatible API with thinking controls.",
KeyEnv: "GLM_API_KEY",
Entries: []ProviderEntry{{
Name: "glm-cn",
Kind: "openai",
BaseURL: "https://open.bigmodel.cn/api/paas/v4",
Models: glmAPIModels,
VisionModels: glmAPIVisionModels,
Default: "glm-5.2",
APIKeyEnv: "GLM_API_KEY",
ContextWindow: 1000000,
}},
},
{
ID: "zai-global",
Label: "Z.AI Global API",
Description: "Z.AI international OpenAI-compatible GLM API.",
KeyEnv: "ZAI_API_KEY",
Entries: []ProviderEntry{{
Name: "zai-global",
Kind: "openai",
BaseURL: "https://api.z.ai/api/paas/v4",
Models: glmAPIModels,
VisionModels: glmAPIVisionModels,
Default: "glm-5.2",
APIKeyEnv: "ZAI_API_KEY",
ContextWindow: 1000000,
}},
},
{
ID: "glm-coding-plan-cn",
Label: "GLM Coding Plan CN",
Description: "Zhipu GLM China coding-plan endpoint.",
KeyEnv: "GLM_PLAN_API_KEY",
Entries: []ProviderEntry{{
Name: "glm-coding-plan-cn",
Kind: "openai",
BaseURL: "https://open.bigmodel.cn/api/coding/paas/v4",
Models: glmCodingModels,
Default: "glm-5.2",
APIKeyEnv: "GLM_PLAN_API_KEY",
ContextWindow: 1000000,
NoProxy: true,
}},
},
{
ID: "glm-coding-plan-cn-anthropic",
Label: "GLM Coding Plan CN Anthropic",
Description: "Zhipu GLM China coding-plan Anthropic-compatible endpoint.",
KeyEnv: "GLM_PLAN_API_KEY",
Entries: []ProviderEntry{{
Name: "glm-coding-plan-cn-anthropic",
Kind: "anthropic",
BaseURL: "https://open.bigmodel.cn/api/anthropic",
Models: glmAnthropicModels,
Default: "glm-5.2[1m]",
APIKeyEnv: "GLM_PLAN_API_KEY",
AuthHeader: true,
Thinking: "adaptive",
ContextWindow: 1000000,
NoProxy: true,
}},
},
{
ID: "zai-coding-plan-global",
Label: "Z.AI Coding Plan Global",
Description: "Z.AI international coding-plan endpoint.",
KeyEnv: "ZAI_CODING_API_KEY",
Entries: []ProviderEntry{{
Name: "zai-coding-plan-global",
Kind: "openai",
BaseURL: "https://api.z.ai/api/coding/paas/v4",
Models: glmCodingModels,
Default: "glm-5.2",
APIKeyEnv: "ZAI_CODING_API_KEY",
ContextWindow: 1000000,
}},
},
{
ID: "zai-coding-plan-global-anthropic",
Label: "Z.AI Coding Plan Global Anthropic",
Description: "Z.AI international coding-plan Anthropic-compatible endpoint.",
KeyEnv: "ZAI_CODING_API_KEY",
Entries: []ProviderEntry{{
Name: "zai-coding-plan-global-anthropic",
Kind: "anthropic",
BaseURL: "https://api.z.ai/api/anthropic",
Models: glmAnthropicModels,
Default: "glm-5.2[1m]",
APIKeyEnv: "ZAI_CODING_API_KEY",
AuthHeader: true,
Thinking: "adaptive",
ContextWindow: 1000000,
}},
},
{
ID: "opencode-go",
Label: "OpenCode Go",
Description: "OpenCode Go relay with per-model capability overrides.",
KeyEnv: "OPENCODE_GO_API_KEY",
Entries: []ProviderEntry{{
Name: "opencode-go",
Kind: "openai",
BaseURL: "https://opencode.ai/zen/go/v1",
Models: opencodeGoModels,
Default: "glm-5.2",
APIKeyEnv: "OPENCODE_GO_API_KEY",
ContextWindow: 128000,
ModelOverrides: map[string]ProviderModelOverride{
"deepseek-v4-flash": {
ReasoningProtocol: ReasoningProtocolDeepSeek,
SupportedEfforts: []string{"disabled", "high", "max"},
DefaultEffort: "high",
},
"deepseek-v4-pro": {
ReasoningProtocol: ReasoningProtocolDeepSeek,
SupportedEfforts: []string{"disabled", "high", "max"},
DefaultEffort: "high",
},
"kimi-k2.6": {
ReasoningProtocol: ReasoningProtocolOpenAI,
SupportedEfforts: []string{"low", "medium", "high"},
DefaultEffort: "high",
},
"kimi-k2.7-code": {
ReasoningProtocol: ReasoningProtocolOpenAI,
SupportedEfforts: []string{"low", "medium", "high"},
DefaultEffort: "high",
},
},
}},
},
{
ID: "opencode-go-anthropic",
Label: "OpenCode Go Anthropic",
Description: "OpenCode Go subscription Anthropic-compatible route for Qwen and MiniMax models.",
KeyEnv: "OPENCODE_GO_API_KEY",
Entries: []ProviderEntry{{
Name: "opencode-go-anthropic",
Kind: "anthropic",
BaseURL: "https://opencode.ai/zen/go",
Models: opencodeGoAnthropicModels,
VisionModels: []string{"qwen3.7-plus", "qwen3.6-plus"},
Default: "qwen3.7-plus",
APIKeyEnv: "OPENCODE_GO_API_KEY",
Thinking: "adaptive",
ContextWindow: 262144,
}},
},
{
ID: "opencode-zen-anthropic",
Label: "OpenCode Zen Anthropic",
Description: "OpenCode Zen Anthropic-compatible route for Claude and Qwen models.",
KeyEnv: "OPENCODE_API_KEY",
Entries: []ProviderEntry{{
Name: "opencode-zen-anthropic",
Kind: "anthropic",
BaseURL: "https://opencode.ai/zen",
Models: opencodeZenAnthropicModels,
VisionModels: opencodeZenAnthropicVisionModels,
Default: "claude-sonnet-4-6",
APIKeyEnv: "OPENCODE_API_KEY",
ContextWindow: 262144,
}},
},
{
ID: "qwen-cn",
Label: "Qwen CN API",
Description: "Alibaba DashScope China standard OpenAI-compatible endpoint.",
KeyEnv: "QWEN_API_KEY",
Entries: []ProviderEntry{{
Name: "qwen-cn",
Kind: "openai",
BaseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
Models: qwenAPIModels,
VisionModels: qwenAPIVisionModels,
Default: "qwen3.7-plus",
APIKeyEnv: "QWEN_API_KEY",
NoProxy: true,
}},
},
{
ID: "qwen-global",
Label: "Qwen Global API",
Description: "Alibaba DashScope international standard OpenAI-compatible endpoint.",
KeyEnv: "QWEN_API_KEY",
Entries: []ProviderEntry{{
Name: "qwen-global",
Kind: "openai",
BaseURL: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
Models: qwenAPIModels,
VisionModels: qwenAPIVisionModels,
Default: "qwen3.7-plus",
APIKeyEnv: "QWEN_API_KEY",
}},
},
{
ID: "qwen-coding-plan-cn",
Label: "Qwen Coding Plan CN",
Description: "Alibaba Cloud Qwen Coding Plan China endpoint.",
KeyEnv: "QWEN_CODING_API_KEY",
Entries: []ProviderEntry{{
Name: "qwen-coding-plan-cn",
Kind: "openai",
BaseURL: "https://coding.dashscope.aliyuncs.com/v1",
Models: qwenPlanModels,
VisionModels: qwenPlanVisionModels,
Default: "qwen3.7-plus",
APIKeyEnv: "QWEN_CODING_API_KEY",
NoProxy: true,
}},
},
{
ID: "qwen-coding-plan-cn-anthropic",
Label: "Qwen Coding Plan CN Anthropic",
Description: "Alibaba Cloud Qwen Coding Plan China Anthropic-compatible endpoint.",
KeyEnv: "QWEN_CODING_API_KEY",
Entries: []ProviderEntry{{
Name: "qwen-coding-plan-cn-anthropic",
Kind: "anthropic",
BaseURL: "https://coding.dashscope.aliyuncs.com/apps/anthropic",
Models: qwenPlanModels,
VisionModels: qwenPlanVisionModels,
Default: "qwen3.7-plus",
APIKeyEnv: "QWEN_CODING_API_KEY",
Thinking: "adaptive",
NoProxy: true,
}},
},
{
ID: "qwen-coding-plan-global",
Label: "Qwen Coding Plan Global",
Description: "Alibaba Cloud Qwen Coding Plan international endpoint.",
KeyEnv: "QWEN_CODING_API_KEY",
Entries: []ProviderEntry{{
Name: "qwen-coding-plan-global",
Kind: "openai",
BaseURL: "https://coding-intl.dashscope.aliyuncs.com/v1",
Models: qwenPlanModels,
VisionModels: qwenPlanVisionModels,
Default: "qwen3.7-plus",
APIKeyEnv: "QWEN_CODING_API_KEY",
}},
},
{
ID: "qwen-coding-plan-global-anthropic",
Label: "Qwen Coding Plan Global Anthropic",
Description: "Alibaba Cloud Qwen Coding Plan international Anthropic-compatible endpoint.",
KeyEnv: "QWEN_CODING_API_KEY",
Entries: []ProviderEntry{{
Name: "qwen-coding-plan-global-anthropic",
Kind: "anthropic",
BaseURL: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic",
Models: qwenPlanModels,
VisionModels: qwenPlanVisionModels,
Default: "qwen3.7-plus",
APIKeyEnv: "QWEN_CODING_API_KEY",
Thinking: "adaptive",
}},
},
{
ID: "stepfun",
Label: "StepFun",
Description: "StepFun coding-plan OpenAI-compatible endpoint.",
KeyEnv: "STEPFUN_API_KEY",
Entries: []ProviderEntry{{
Name: "stepfun",
Kind: "openai",
BaseURL: "https://api.stepfun.com/step_plan/v1",
Models: stepfunPlanModels,
Default: "step-3.7-flash",
APIKeyEnv: "STEPFUN_API_KEY",
SupportedEfforts: []string{"low", "medium", "high"},
DefaultEffort: "medium",
}},
},
{
ID: "stepfun-anthropic",
Label: "StepFun Anthropic",
Description: "StepFun coding-plan Anthropic-compatible endpoint.",
KeyEnv: "STEPFUN_API_KEY",
Entries: []ProviderEntry{{
Name: "stepfun-anthropic",
Kind: "anthropic",
BaseURL: "https://api.stepfun.com/step_plan",
Models: stepfunPlanModels,
Default: "step-3.7-flash",
APIKeyEnv: "STEPFUN_API_KEY",
Thinking: "adaptive",
SupportedEfforts: []string{"low", "medium", "high"},
DefaultEffort: "medium",
}},
},
{
ID: "novita",
Label: "NovitaAI",
Description: "NovitaAI OpenAI-compatible multi-model gateway.",
KeyEnv: "NOVITA_API_KEY",
Entries: []ProviderEntry{{
Name: "novita",
Kind: "openai",
BaseURL: "https://api.novita.ai/openai/v1",
Models: novitaModels,
Default: "zai-org/glm-5.2",
APIKeyEnv: "NOVITA_API_KEY",
}},
},
{
ID: "gmi",
Label: "GMI Cloud",
Description: "GMI Cloud direct multi-model OpenAI-compatible gateway.",
KeyEnv: "GMI_API_KEY",
Entries: []ProviderEntry{{
Name: "gmi",
Kind: "openai",
BaseURL: "https://api.gmi-serving.com/v1",
Models: gmiModels,
Default: "zai-org/GLM-5.2-FP8",
APIKeyEnv: "GMI_API_KEY",
Headers: map[string]string{"User-Agent": "Reasonix"},
}},
},
{
ID: "vercel-ai-gateway",
Label: "Vercel AI Gateway",
Description: "Vercel AI Gateway via Anthropic-compatible Messages API.",
KeyEnv: "AI_GATEWAY_API_KEY",
Entries: []ProviderEntry{{
Name: "vercel-ai-gateway",
Kind: "anthropic",
BaseURL: "https://ai-gateway.vercel.sh",
Models: vercelModels,
VisionModels: []string{"anthropic/claude-sonnet-4.6", "anthropic/claude-opus-4.8", "openai/gpt-5.4", "openai/gpt-5.4-pro", "moonshotai/kimi-k2.7-code"},
Default: "anthropic/claude-sonnet-4.6",
APIKeyEnv: "AI_GATEWAY_API_KEY",
AuthHeader: true,
ContextWindow: 1000000,
}},
},
{
ID: "huggingface",
Label: "HuggingFace Router",
Description: "HuggingFace Inference Router OpenAI-compatible endpoint.",
KeyEnv: "HF_TOKEN",
Entries: []ProviderEntry{{
Name: "huggingface",
Kind: "openai",
BaseURL: "https://router.huggingface.co/v1",
Models: huggingFaceModels,
Default: "zai-org/GLM-5.2",
APIKeyEnv: "HF_TOKEN",
}},
},
{
ID: "nvidia",
Label: "NVIDIA NIM",
Description: "NVIDIA NIM OpenAI-compatible accelerated inference endpoint.",
KeyEnv: "NVIDIA_API_KEY",
Entries: []ProviderEntry{{
Name: "nvidia",
Kind: "openai",
BaseURL: "https://integrate.api.nvidia.com/v1",
Models: nvidiaModels,
Default: "nvidia/nemotron-3-nano-30b-a3b",
APIKeyEnv: "NVIDIA_API_KEY",
}},
},
{
ID: "kilocode",
Label: "KiloCode",
Description: "Kilo Code gateway OpenAI-compatible endpoint.",
KeyEnv: "KILOCODE_API_KEY",
Entries: []ProviderEntry{{
Name: "kilocode",
Kind: "openai",
BaseURL: "https://api.kilo.ai/api/gateway",
Models: []string{"kilo/auto"},
Default: "kilo/auto",
APIKeyEnv: "KILOCODE_API_KEY",
}},
},
{
ID: "ollama-cloud",
Label: "Ollama Cloud",
Description: "Hosted Ollama Cloud OpenAI-compatible endpoint with max reasoning effort.",
KeyEnv: "OLLAMA_API_KEY",
Entries: []ProviderEntry{{
Name: "ollama-cloud",
Kind: "openai",
BaseURL: "https://ollama.com/v1",
Models: ollamaCloudModels,
Default: "glm-5.2",
APIKeyEnv: "OLLAMA_API_KEY",
}},
},
}
func cloneProviderPresets(in []ProviderPreset) []ProviderPreset {
out := make([]ProviderPreset, 0, len(in))
for _, p := range in {
out = append(out, cloneProviderPreset(p))
}
return out
}
func cloneProviderPreset(p ProviderPreset) ProviderPreset {
p.Entries = cloneProviderEntries(p.Entries)
for i := range p.Entries {
p.Entries[i].PresetID = p.ID
p.Entries[i].PresetVersion = ProviderPresetVersion
}
return p
}
func cloneProviderEntries(in []ProviderEntry) []ProviderEntry {
out := make([]ProviderEntry, 0, len(in))
for _, e := range in {
out = append(out, cloneProviderEntry(e))
}
return out
}
func cloneProviderEntry(e ProviderEntry) ProviderEntry {
e.Models = append([]string(nil), e.Models...)
e.VisionModels = append([]string(nil), e.VisionModels...)
e.SupportedEfforts = append([]string(nil), e.SupportedEfforts...)
e.Headers = cloneStringMap(e.Headers)
e.ExtraBody = cloneAnyMap(e.ExtraBody)
e.Price = clonePricing(e.Price)
e.Prices = clonePricingMap(e.Prices)
e.ModelOverrides = cloneModelOverrideMap(e.ModelOverrides)
return e
}
func clonePricingMap(in map[string]*provider.Pricing) map[string]*provider.Pricing {
if len(in) == 0 {
return nil
}
out := make(map[string]*provider.Pricing, len(in))
for k, v := range in {
out[k] = clonePricing(v)
}
return out
}
func cloneAnyMap(in map[string]any) map[string]any {
if len(in) == 0 {
return nil
}
out := make(map[string]any, len(in))
for k, v := range in {
out[k] = cloneAnyValue(v)
}
return out
}
func cloneAnyValue(v any) any {
switch x := v.(type) {
case map[string]any:
return cloneAnyMap(x)
case []any:
out := make([]any, len(x))
for i := range x {
out[i] = cloneAnyValue(x[i])
}
return out
default:
return v
}
}
func cloneModelOverrideMap(in map[string]ProviderModelOverride) map[string]ProviderModelOverride {
if len(in) == 0 {
return nil
}
out := make(map[string]ProviderModelOverride, len(in))
for k, v := range in {
v.SupportedEfforts = append([]string(nil), v.SupportedEfforts...)
out[k] = v
}
return out
}