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