返回 DeepSeek-Reasonix
provider_presets.go
根目录 / internal / config / provider_presets.go
1 package config
2
3 import (
4 "sort"
5 "strings"
6
7 "reasonix/internal/provider"
8 )
9
10 // ProviderPreset is a curated, editable provider starter template. Presets are
11 // not secret-bearing: API key values still live only in Reasonix home .env.
12 type ProviderPreset struct {
13 ID string
14 Label string
15 Description string
16 KeyEnv string
17 Entries []ProviderEntry
18 }
19
20 const (
21 ProviderPresetVersion = 1
22 longCat20ContextWindow = 1_048_576
23 legacyLongCat20ContextWindow = 131_072
24 longCatOpenAIBaseURL = "https://api.longcat.chat/openai/v1"
25 longCatAnthropicBaseURL = "https://api.longcat.chat/anthropic"
26 deepSeekAnthropicBaseURL = "https://api.deepseek.com/anthropic"
27 )
28
29 // CuratedProviderPresets returns one-click provider templates for common
30 // OpenAI-compatible and Anthropic-compatible coding-plan services. These are
31 // intentionally editable after installation; they reduce setup friction without
32 // turning fast-moving third-party catalogs into hard runtime dependencies.
33 func CuratedProviderPresets() []ProviderPreset {
34 presets := cloneProviderPresets(curatedProviderPresets)
35 sort.SliceStable(presets, func(i, j int) bool {
36 return providerPresetDisplayRank(presets[i].ID) < providerPresetDisplayRank(presets[j].ID)
37 })
38 return presets
39 }
40
41 // CuratedProviderPreset returns a single provider preset by id.
42 func CuratedProviderPreset(id string) (ProviderPreset, bool) {
43 id = strings.ToLower(strings.TrimSpace(id))
44 for _, p := range curatedProviderPresets {
45 if p.ID == id {
46 return cloneProviderPreset(p), true
47 }
48 }
49 return ProviderPreset{}, false
50 }
51
52 func providerPresetDisplayRank(id string) int {
53 switch {
54 case id == "deepseek-responses":
55 return -1
56 case id == "deepseek-anthropic":
57 return 0
58 case id == "glm-cn" || id == "zai-global" || strings.HasPrefix(id, "glm-coding-plan-") || strings.HasPrefix(id, "zai-coding-plan-"):
59 return 0
60 case strings.HasPrefix(id, "longcat-"):
61 return 1
62 case id == "token-rhythm":
63 return 1
64 case strings.HasPrefix(id, "kimi-"):
65 return 2
66 case strings.HasPrefix(id, "minimax-"):
67 return 3
68 default:
69 return 4
70 }
71 }
72
73 var (
74 legacyKimiAPIModels = []string{"kimi-k2.7-code", "kimi-k2.7-code-highspeed", "kimi-k2.6", "kimi-k2.5"}
75 kimiAPIModels = []string{"kimi-k3", "kimi-k2.7-code", "kimi-k2.7-code-highspeed", "kimi-k2.6", "kimi-k2.5"}
76 kimiAPIVisionModels = []string{"kimi-k3", "kimi-k2.7-code", "kimi-k2.7-code-highspeed", "kimi-k2.6", "kimi-k2.5"}
77 kimiCodingModels = []string{"kimi-for-coding"}
78
79 longCat20Models = []string{"LongCat-2.0"}
80 deepSeekV4Models = []string{"deepseek-v4-flash", "deepseek-v4-pro"}
81 tokenRhythmModels = []string{
82 "deepseek-v4-flash", "deepseek-v4-pro", "glm-5", "glm-5.1",
83 "minimax-m2.7", "kimi-k2.5", "kimi-k2.6", "minimax-m2.5",
84 "mimo-v2.5-pro", "qwen3.7-max", "kimi-k2.7-code", "glm-5.2",
85 "qwen3.8-max", "deepseek-v4-flash-0731",
86 }
87 tokenRhythmVisionModels = []string{"kimi-k2.5", "kimi-k2.6", "kimi-k2.7-code"}
88
89 mimoV25Models = []string{"mimo-v2.5-pro", "mimo-v2.5"}
90 mimoV25VisionModels = []string{"mimo-v2.5"}
91
92 minimaxMSeriesModels = []string{"MiniMax-M3", "MiniMax-M2.7", "MiniMax-M2.7-highspeed"}
93 minimaxMSeriesVisionModels = []string{"MiniMax-M3"}
94 deepSeekResponsesModels = []string{"deepseek-v4-flash"}
95
96 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"}
97 glmAPIVisionModels = []string{"glm-5v-turbo"}
98 glmCodingModels = []string{"glm-5.2", "glm-5.1", "glm-5", "glm-4.7"}
99 glmAnthropicModels = []string{"glm-5.2[1m]", "glm-5.2", "glm-5.1", "glm-5", "glm-4.7", "glm-4.5-air"}
100
101 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"}
102 qwenAPIVisionModels = []string{"qwen3.7-plus", "qwen3.6-plus", "qwen3.5-plus", "kimi-k2.5"}
103 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"}
104 qwenPlanVisionModels = []string{"qwen3.7-plus", "qwen3.6-plus", "qwen3.5-plus", "kimi-k2.5"}
105
106 stepfunPlanModels = []string{"step-3.7-flash", "step-3.5-flash", "step-3.5-flash-2603"}
107
108 legacyOpenCodeGoModels = []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"}
109 opencodeGoModels = []string{"glm-5.2", "glm-5.1", "kimi-k3", "kimi-k2.7-code", "kimi-k2.6", "deepseek-v4-pro", "deepseek-v4-flash", "mimo-v2.5-pro", "mimo-v2.5"}
110 opencodeGoVisionModels = []string{"kimi-k3"}
111 opencodeGoAnthropicModels = []string{"qwen3.7-plus", "qwen3.7-max", "qwen3.6-plus", "minimax-m3", "minimax-m2.7", "minimax-m2.5"}
112 opencodeZenAnthropicModels = []string{"claude-sonnet-4-6", "claude-opus-4-8", "claude-haiku-4-5", "qwen3.6-plus", "qwen3.5-plus", "qwen3.6-plus-free"}
113 opencodeZenAnthropicVisionModels = []string{"claude-sonnet-4-6", "claude-opus-4-8", "claude-haiku-4-5"}
114
115 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"}
116 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"}
117 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"}
118 huggingFaceModels = []string{"zai-org/GLM-5.2", "deepseek-ai/DeepSeek-V3.2", "Qwen/Qwen3.5-72B-Instruct"}
119 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"}
120 ollamaCloudModels = []string{"glm-5.2", "kimi-k2.7-code", "deepseek-v4-pro", "deepseek-v4-flash", "minimax-m3", "nemotron-3-nano:30b", "qwen3-coder-next"}
121 )
122
123 func qwenModelContextOverrides() map[string]ProviderModelOverride {
124 return map[string]ProviderModelOverride{
125 "qwen3-max-2026-01-23": {ContextWindow: 262_144},
126 "qwen3-coder-next": {ContextWindow: 262_144},
127 "MiniMax-M2.5": {ContextWindow: 196_608},
128 "glm-5": {ContextWindow: 202_752},
129 "glm-4.7": {ContextWindow: 202_752},
130 "kimi-k2.5": {ContextWindow: 262_144},
131 }
132 }
133
134 func tokenRhythmModelOverrides() map[string]ProviderModelOverride {
135 return map[string]ProviderModelOverride{
136 "deepseek-v4-flash": {
137 ReasoningProtocol: ReasoningProtocolDeepSeek,
138 SupportedEfforts: []string{"disabled", "low", "high", "max"},
139 DefaultEffort: "high",
140 },
141 "deepseek-v4-pro": {
142 ReasoningProtocol: ReasoningProtocolDeepSeek,
143 SupportedEfforts: []string{"disabled", "high", "max"},
144 DefaultEffort: "high",
145 },
146 "deepseek-v4-flash-0731": {
147 ReasoningProtocol: ReasoningProtocolDeepSeek,
148 SupportedEfforts: []string{"disabled", "low", "high", "max"},
149 DefaultEffort: "high",
150 },
151 "glm-5": {
152 ReasoningProtocol: ReasoningProtocolGLM,
153 SupportedEfforts: []string{"enabled", "disabled"},
154 DefaultEffort: "enabled",
155 },
156 "glm-5.1": {
157 ReasoningProtocol: ReasoningProtocolGLM,
158 SupportedEfforts: []string{"enabled", "disabled"},
159 DefaultEffort: "enabled",
160 ContextWindow: 200_000,
161 },
162 "glm-5.2": {
163 ReasoningProtocol: ReasoningProtocolGLM,
164 SupportedEfforts: []string{"enabled", "disabled"},
165 DefaultEffort: "enabled",
166 },
167 "minimax-m2.7": {ContextWindow: 200_000},
168 "kimi-k2.5": {ContextWindow: 256_000},
169 "kimi-k2.6": {ContextWindow: 256_000},
170 "minimax-m2.5": {ContextWindow: 200_000},
171 "mimo-v2.5-pro": {ContextWindow: 256_000},
172 "kimi-k2.7-code": {ContextWindow: 256_000},
173 }
174 }
175
176 func kimiK3DirectOverride() ProviderModelOverride {
177 return ProviderModelOverride{
178 ReasoningProtocol: ReasoningProtocolOpenAI,
179 SupportedEfforts: []string{"low", "high", "max"},
180 DefaultEffort: "max",
181 ContextWindow: 1_048_576,
182 }
183 }
184
185 var curatedProviderPresets = []ProviderPreset{
186 {
187 ID: "deepseek-anthropic",
188 Label: "DeepSeek Anthropic",
189 Description: "Official DeepSeek Anthropic-compatible endpoint for Flash and Pro with server-side web search; search may increase token usage.",
190 KeyEnv: "DEEPSEEK_API_KEY",
191 Entries: []ProviderEntry{{
192 Name: "deepseek-anthropic",
193 Kind: "anthropic",
194 BaseURL: deepSeekAnthropicBaseURL,
195 Models: deepSeekV4Models,
196 Default: "deepseek-v4-flash",
197 APIKeyEnv: "DEEPSEEK_API_KEY",
198 BalanceURL: "https://api.deepseek.com/user/balance",
199 Thinking: "enabled",
200 WebSearch: boolPointer(true),
201 ContextWindow: 1_000_000,
202 Prices: deepSeekV4PricesUSD(),
203 ModelOverrides: map[string]ProviderModelOverride{
204 "deepseek-v4-flash": {SupportedEfforts: []string{"disabled", "low", "high", "max"}, DefaultEffort: "high"},
205 "deepseek-v4-pro": {SupportedEfforts: []string{"disabled", "high", "max"}, DefaultEffort: "high"},
206 },
207 }},
208 },
209 {
210 ID: "longcat-openai",
211 Label: "LongCat OpenAI",
212 Description: "LongCat Platform OpenAI-compatible endpoint for LongCat-2.0.",
213 KeyEnv: "LONGCAT_API_KEY",
214 Entries: []ProviderEntry{{
215 Name: "longcat-openai",
216 Kind: "openai",
217 BaseURL: longCatOpenAIBaseURL,
218 ModelsURL: "https://api.longcat.chat/openai/v1/models",
219 Models: longCat20Models,
220 Default: "LongCat-2.0",
221 APIKeyEnv: "LONGCAT_API_KEY",
222 ContextWindow: longCat20ContextWindow,
223 Prices: longCat20Prices(longCat20Models),
224 Thinking: "enabled",
225 SupportedEfforts: []string{"enabled", "disabled"},
226 DefaultEffort: "enabled",
227 }},
228 },
229 {
230 ID: "longcat-anthropic",
231 Label: "LongCat Anthropic",
232 Description: "LongCat Platform Anthropic-compatible Messages endpoint for LongCat-2.0.",
233 KeyEnv: "LONGCAT_API_KEY",
234 Entries: []ProviderEntry{{
235 Name: "longcat-anthropic",
236 Kind: "anthropic",
237 BaseURL: longCatAnthropicBaseURL,
238 ModelsURL: "https://api.longcat.chat/anthropic/v1/models",
239 Models: longCat20Models,
240 Default: "LongCat-2.0",
241 APIKeyEnv: "LONGCAT_API_KEY",
242 AuthHeader: true,
243 Thinking: "enabled",
244 SupportedEfforts: []string{"enabled", "disabled"},
245 DefaultEffort: "enabled",
246 ContextWindow: longCat20ContextWindow,
247 Prices: longCat20Prices(longCat20Models),
248 }},
249 },
250 {
251 ID: "token-rhythm",
252 Label: "Token Rhythm",
253 Description: "Token Rhythm (基元律动) multi-model OpenAI-compatible gateway.",
254 KeyEnv: "TOKEN_RHYTHM_API_KEY",
255 Entries: []ProviderEntry{{
256 Name: "token-rhythm",
257 Kind: "openai",
258 BaseURL: "https://tokenrhythm.studio/v1",
259 ModelsURL: "https://tokenrhythm.studio/v1/models",
260 Models: tokenRhythmModels,
261 VisionModels: tokenRhythmVisionModels,
262 Default: "deepseek-v4-flash",
263 APIKeyEnv: "TOKEN_RHYTHM_API_KEY",
264 ContextWindow: 1_000_000,
265 ModelOverrides: tokenRhythmModelOverrides(),
266 }},
267 },
268 {
269 ID: "kimi-cn",
270 Label: "Kimi CN API",
271 Description: "Moonshot Kimi China OpenAI-compatible API.",
272 KeyEnv: "KIMI_API_KEY",
273 Entries: []ProviderEntry{{
274 Name: "kimi-cn",
275 Kind: "openai",
276 BaseURL: "https://api.moonshot.cn/v1",
277 Models: kimiAPIModels,
278 VisionModels: kimiAPIVisionModels,
279 Default: "kimi-k2.7-code",
280 APIKeyEnv: "KIMI_API_KEY",
281 BalanceURL: "https://api.moonshot.cn/v1/users/me/balance",
282 ContextWindow: 262144,
283 ReasoningProtocol: ReasoningProtocolNone,
284 ModelOverrides: map[string]ProviderModelOverride{
285 "kimi-k3": kimiK3DirectOverride(),
286 },
287 }},
288 },
289 {
290 ID: "kimi-global",
291 Label: "Kimi Global API",
292 Description: "Moonshot Kimi international OpenAI-compatible API.",
293 KeyEnv: "MOONSHOT_API_KEY",
294 Entries: []ProviderEntry{{
295 Name: "kimi-global",
296 Kind: "openai",
297 BaseURL: "https://api.moonshot.ai/v1",
298 Models: kimiAPIModels,
299 VisionModels: kimiAPIVisionModels,
300 Default: "kimi-k2.7-code",
301 APIKeyEnv: "MOONSHOT_API_KEY",
302 BalanceURL: "https://api.moonshot.ai/v1/users/me/balance",
303 ContextWindow: 262144,
304 ReasoningProtocol: ReasoningProtocolNone,
305 ModelOverrides: map[string]ProviderModelOverride{
306 "kimi-k3": kimiK3DirectOverride(),
307 },
308 }},
309 },
310 {
311 ID: "kimi-coding-plan",
312 Label: "Kimi Coding Plan",
313 Description: "Kimi Coding Plan via its dedicated Anthropic-compatible endpoint.",
314 KeyEnv: "KIMI_CODING_API_KEY",
315 Entries: []ProviderEntry{{
316 Name: "kimi-coding-plan",
317 Kind: "anthropic",
318 BaseURL: "https://api.kimi.com/coding/",
319 Models: kimiCodingModels,
320 VisionModels: kimiCodingModels,
321 Default: "kimi-for-coding",
322 APIKeyEnv: "KIMI_CODING_API_KEY",
323 Headers: map[string]string{"User-Agent": "claude-code/0.1.0"},
324 Thinking: "adaptive",
325 ContextWindow: 262144,
326 }},
327 },
328 {
329 ID: "mimo-api",
330 Label: "MiMo API",
331 Description: "Xiaomi MiMo direct API with text and vision-capable models.",
332 KeyEnv: "MIMO_API_KEY",
333 Entries: []ProviderEntry{{
334 Name: "mimo-api",
335 Kind: "openai",
336 BaseURL: "https://api.xiaomimimo.com/v1",
337 Models: mimoV25Models,
338 VisionModels: mimoV25VisionModels,
339 Default: "mimo-v2.5-pro",
340 APIKeyEnv: "MIMO_API_KEY",
341 ContextWindow: 1048576,
342 Prices: mimoDomesticPrices(mimoV25Models),
343 NoProxy: true,
344 }},
345 },
346 {
347 ID: "mimo-anthropic",
348 Label: "MiMo Anthropic",
349 Description: "Xiaomi MiMo direct Anthropic-compatible endpoint.",
350 KeyEnv: "MIMO_API_KEY",
351 Entries: []ProviderEntry{{
352 Name: "mimo-anthropic",
353 Kind: "anthropic",
354 BaseURL: "https://api.xiaomimimo.com/anthropic",
355 Models: mimoV25Models,
356 VisionModels: mimoV25VisionModels,
357 Default: "mimo-v2.5-pro",
358 APIKeyEnv: "MIMO_API_KEY",
359 Thinking: "adaptive",
360 ContextWindow: 1048576,
361 Prices: mimoDomesticPrices(mimoV25Models),
362 NoProxy: true,
363 }},
364 },
365 {
366 ID: "mimo-token-plan-cn",
367 Label: "MiMo Token Plan CN",
368 Description: "Xiaomi MiMo token-plan China endpoint.",
369 KeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
370 Entries: []ProviderEntry{{
371 Name: "mimo-token-plan-cn",
372 Kind: "openai",
373 BaseURL: "https://token-plan-cn.xiaomimimo.com/v1",
374 Models: mimoV25Models,
375 VisionModels: mimoV25VisionModels,
376 Default: "mimo-v2.5-pro",
377 APIKeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
378 ContextWindow: 1048576,
379 Prices: mimoDomesticPrices(mimoV25Models),
380 NoProxy: true,
381 }},
382 },
383 {
384 ID: "mimo-token-plan-cn-anthropic",
385 Label: "MiMo Token Plan CN Anthropic",
386 Description: "Xiaomi MiMo token-plan China Anthropic-compatible endpoint.",
387 KeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
388 Entries: []ProviderEntry{{
389 Name: "mimo-token-plan-cn-anthropic",
390 Kind: "anthropic",
391 BaseURL: "https://token-plan-cn.xiaomimimo.com/anthropic",
392 Models: mimoV25Models,
393 VisionModels: mimoV25VisionModels,
394 Default: "mimo-v2.5-pro",
395 APIKeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
396 Thinking: "adaptive",
397 ContextWindow: 1048576,
398 Prices: mimoDomesticPrices(mimoV25Models),
399 NoProxy: true,
400 }},
401 },
402 {
403 ID: "mimo-token-plan-sgp",
404 Label: "MiMo Token Plan SGP",
405 Description: "Xiaomi MiMo token-plan Singapore endpoint.",
406 KeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
407 Entries: []ProviderEntry{{
408 Name: "mimo-token-plan-sgp",
409 Kind: "openai",
410 BaseURL: "https://token-plan-sgp.xiaomimimo.com/v1",
411 Models: mimoV25Models,
412 VisionModels: mimoV25VisionModels,
413 Default: "mimo-v2.5-pro",
414 APIKeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
415 ContextWindow: 1048576,
416 Prices: mimoDomesticPrices(mimoV25Models),
417 }},
418 },
419 {
420 ID: "mimo-token-plan-sgp-anthropic",
421 Label: "MiMo Token Plan SGP Anthropic",
422 Description: "Xiaomi MiMo token-plan Singapore Anthropic-compatible endpoint.",
423 KeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
424 Entries: []ProviderEntry{{
425 Name: "mimo-token-plan-sgp-anthropic",
426 Kind: "anthropic",
427 BaseURL: "https://token-plan-sgp.xiaomimimo.com/anthropic",
428 Models: mimoV25Models,
429 VisionModels: mimoV25VisionModels,
430 Default: "mimo-v2.5-pro",
431 APIKeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
432 Thinking: "adaptive",
433 ContextWindow: 1048576,
434 Prices: mimoDomesticPrices(mimoV25Models),
435 }},
436 },
437 {
438 ID: "mimo-token-plan-ams",
439 Label: "MiMo Token Plan AMS",
440 Description: "Xiaomi MiMo token-plan Amsterdam endpoint.",
441 KeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
442 Entries: []ProviderEntry{{
443 Name: "mimo-token-plan-ams",
444 Kind: "openai",
445 BaseURL: "https://token-plan-ams.xiaomimimo.com/v1",
446 Models: mimoV25Models,
447 VisionModels: mimoV25VisionModels,
448 Default: "mimo-v2.5-pro",
449 APIKeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
450 ContextWindow: 1048576,
451 Prices: mimoDomesticPrices(mimoV25Models),
452 }},
453 },
454 {
455 ID: "mimo-token-plan-ams-anthropic",
456 Label: "MiMo Token Plan AMS Anthropic",
457 Description: "Xiaomi MiMo token-plan Amsterdam Anthropic-compatible endpoint.",
458 KeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
459 Entries: []ProviderEntry{{
460 Name: "mimo-token-plan-ams-anthropic",
461 Kind: "anthropic",
462 BaseURL: "https://token-plan-ams.xiaomimimo.com/anthropic",
463 Models: mimoV25Models,
464 VisionModels: mimoV25VisionModels,
465 Default: "mimo-v2.5-pro",
466 APIKeyEnv: "MIMO_TOKEN_PLAN_API_KEY",
467 Thinking: "adaptive",
468 ContextWindow: 1048576,
469 Prices: mimoDomesticPrices(mimoV25Models),
470 }},
471 },
472 {
473 ID: "minimax-cn-api",
474 Label: "MiniMax CN API",
475 Description: "MiniMax China OpenAI-compatible M-series API endpoint.",
476 KeyEnv: "MINIMAX_API_KEY",
477 Entries: []ProviderEntry{{
478 Name: "minimax-cn-api",
479 Kind: "openai",
480 BaseURL: "https://api.minimaxi.com/v1",
481 Models: minimaxMSeriesModels,
482 VisionModels: minimaxMSeriesVisionModels,
483 Default: "MiniMax-M3",
484 APIKeyEnv: "MINIMAX_API_KEY",
485 ContextWindow: 1048576,
486 ExtraBody: map[string]any{"reasoning_split": true},
487 }},
488 },
489 {
490 ID: "minimax-global-api",
491 Label: "MiniMax Global API",
492 Description: "MiniMax international OpenAI-compatible M-series API endpoint.",
493 KeyEnv: "MINIMAX_API_KEY",
494 Entries: []ProviderEntry{{
495 Name: "minimax-global-api",
496 Kind: "openai",
497 BaseURL: "https://api.minimax.io/v1",
498 Models: minimaxMSeriesModels,
499 VisionModels: minimaxMSeriesVisionModels,
500 Default: "MiniMax-M3",
501 APIKeyEnv: "MINIMAX_API_KEY",
502 ContextWindow: 1048576,
503 ExtraBody: map[string]any{"reasoning_split": true},
504 }},
505 },
506 {
507 ID: "minimax-cn-anthropic",
508 Label: "MiniMax CN Anthropic",
509 Description: "MiniMax China Anthropic-compatible M-series endpoint.",
510 KeyEnv: "MINIMAX_PLAN_API_KEY",
511 Entries: []ProviderEntry{{
512 Name: "minimax-cn-anthropic",
513 Kind: "anthropic",
514 BaseURL: "https://api.minimaxi.com/anthropic",
515 Models: minimaxMSeriesModels,
516 VisionModels: minimaxMSeriesVisionModels,
517 Default: "MiniMax-M3",
518 APIKeyEnv: "MINIMAX_PLAN_API_KEY",
519 AuthHeader: true,
520 ContextWindow: 1048576,
521 }},
522 },
523 {
524 ID: "minimax-global-anthropic",
525 Label: "MiniMax Global Anthropic",
526 Description: "MiniMax international Anthropic-compatible endpoint with Bearer auth.",
527 KeyEnv: "MINIMAX_API_KEY",
528 Entries: []ProviderEntry{{
529 Name: "minimax-global-anthropic",
530 Kind: "anthropic",
531 BaseURL: "https://api.minimax.io/anthropic",
532 Models: minimaxMSeriesModels,
533 VisionModels: minimaxMSeriesVisionModels,
534 Default: "MiniMax-M3",
535 APIKeyEnv: "MINIMAX_API_KEY",
536 AuthHeader: true,
537 ContextWindow: 1048576,
538 }},
539 },
540 {
541 ID: "deepseek-responses",
542 Label: "DeepSeek Responses API",
543 Description: "DeepSeek official stateless Responses API for deepseek-v4-flash with server-side web search; search may increase token usage.",
544 KeyEnv: "DEEPSEEK_API_KEY",
545 Entries: []ProviderEntry{{
546 Name: "deepseek-responses",
547 Kind: "responses",
548 BaseURL: "https://api.deepseek.com",
549 Models: deepSeekResponsesModels,
550 Default: "deepseek-v4-flash",
551 APIKeyEnv: "DEEPSEEK_API_KEY",
552 BalanceURL: "https://api.deepseek.com/user/balance",
553 ContextWindow: 1_000_000,
554 Price: deepSeekV4FlashPriceUSD(),
555 ResponsesMode: "stateless",
556 WebSearch: boolPointer(true),
557 SupportedEfforts: []string{"low", "high", "max"},
558 DefaultEffort: "high",
559 }},
560 },
561 {
562 ID: "glm-cn",
563 Label: "GLM CN API",
564 Description: "Zhipu GLM China OpenAI-compatible API with thinking controls.",
565 KeyEnv: "GLM_API_KEY",
566 Entries: []ProviderEntry{{
567 Name: "glm-cn",
568 Kind: "openai",
569 BaseURL: "https://open.bigmodel.cn/api/paas/v4",
570 Models: glmAPIModels,
571 VisionModels: glmAPIVisionModels,
572 Default: "glm-5.2",
573 APIKeyEnv: "GLM_API_KEY",
574 ContextWindow: 1000000,
575 }},
576 },
577 {
578 ID: "zai-global",
579 Label: "Z.AI Global API",
580 Description: "Z.AI international OpenAI-compatible GLM API.",
581 KeyEnv: "ZAI_API_KEY",
582 Entries: []ProviderEntry{{
583 Name: "zai-global",
584 Kind: "openai",
585 BaseURL: "https://api.z.ai/api/paas/v4",
586 Models: glmAPIModels,
587 VisionModels: glmAPIVisionModels,
588 Default: "glm-5.2",
589 APIKeyEnv: "ZAI_API_KEY",
590 ContextWindow: 1000000,
591 }},
592 },
593 {
594 ID: "glm-coding-plan-cn",
595 Label: "GLM Coding Plan CN",
596 Description: "Zhipu GLM China coding-plan endpoint.",
597 KeyEnv: "GLM_PLAN_API_KEY",
598 Entries: []ProviderEntry{{
599 Name: "glm-coding-plan-cn",
600 Kind: "openai",
601 BaseURL: "https://open.bigmodel.cn/api/coding/paas/v4",
602 Models: glmCodingModels,
603 Default: "glm-5.2",
604 APIKeyEnv: "GLM_PLAN_API_KEY",
605 ContextWindow: 1000000,
606 NoProxy: true,
607 }},
608 },
609 {
610 ID: "glm-coding-plan-cn-anthropic",
611 Label: "GLM Coding Plan CN Anthropic",
612 Description: "Zhipu GLM China coding-plan Anthropic-compatible endpoint.",
613 KeyEnv: "GLM_PLAN_API_KEY",
614 Entries: []ProviderEntry{{
615 Name: "glm-coding-plan-cn-anthropic",
616 Kind: "anthropic",
617 BaseURL: "https://open.bigmodel.cn/api/anthropic",
618 Models: glmAnthropicModels,
619 Default: "glm-5.2",
620 APIKeyEnv: "GLM_PLAN_API_KEY",
621 AuthHeader: true,
622 Thinking: "adaptive",
623 ContextWindow: 1000000,
624 NoProxy: true,
625 }},
626 },
627 {
628 ID: "zai-coding-plan-global",
629 Label: "Z.AI Coding Plan Global",
630 Description: "Z.AI international coding-plan endpoint.",
631 KeyEnv: "ZAI_CODING_API_KEY",
632 Entries: []ProviderEntry{{
633 Name: "zai-coding-plan-global",
634 Kind: "openai",
635 BaseURL: "https://api.z.ai/api/coding/paas/v4",
636 Models: glmCodingModels,
637 Default: "glm-5.2",
638 APIKeyEnv: "ZAI_CODING_API_KEY",
639 ContextWindow: 1000000,
640 }},
641 },
642 {
643 ID: "zai-coding-plan-global-anthropic",
644 Label: "Z.AI Coding Plan Global Anthropic",
645 Description: "Z.AI international coding-plan Anthropic-compatible endpoint.",
646 KeyEnv: "ZAI_CODING_API_KEY",
647 Entries: []ProviderEntry{{
648 Name: "zai-coding-plan-global-anthropic",
649 Kind: "anthropic",
650 BaseURL: "https://api.z.ai/api/anthropic",
651 Models: glmAnthropicModels,
652 Default: "glm-5.2",
653 APIKeyEnv: "ZAI_CODING_API_KEY",
654 AuthHeader: true,
655 Thinking: "adaptive",
656 ContextWindow: 1000000,
657 }},
658 },
659 {
660 ID: "opencode-go",
661 Label: "OpenCode Go",
662 Description: "OpenCode Go relay with per-model capability overrides.",
663 KeyEnv: "OPENCODE_GO_API_KEY",
664 Entries: []ProviderEntry{{
665 Name: "opencode-go",
666 Kind: "openai",
667 BaseURL: "https://opencode.ai/zen/go/v1",
668 Models: opencodeGoModels,
669 VisionModels: opencodeGoVisionModels,
670 Default: "glm-5.2",
671 APIKeyEnv: "OPENCODE_GO_API_KEY",
672 ContextWindow: 128000,
673 ModelOverrides: map[string]ProviderModelOverride{
674 "deepseek-v4-flash": {
675 ReasoningProtocol: ReasoningProtocolDeepSeek,
676 SupportedEfforts: []string{"disabled", "high", "max"},
677 DefaultEffort: "high",
678 },
679 "deepseek-v4-pro": {
680 ReasoningProtocol: ReasoningProtocolDeepSeek,
681 SupportedEfforts: []string{"disabled", "high", "max"},
682 DefaultEffort: "high",
683 },
684 "kimi-k2.6": {
685 ReasoningProtocol: ReasoningProtocolOpenAI,
686 SupportedEfforts: []string{"low", "medium", "high"},
687 DefaultEffort: "high",
688 },
689 "kimi-k2.7-code": {
690 ReasoningProtocol: ReasoningProtocolOpenAI,
691 SupportedEfforts: []string{"low", "medium", "high"},
692 DefaultEffort: "high",
693 },
694 "kimi-k3": {
695 ReasoningProtocol: ReasoningProtocolOpenAI,
696 SupportedEfforts: []string{"high", "max"},
697 DefaultEffort: "max",
698 ContextWindow: 1_048_576,
699 },
700 },
701 }},
702 },
703 {
704 ID: "opencode-go-anthropic",
705 Label: "OpenCode Go Anthropic",
706 Description: "OpenCode Go subscription Anthropic-compatible route for Qwen and MiniMax models.",
707 KeyEnv: "OPENCODE_GO_API_KEY",
708 Entries: []ProviderEntry{{
709 Name: "opencode-go-anthropic",
710 Kind: "anthropic",
711 BaseURL: "https://opencode.ai/zen/go",
712 Models: opencodeGoAnthropicModels,
713 VisionModels: []string{"qwen3.7-plus", "qwen3.6-plus"},
714 Default: "qwen3.7-plus",
715 APIKeyEnv: "OPENCODE_GO_API_KEY",
716 Thinking: "adaptive",
717 ContextWindow: 262144,
718 }},
719 },
720 {
721 ID: "opencode-zen-anthropic",
722 Label: "OpenCode Zen Anthropic",
723 Description: "OpenCode Zen Anthropic-compatible route for Claude and Qwen models.",
724 KeyEnv: "OPENCODE_API_KEY",
725 Entries: []ProviderEntry{{
726 Name: "opencode-zen-anthropic",
727 Kind: "anthropic",
728 BaseURL: "https://opencode.ai/zen",
729 Models: opencodeZenAnthropicModels,
730 VisionModels: opencodeZenAnthropicVisionModels,
731 Default: "claude-sonnet-4-6",
732 APIKeyEnv: "OPENCODE_API_KEY",
733 ContextWindow: 262144,
734 }},
735 },
736 {
737 ID: "qwen-cn",
738 Label: "Qwen CN API",
739 Description: "Alibaba DashScope China standard OpenAI-compatible endpoint.",
740 KeyEnv: "QWEN_API_KEY",
741 Entries: []ProviderEntry{{
742 Name: "qwen-cn",
743 Kind: "openai",
744 BaseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
745 Models: qwenAPIModels,
746 VisionModels: qwenAPIVisionModels,
747 Default: "qwen3.7-plus",
748 APIKeyEnv: "QWEN_API_KEY",
749 ContextWindow: 1_000_000,
750 ModelOverrides: qwenModelContextOverrides(),
751 NoProxy: true,
752 }},
753 },
754 {
755 ID: "qwen-global",
756 Label: "Qwen Global API",
757 Description: "Alibaba DashScope international standard OpenAI-compatible endpoint.",
758 KeyEnv: "QWEN_API_KEY",
759 Entries: []ProviderEntry{{
760 Name: "qwen-global",
761 Kind: "openai",
762 BaseURL: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
763 Models: qwenAPIModels,
764 VisionModels: qwenAPIVisionModels,
765 Default: "qwen3.7-plus",
766 APIKeyEnv: "QWEN_API_KEY",
767 ContextWindow: 1_000_000,
768 ModelOverrides: qwenModelContextOverrides(),
769 }},
770 },
771 {
772 ID: "qwen-coding-plan-cn",
773 Label: "Qwen Coding Plan CN",
774 Description: "Alibaba Cloud Qwen Coding Plan China endpoint.",
775 KeyEnv: "QWEN_CODING_API_KEY",
776 Entries: []ProviderEntry{{
777 Name: "qwen-coding-plan-cn",
778 Kind: "openai",
779 BaseURL: "https://coding.dashscope.aliyuncs.com/v1",
780 Models: qwenPlanModels,
781 VisionModels: qwenPlanVisionModels,
782 Default: "qwen3.7-plus",
783 APIKeyEnv: "QWEN_CODING_API_KEY",
784 ContextWindow: 1_000_000,
785 ModelOverrides: qwenModelContextOverrides(),
786 NoProxy: true,
787 }},
788 },
789 {
790 ID: "qwen-coding-plan-cn-anthropic",
791 Label: "Qwen Coding Plan CN Anthropic",
792 Description: "Alibaba Cloud Qwen Coding Plan China Anthropic-compatible endpoint.",
793 KeyEnv: "QWEN_CODING_API_KEY",
794 Entries: []ProviderEntry{{
795 Name: "qwen-coding-plan-cn-anthropic",
796 Kind: "anthropic",
797 BaseURL: "https://coding.dashscope.aliyuncs.com/apps/anthropic",
798 Models: qwenPlanModels,
799 VisionModels: qwenPlanVisionModels,
800 Default: "qwen3.7-plus",
801 APIKeyEnv: "QWEN_CODING_API_KEY",
802 ContextWindow: 1_000_000,
803 ModelOverrides: qwenModelContextOverrides(),
804 Thinking: "adaptive",
805 NoProxy: true,
806 }},
807 },
808 {
809 ID: "qwen-coding-plan-global",
810 Label: "Qwen Coding Plan Global",
811 Description: "Alibaba Cloud Qwen Coding Plan international endpoint.",
812 KeyEnv: "QWEN_CODING_API_KEY",
813 Entries: []ProviderEntry{{
814 Name: "qwen-coding-plan-global",
815 Kind: "openai",
816 BaseURL: "https://coding-intl.dashscope.aliyuncs.com/v1",
817 Models: qwenPlanModels,
818 VisionModels: qwenPlanVisionModels,
819 Default: "qwen3.7-plus",
820 APIKeyEnv: "QWEN_CODING_API_KEY",
821 ContextWindow: 1_000_000,
822 ModelOverrides: qwenModelContextOverrides(),
823 }},
824 },
825 {
826 ID: "qwen-coding-plan-global-anthropic",
827 Label: "Qwen Coding Plan Global Anthropic",
828 Description: "Alibaba Cloud Qwen Coding Plan international Anthropic-compatible endpoint.",
829 KeyEnv: "QWEN_CODING_API_KEY",
830 Entries: []ProviderEntry{{
831 Name: "qwen-coding-plan-global-anthropic",
832 Kind: "anthropic",
833 BaseURL: "https://coding-intl.dashscope.aliyuncs.com/apps/anthropic",
834 Models: qwenPlanModels,
835 VisionModels: qwenPlanVisionModels,
836 Default: "qwen3.7-plus",
837 APIKeyEnv: "QWEN_CODING_API_KEY",
838 ContextWindow: 1_000_000,
839 ModelOverrides: qwenModelContextOverrides(),
840 Thinking: "adaptive",
841 }},
842 },
843 {
844 ID: "stepfun",
845 Label: "StepFun",
846 Description: "StepFun coding-plan OpenAI-compatible endpoint.",
847 KeyEnv: "STEPFUN_API_KEY",
848 Entries: []ProviderEntry{{
849 Name: "stepfun",
850 Kind: "openai",
851 BaseURL: "https://api.stepfun.com/step_plan/v1",
852 Models: stepfunPlanModels,
853 Default: "step-3.7-flash",
854 APIKeyEnv: "STEPFUN_API_KEY",
855 SupportedEfforts: []string{"low", "medium", "high"},
856 DefaultEffort: "medium",
857 }},
858 },
859 {
860 ID: "stepfun-anthropic",
861 Label: "StepFun Anthropic",
862 Description: "StepFun coding-plan Anthropic-compatible endpoint.",
863 KeyEnv: "STEPFUN_API_KEY",
864 Entries: []ProviderEntry{{
865 Name: "stepfun-anthropic",
866 Kind: "anthropic",
867 BaseURL: "https://api.stepfun.com/step_plan",
868 Models: stepfunPlanModels,
869 Default: "step-3.7-flash",
870 APIKeyEnv: "STEPFUN_API_KEY",
871 Thinking: "adaptive",
872 SupportedEfforts: []string{"low", "medium", "high"},
873 DefaultEffort: "medium",
874 }},
875 },
876 {
877 ID: "novita",
878 Label: "NovitaAI",
879 Description: "NovitaAI OpenAI-compatible multi-model gateway.",
880 KeyEnv: "NOVITA_API_KEY",
881 Entries: []ProviderEntry{{
882 Name: "novita",
883 Kind: "openai",
884 BaseURL: "https://api.novita.ai/openai/v1",
885 Models: novitaModels,
886 Default: "zai-org/glm-5.2",
887 APIKeyEnv: "NOVITA_API_KEY",
888 }},
889 },
890 {
891 ID: "gmi",
892 Label: "GMI Cloud",
893 Description: "GMI Cloud direct multi-model OpenAI-compatible gateway.",
894 KeyEnv: "GMI_API_KEY",
895 Entries: []ProviderEntry{{
896 Name: "gmi",
897 Kind: "openai",
898 BaseURL: "https://api.gmi-serving.com/v1",
899 Models: gmiModels,
900 Default: "zai-org/GLM-5.2-FP8",
901 APIKeyEnv: "GMI_API_KEY",
902 Headers: map[string]string{"User-Agent": "Reasonix"},
903 }},
904 },
905 {
906 ID: "vercel-ai-gateway",
907 Label: "Vercel AI Gateway",
908 Description: "Vercel AI Gateway via Anthropic-compatible Messages API.",
909 KeyEnv: "AI_GATEWAY_API_KEY",
910 Entries: []ProviderEntry{{
911 Name: "vercel-ai-gateway",
912 Kind: "anthropic",
913 BaseURL: "https://ai-gateway.vercel.sh",
914 Models: vercelModels,
915 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"},
916 Default: "anthropic/claude-sonnet-4.6",
917 APIKeyEnv: "AI_GATEWAY_API_KEY",
918 AuthHeader: true,
919 ContextWindow: 1000000,
920 }},
921 },
922 {
923 ID: "huggingface",
924 Label: "HuggingFace Router",
925 Description: "HuggingFace Inference Router OpenAI-compatible endpoint.",
926 KeyEnv: "HF_TOKEN",
927 Entries: []ProviderEntry{{
928 Name: "huggingface",
929 Kind: "openai",
930 BaseURL: "https://router.huggingface.co/v1",
931 Models: huggingFaceModels,
932 Default: "zai-org/GLM-5.2",
933 APIKeyEnv: "HF_TOKEN",
934 }},
935 },
936 {
937 ID: "nvidia",
938 Label: "NVIDIA NIM",
939 Description: "NVIDIA NIM OpenAI-compatible accelerated inference endpoint.",
940 KeyEnv: "NVIDIA_API_KEY",
941 Entries: []ProviderEntry{{
942 Name: "nvidia",
943 Kind: "openai",
944 BaseURL: "https://integrate.api.nvidia.com/v1",
945 Models: nvidiaModels,
946 Default: "nvidia/nemotron-3-nano-30b-a3b",
947 APIKeyEnv: "NVIDIA_API_KEY",
948 }},
949 },
950 {
951 ID: "kilocode",
952 Label: "KiloCode",
953 Description: "Kilo Code gateway OpenAI-compatible endpoint.",
954 KeyEnv: "KILOCODE_API_KEY",
955 Entries: []ProviderEntry{{
956 Name: "kilocode",
957 Kind: "openai",
958 BaseURL: "https://api.kilo.ai/api/gateway",
959 Models: []string{"kilo/auto"},
960 Default: "kilo/auto",
961 APIKeyEnv: "KILOCODE_API_KEY",
962 }},
963 },
964 {
965 ID: "ollama-cloud",
966 Label: "Ollama Cloud",
967 Description: "Hosted Ollama Cloud OpenAI-compatible endpoint with max reasoning effort.",
968 KeyEnv: "OLLAMA_API_KEY",
969 Entries: []ProviderEntry{{
970 Name: "ollama-cloud",
971 Kind: "openai",
972 BaseURL: "https://ollama.com/v1",
973 Models: ollamaCloudModels,
974 Default: "glm-5.2",
975 APIKeyEnv: "OLLAMA_API_KEY",
976 }},
977 },
978 }
979
980 func boolPointer(value bool) *bool {
981 return &value
982 }
983
984 func cloneProviderPresets(in []ProviderPreset) []ProviderPreset {
985 out := make([]ProviderPreset, 0, len(in))
986 for _, p := range in {
987 out = append(out, cloneProviderPreset(p))
988 }
989 return out
990 }
991
992 func cloneProviderPreset(p ProviderPreset) ProviderPreset {
993 p.Entries = cloneProviderEntries(p.Entries)
994 for i := range p.Entries {
995 p.Entries[i].PresetID = p.ID
996 p.Entries[i].PresetVersion = ProviderPresetVersion
997 }
998 return p
999 }
1000
1001 func cloneProviderEntries(in []ProviderEntry) []ProviderEntry {
1002 out := make([]ProviderEntry, 0, len(in))
1003 for _, e := range in {
1004 out = append(out, cloneProviderEntry(e))
1005 }
1006 return out
1007 }
1008
1009 func cloneProviderEntry(e ProviderEntry) ProviderEntry {
1010 if e.WebSearch != nil {
1011 value := *e.WebSearch
1012 e.WebSearch = &value
1013 }
1014 e.Models = append([]string(nil), e.Models...)
1015 e.VisionModels = append([]string(nil), e.VisionModels...)
1016 e.SupportedEfforts = append([]string(nil), e.SupportedEfforts...)
1017 e.Headers = cloneStringMap(e.Headers)
1018 e.ExtraBody = cloneAnyMap(e.ExtraBody)
1019 e.Price = clonePricing(e.Price)
1020 e.Prices = clonePricingMap(e.Prices)
1021 e.ModelOverrides = cloneModelOverrideMap(e.ModelOverrides)
1022 return e
1023 }
1024
1025 func clonePricingMap(in map[string]*provider.Pricing) map[string]*provider.Pricing {
1026 if len(in) == 0 {
1027 return nil
1028 }
1029 out := make(map[string]*provider.Pricing, len(in))
1030 for k, v := range in {
1031 out[k] = clonePricing(v)
1032 }
1033 return out
1034 }
1035
1036 func cloneAnyMap(in map[string]any) map[string]any {
1037 if len(in) == 0 {
1038 return nil
1039 }
1040 out := make(map[string]any, len(in))
1041 for k, v := range in {
1042 out[k] = cloneAnyValue(v)
1043 }
1044 return out
1045 }
1046
1047 func cloneAnyValue(v any) any {
1048 switch x := v.(type) {
1049 case map[string]any:
1050 return cloneAnyMap(x)
1051 case []any:
1052 out := make([]any, len(x))
1053 for i := range x {
1054 out[i] = cloneAnyValue(x[i])
1055 }
1056 return out
1057 default:
1058 return v
1059 }
1060 }
1061
1062 func cloneModelOverrideMap(in map[string]ProviderModelOverride) map[string]ProviderModelOverride {
1063 if len(in) == 0 {
1064 return nil
1065 }
1066 out := make(map[string]ProviderModelOverride, len(in))
1067 for k, v := range in {
1068 v.SupportedEfforts = append([]string(nil), v.SupportedEfforts...)
1069 out[k] = v
1070 }
1071 return out
1072 }
1073
1073 lines GO