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