1use std::borrow::Cow;
5use std::sync::LazyLock;
6use crate::ReasoningEffort;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub enum AnthropicModel {
10 Claude35Haiku20241022,
11 Claude35Sonnet20240620,
12 Claude35Sonnet20241022,
13 Claude37Sonnet20250219,
14 Claude3Haiku20240307,
15 Claude3Opus20240229,
16 Claude3Sonnet20240229,
17 ClaudeHaiku45,
18 ClaudeHaiku4520251001,
19 ClaudeOpus40,
20 ClaudeOpus41,
21 ClaudeOpus4120250805,
22 ClaudeOpus420250514,
23 ClaudeOpus45,
24 ClaudeOpus4520251101,
25 ClaudeOpus46,
26 ClaudeOpus47,
27 ClaudeSonnet40,
28 ClaudeSonnet420250514,
29 ClaudeSonnet45,
30 ClaudeSonnet4520250929,
31 ClaudeSonnet46,
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
35pub enum CodexModel {
36 Gpt5Codex,
37 Gpt51Codex,
38 Gpt51CodexMax,
39 Gpt51CodexMini,
40 Gpt52Codex,
41 Gpt53Codex,
42 Gpt53CodexSpark,
43 Gpt54,
44 Gpt54Mini,
45 Gpt54Nano,
46 Gpt54Pro,
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
50pub enum DeepSeekModel {
51 DeepseekChat,
52 DeepseekReasoner,
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
56pub enum GeminiModel {
57 Gemini15Flash,
58 Gemini15Flash8b,
59 Gemini15Pro,
60 Gemini20Flash,
61 Gemini20FlashLite,
62 Gemini25Flash,
63 Gemini25FlashLite,
64 Gemini25FlashLitePreview0617,
65 Gemini25FlashLitePreview092025,
66 Gemini25FlashPreview0417,
67 Gemini25FlashPreview0520,
68 Gemini25FlashPreview092025,
69 Gemini25Pro,
70 Gemini25ProPreview0506,
71 Gemini25ProPreview0605,
72 Gemini3FlashPreview,
73 Gemini3ProPreview,
74 Gemini31FlashLitePreview,
75 Gemini31ProPreview,
76 Gemini31ProPreviewCustomtools,
77 GeminiLive25Flash,
78 GeminiLive25FlashPreviewNativeAudio,
79 Gemma327bIt,
80 Gemma426bIt,
81 Gemma431bIt,
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
85pub enum MoonshotModel {
86 KimiK20711Preview,
87 KimiK20905Preview,
88 KimiK2Thinking,
89 KimiK2ThinkingTurbo,
90 KimiK2TurboPreview,
91 KimiK25,
92 KimiK26,
93}
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
96pub enum OpenaiModel {
97 Gpt4,
98 Gpt4Turbo,
99 Gpt41,
100 Gpt41Mini,
101 Gpt41Nano,
102 Gpt4o,
103 Gpt4o20240513,
104 Gpt4o20240806,
105 Gpt4o20241120,
106 Gpt4oMini,
107 Gpt5,
108 Gpt5Codex,
109 Gpt5Mini,
110 Gpt5Nano,
111 Gpt5Pro,
112 Gpt51,
113 Gpt51Codex,
114 Gpt51CodexMax,
115 Gpt51CodexMini,
116 Gpt52,
117 Gpt52Codex,
118 Gpt52Pro,
119 Gpt53Codex,
120 Gpt53CodexSpark,
121 Gpt54,
122 Gpt54Mini,
123 Gpt54Nano,
124 Gpt54Pro,
125 O1,
126 O1Pro,
127 O3,
128 O3DeepResearch,
129 O3Mini,
130 O3Pro,
131 O4Mini,
132 O4MiniDeepResearch,
133}
134
135#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
136pub enum OpenRouterModel {
137 AnthropicClaude35Haiku,
138 AnthropicClaude37Sonnet,
139 AnthropicClaudeHaiku45,
140 AnthropicClaudeOpus4,
141 AnthropicClaudeOpus41,
142 AnthropicClaudeOpus45,
143 AnthropicClaudeOpus46,
144 AnthropicClaudeOpus47,
145 AnthropicClaudeSonnet4,
146 AnthropicClaudeSonnet45,
147 AnthropicClaudeSonnet46,
148 ArceeAiTrinityLargePreviewFree,
149 ArceeAiTrinityLargeThinking,
150 DeepseekDeepseekChatV31,
151 DeepseekDeepseekR1,
152 DeepseekDeepseekV31Terminus,
153 DeepseekDeepseekV31TerminusExacto,
154 DeepseekDeepseekV32,
155 DeepseekDeepseekV32Speciale,
156 GoogleGemini20Flash001,
157 GoogleGemini25Flash,
158 GoogleGemini25FlashLite,
159 GoogleGemini25FlashLitePreview092025,
160 GoogleGemini25FlashPreview092025,
161 GoogleGemini25Pro,
162 GoogleGemini25ProPreview0506,
163 GoogleGemini25ProPreview0605,
164 GoogleGemini3FlashPreview,
165 GoogleGemini3ProPreview,
166 GoogleGemini31FlashLitePreview,
167 GoogleGemini31ProPreview,
168 GoogleGemini31ProPreviewCustomtools,
169 GoogleGemma327bIt,
170 GoogleGemma327bItFree,
171 GoogleGemma426bA4bIt,
172 GoogleGemma426bA4bItFree,
173 GoogleGemma431bIt,
174 GoogleGemma431bItFree,
175 InceptionMercury2,
176 MetaLlamaLlama3370bInstructFree,
177 MinimaxMinimax01,
178 MinimaxMinimaxM1,
179 MinimaxMinimaxM2,
180 MinimaxMinimaxM21,
181 MinimaxMinimaxM25,
182 MinimaxMinimaxM25Free,
183 MinimaxMinimaxM27,
184 MistralaiCodestral2508,
185 MistralaiDevstral2512,
186 MistralaiDevstralMedium2507,
187 MistralaiDevstralSmall2505,
188 MistralaiDevstralSmall2507,
189 MistralaiMistralMedium3,
190 MistralaiMistralMedium31,
191 MistralaiMistralSmall2603,
192 MistralaiMistralSmall3124bInstruct,
193 MistralaiMistralSmall3224bInstruct,
194 MoonshotaiKimiK2,
195 MoonshotaiKimiK20905,
196 MoonshotaiKimiK20905Exacto,
197 MoonshotaiKimiK2Thinking,
198 MoonshotaiKimiK25,
199 MoonshotaiKimiK26,
200 NousresearchHermes4405b,
201 NousresearchHermes470b,
202 NvidiaNemotron3Nano30bA3bFree,
203 NvidiaNemotron3Super120bA12b,
204 NvidiaNemotron3Super120bA12bFree,
205 NvidiaNemotronNano12bV2VlFree,
206 NvidiaNemotronNano9bV2,
207 NvidiaNemotronNano9bV2Free,
208 OpenaiGpt41,
209 OpenaiGpt41Mini,
210 OpenaiGpt4oMini,
211 OpenaiGpt5,
212 OpenaiGpt5Codex,
213 OpenaiGpt5Image,
214 OpenaiGpt5Mini,
215 OpenaiGpt5Nano,
216 OpenaiGpt5Pro,
217 OpenaiGpt51,
218 OpenaiGpt51Chat,
219 OpenaiGpt51Codex,
220 OpenaiGpt51CodexMax,
221 OpenaiGpt51CodexMini,
222 OpenaiGpt52,
223 OpenaiGpt52Chat,
224 OpenaiGpt52Codex,
225 OpenaiGpt52Pro,
226 OpenaiGpt53Codex,
227 OpenaiGpt54,
228 OpenaiGpt54Mini,
229 OpenaiGpt54Nano,
230 OpenaiGpt54Pro,
231 OpenaiGptOss120b,
232 OpenaiGptOss120bExacto,
233 OpenaiGptOss120bFree,
234 OpenaiGptOss20b,
235 OpenaiGptOss20bFree,
236 OpenaiGptOssSafeguard20b,
237 OpenaiO4Mini,
238 OpenrouterElephantAlpha,
239 OpenrouterFree,
240 PrimeIntellectIntellect3,
241 QwenQwen3235bA22b0725,
242 QwenQwen3235bA22bThinking2507,
243 QwenQwen330bA3bInstruct2507,
244 QwenQwen330bA3bThinking2507,
245 QwenQwen3Coder,
246 QwenQwen3Coder30bA3bInstruct,
247 QwenQwen3CoderFlash,
248 QwenQwen3CoderExacto,
249 QwenQwen3Max,
250 QwenQwen3Next80bA3bInstruct,
251 QwenQwen3Next80bA3bThinking,
252 QwenQwen35397bA17b,
253 QwenQwen35Flash0223,
254 QwenQwen35Plus0215,
255 QwenQwen36Plus,
256 StepfunStep35Flash,
257 XAiGrok3,
258 XAiGrok3Beta,
259 XAiGrok3Mini,
260 XAiGrok3MiniBeta,
261 XAiGrok4,
262 XAiGrok4Fast,
263 XAiGrok41Fast,
264 XAiGrok420Beta,
265 XAiGrokCodeFast1,
266 XiaomiMimoV2Flash,
267 XiaomiMimoV2Omni,
268 XiaomiMimoV2Pro,
269 ZAiGlm45,
270 ZAiGlm45Air,
271 ZAiGlm45v,
272 ZAiGlm46,
273 ZAiGlm46Exacto,
274 ZAiGlm47,
275 ZAiGlm47Flash,
276 ZAiGlm5,
277 ZAiGlm5Turbo,
278 ZAiGlm51,
279}
280
281#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
282pub enum ZAiModel {
283 Glm45,
284 Glm45Air,
285 Glm45Flash,
286 Glm45v,
287 Glm46,
288 Glm46v,
289 Glm47,
290 Glm47Flash,
291 Glm47Flashx,
292 Glm5,
293 Glm5Turbo,
294 Glm51,
295 Glm5vTurbo,
296}
297
298#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
299pub enum BedrockModel {
300 AmazonNova2LiteV10,
301 AmazonNovaLiteV10,
302 AmazonNovaMicroV10,
303 AmazonNovaPremierV10,
304 AmazonNovaProV10,
305 AnthropicClaude35Haiku20241022V10,
306 AnthropicClaude35Sonnet20240620V10,
307 AnthropicClaude35Sonnet20241022V20,
308 AnthropicClaude37Sonnet20250219V10,
309 AnthropicClaude3Haiku20240307V10,
310 AnthropicClaudeHaiku4520251001V10,
311 AnthropicClaudeOpus4120250805V10,
312 AnthropicClaudeOpus420250514V10,
313 AnthropicClaudeOpus4520251101V10,
314 AnthropicClaudeOpus46V1,
315 AnthropicClaudeOpus47,
316 AnthropicClaudeSonnet420250514V10,
317 AnthropicClaudeSonnet4520250929V10,
318 AnthropicClaudeSonnet46,
319 DeepseekR1V10,
320 DeepseekV3V10,
321 DeepseekV32,
322 EuAnthropicClaudeHaiku4520251001V10,
323 EuAnthropicClaudeOpus4520251101V10,
324 EuAnthropicClaudeOpus46V1,
325 EuAnthropicClaudeOpus47,
326 EuAnthropicClaudeSonnet420250514V10,
327 EuAnthropicClaudeSonnet4520250929V10,
328 EuAnthropicClaudeSonnet46,
329 GlobalAnthropicClaudeHaiku4520251001V10,
330 GlobalAnthropicClaudeOpus4520251101V10,
331 GlobalAnthropicClaudeOpus46V1,
332 GlobalAnthropicClaudeOpus47,
333 GlobalAnthropicClaudeSonnet420250514V10,
334 GlobalAnthropicClaudeSonnet4520250929V10,
335 GlobalAnthropicClaudeSonnet46,
336 GoogleGemma327bIt,
337 GoogleGemma34bIt,
338 MetaLlama31405bInstructV10,
339 MetaLlama3170bInstructV10,
340 MetaLlama318bInstructV10,
341 MetaLlama3211bInstructV10,
342 MetaLlama321bInstructV10,
343 MetaLlama323bInstructV10,
344 MetaLlama3290bInstructV10,
345 MetaLlama3370bInstructV10,
346 MetaLlama4Maverick17bInstructV10,
347 MetaLlama4Scout17bInstructV10,
348 MinimaxMinimaxM2,
349 MinimaxMinimaxM21,
350 MinimaxMinimaxM25,
351 MistralDevstral2123b,
352 MistralMagistralSmall2509,
353 MistralMinistral314bInstruct,
354 MistralMinistral33bInstruct,
355 MistralMinistral38bInstruct,
356 MistralMistralLarge3675bInstruct,
357 MistralPixtralLarge2502V10,
358 MistralVoxtralMini3b2507,
359 MistralVoxtralSmall24b2507,
360 MoonshotKimiK2Thinking,
361 MoonshotaiKimiK25,
362 NvidiaNemotronNano12bV2,
363 NvidiaNemotronNano330b,
364 NvidiaNemotronNano9bV2,
365 NvidiaNemotronSuper3120b,
366 OpenaiGptOss120b10,
367 OpenaiGptOss20b10,
368 OpenaiGptOssSafeguard120b,
369 OpenaiGptOssSafeguard20b,
370 QwenQwen3235bA22b2507V10,
371 QwenQwen332bV10,
372 QwenQwen3Coder30bA3bV10,
373 QwenQwen3Coder480bA35bV10,
374 QwenQwen3CoderNext,
375 QwenQwen3Next80bA3b,
376 QwenQwen3Vl235bA22b,
377 UsAnthropicClaudeHaiku4520251001V10,
378 UsAnthropicClaudeOpus4120250805V10,
379 UsAnthropicClaudeOpus420250514V10,
380 UsAnthropicClaudeOpus4520251101V10,
381 UsAnthropicClaudeOpus46V1,
382 UsAnthropicClaudeOpus47,
383 UsAnthropicClaudeSonnet420250514V10,
384 UsAnthropicClaudeSonnet4520250929V10,
385 UsAnthropicClaudeSonnet46,
386 WriterPalmyraX4V10,
387 WriterPalmyraX5V10,
388 ZaiGlm47,
389 ZaiGlm47Flash,
390 ZaiGlm5,
391}
392
393impl AnthropicModel {
394 #[allow(clippy::too_many_lines)]
395 fn model_id(self) -> &'static str {
396 match self {
397 Self::Claude35Haiku20241022 => "claude-3-5-haiku-20241022",
398 Self::Claude35Sonnet20240620 => "claude-3-5-sonnet-20240620",
399 Self::Claude35Sonnet20241022 => "claude-3-5-sonnet-20241022",
400 Self::Claude37Sonnet20250219 => "claude-3-7-sonnet-20250219",
401 Self::Claude3Haiku20240307 => "claude-3-haiku-20240307",
402 Self::Claude3Opus20240229 => "claude-3-opus-20240229",
403 Self::Claude3Sonnet20240229 => "claude-3-sonnet-20240229",
404 Self::ClaudeHaiku45 => "claude-haiku-4-5",
405 Self::ClaudeHaiku4520251001 => "claude-haiku-4-5-20251001",
406 Self::ClaudeOpus40 => "claude-opus-4-0",
407 Self::ClaudeOpus41 => "claude-opus-4-1",
408 Self::ClaudeOpus4120250805 => "claude-opus-4-1-20250805",
409 Self::ClaudeOpus420250514 => "claude-opus-4-20250514",
410 Self::ClaudeOpus45 => "claude-opus-4-5",
411 Self::ClaudeOpus4520251101 => "claude-opus-4-5-20251101",
412 Self::ClaudeOpus46 => "claude-opus-4-6",
413 Self::ClaudeOpus47 => "claude-opus-4-7",
414 Self::ClaudeSonnet40 => "claude-sonnet-4-0",
415 Self::ClaudeSonnet420250514 => "claude-sonnet-4-20250514",
416 Self::ClaudeSonnet45 => "claude-sonnet-4-5",
417 Self::ClaudeSonnet4520250929 => "claude-sonnet-4-5-20250929",
418 Self::ClaudeSonnet46 => "claude-sonnet-4-6",
419 }
420 }
421
422 #[allow(clippy::too_many_lines)]
423 fn display_name(self) -> &'static str {
424 match self {
425 Self::Claude3Haiku20240307 => "Claude Haiku 3",
426 Self::Claude35Haiku20241022 => "Claude Haiku 3.5",
427 Self::ClaudeHaiku4520251001 => "Claude Haiku 4.5",
428 Self::ClaudeHaiku45 => "Claude Haiku 4.5 (latest)",
429 Self::Claude3Opus20240229 => "Claude Opus 3",
430 Self::ClaudeOpus420250514 => "Claude Opus 4",
431 Self::ClaudeOpus40 => "Claude Opus 4 (latest)",
432 Self::ClaudeOpus4120250805 => "Claude Opus 4.1",
433 Self::ClaudeOpus41 => "Claude Opus 4.1 (latest)",
434 Self::ClaudeOpus4520251101 => "Claude Opus 4.5",
435 Self::ClaudeOpus45 => "Claude Opus 4.5 (latest)",
436 Self::ClaudeOpus46 => "Claude Opus 4.6",
437 Self::ClaudeOpus47 => "Claude Opus 4.7",
438 Self::Claude3Sonnet20240229 => "Claude Sonnet 3",
439 Self::Claude35Sonnet20240620 => "Claude Sonnet 3.5",
440 Self::Claude35Sonnet20241022 => "Claude Sonnet 3.5 v2",
441 Self::Claude37Sonnet20250219 => "Claude Sonnet 3.7",
442 Self::ClaudeSonnet420250514 => "Claude Sonnet 4",
443 Self::ClaudeSonnet40 => "Claude Sonnet 4 (latest)",
444 Self::ClaudeSonnet4520250929 => "Claude Sonnet 4.5",
445 Self::ClaudeSonnet45 => "Claude Sonnet 4.5 (latest)",
446 Self::ClaudeSonnet46 => "Claude Sonnet 4.6",
447 }
448 }
449
450 fn context_window(self) -> u32 {
451 match self {
452 Self::ClaudeOpus46 | Self::ClaudeOpus47 | Self::ClaudeSonnet46 => 1_000_000,
453 Self::Claude35Haiku20241022 | Self::Claude35Sonnet20240620 | Self::Claude35Sonnet20241022 | Self::Claude37Sonnet20250219 | Self::Claude3Haiku20240307 | Self::Claude3Opus20240229 | Self::Claude3Sonnet20240229 | Self::ClaudeHaiku45 | Self::ClaudeHaiku4520251001 | Self::ClaudeOpus40 | Self::ClaudeOpus41 | Self::ClaudeOpus4120250805 | Self::ClaudeOpus420250514 | Self::ClaudeOpus45 | Self::ClaudeOpus4520251101 | Self::ClaudeSonnet40 | Self::ClaudeSonnet420250514 | Self::ClaudeSonnet45 | Self::ClaudeSonnet4520250929 => 200_000,
454 }
455 }
456
457 pub fn reasoning_levels(self) -> &'static [ReasoningEffort] {
458 match self {
459 Self::Claude35Haiku20241022 | Self::Claude35Sonnet20240620 | Self::Claude35Sonnet20241022 | Self::Claude3Haiku20240307 | Self::Claude3Opus20240229 | Self::Claude3Sonnet20240229 => &[],
460 Self::Claude37Sonnet20250219 | Self::ClaudeHaiku45 | Self::ClaudeHaiku4520251001 | Self::ClaudeOpus40 | Self::ClaudeOpus41 | Self::ClaudeOpus4120250805 | Self::ClaudeOpus420250514 | Self::ClaudeOpus45 | Self::ClaudeOpus4520251101 | Self::ClaudeOpus46 | Self::ClaudeOpus47 | Self::ClaudeSonnet40 | Self::ClaudeSonnet420250514 | Self::ClaudeSonnet45 | Self::ClaudeSonnet4520250929 | Self::ClaudeSonnet46 => &[ReasoningEffort::Low, ReasoningEffort::Medium, ReasoningEffort::High],
461 }
462 }
463
464 pub fn supports_reasoning(self) -> bool {
465 !self.reasoning_levels().is_empty()
466 }
467
468 pub fn supports_image(self) -> bool {
469 match self {
470 Self::Claude35Haiku20241022 | Self::Claude35Sonnet20240620 | Self::Claude35Sonnet20241022 | Self::Claude37Sonnet20250219 | Self::Claude3Haiku20240307 | Self::Claude3Opus20240229 | Self::Claude3Sonnet20240229 | Self::ClaudeHaiku45 | Self::ClaudeHaiku4520251001 | Self::ClaudeOpus40 | Self::ClaudeOpus41 | Self::ClaudeOpus4120250805 | Self::ClaudeOpus420250514 | Self::ClaudeOpus45 | Self::ClaudeOpus4520251101 | Self::ClaudeOpus46 | Self::ClaudeOpus47 | Self::ClaudeSonnet40 | Self::ClaudeSonnet420250514 | Self::ClaudeSonnet45 | Self::ClaudeSonnet4520250929 | Self::ClaudeSonnet46 => true,
471 }
472 }
473
474 pub fn supports_audio(self) -> bool {
475 match self {
476 Self::Claude35Haiku20241022 | Self::Claude35Sonnet20240620 | Self::Claude35Sonnet20241022 | Self::Claude37Sonnet20250219 | Self::Claude3Haiku20240307 | Self::Claude3Opus20240229 | Self::Claude3Sonnet20240229 | Self::ClaudeHaiku45 | Self::ClaudeHaiku4520251001 | Self::ClaudeOpus40 | Self::ClaudeOpus41 | Self::ClaudeOpus4120250805 | Self::ClaudeOpus420250514 | Self::ClaudeOpus45 | Self::ClaudeOpus4520251101 | Self::ClaudeOpus46 | Self::ClaudeOpus47 | Self::ClaudeSonnet40 | Self::ClaudeSonnet420250514 | Self::ClaudeSonnet45 | Self::ClaudeSonnet4520250929 | Self::ClaudeSonnet46 => false,
477 }
478 }
479
480 const ALL: &[AnthropicModel] = &[
481 Self::Claude35Haiku20241022,
482 Self::Claude35Sonnet20240620,
483 Self::Claude35Sonnet20241022,
484 Self::Claude37Sonnet20250219,
485 Self::Claude3Haiku20240307,
486 Self::Claude3Opus20240229,
487 Self::Claude3Sonnet20240229,
488 Self::ClaudeHaiku45,
489 Self::ClaudeHaiku4520251001,
490 Self::ClaudeOpus40,
491 Self::ClaudeOpus41,
492 Self::ClaudeOpus4120250805,
493 Self::ClaudeOpus420250514,
494 Self::ClaudeOpus45,
495 Self::ClaudeOpus4520251101,
496 Self::ClaudeOpus46,
497 Self::ClaudeOpus47,
498 Self::ClaudeSonnet40,
499 Self::ClaudeSonnet420250514,
500 Self::ClaudeSonnet45,
501 Self::ClaudeSonnet4520250929,
502 Self::ClaudeSonnet46,
503 ];
504}
505
506impl std::str::FromStr for AnthropicModel {
507 type Err = String;
508
509 #[allow(clippy::too_many_lines)]
510 fn from_str(s: &str) -> Result<Self, Self::Err> {
511 match s {
512 "claude-3-5-haiku-20241022" => Ok(Self::Claude35Haiku20241022),
513 "claude-3-5-sonnet-20240620" => Ok(Self::Claude35Sonnet20240620),
514 "claude-3-5-sonnet-20241022" => Ok(Self::Claude35Sonnet20241022),
515 "claude-3-7-sonnet-20250219" => Ok(Self::Claude37Sonnet20250219),
516 "claude-3-haiku-20240307" => Ok(Self::Claude3Haiku20240307),
517 "claude-3-opus-20240229" => Ok(Self::Claude3Opus20240229),
518 "claude-3-sonnet-20240229" => Ok(Self::Claude3Sonnet20240229),
519 "claude-haiku-4-5" => Ok(Self::ClaudeHaiku45),
520 "claude-haiku-4-5-20251001" => Ok(Self::ClaudeHaiku4520251001),
521 "claude-opus-4-0" => Ok(Self::ClaudeOpus40),
522 "claude-opus-4-1" => Ok(Self::ClaudeOpus41),
523 "claude-opus-4-1-20250805" => Ok(Self::ClaudeOpus4120250805),
524 "claude-opus-4-20250514" => Ok(Self::ClaudeOpus420250514),
525 "claude-opus-4-5" => Ok(Self::ClaudeOpus45),
526 "claude-opus-4-5-20251101" => Ok(Self::ClaudeOpus4520251101),
527 "claude-opus-4-6" => Ok(Self::ClaudeOpus46),
528 "claude-opus-4-7" => Ok(Self::ClaudeOpus47),
529 "claude-sonnet-4-0" => Ok(Self::ClaudeSonnet40),
530 "claude-sonnet-4-20250514" => Ok(Self::ClaudeSonnet420250514),
531 "claude-sonnet-4-5" => Ok(Self::ClaudeSonnet45),
532 "claude-sonnet-4-5-20250929" => Ok(Self::ClaudeSonnet4520250929),
533 "claude-sonnet-4-6" => Ok(Self::ClaudeSonnet46),
534 _ => Err(format!("Unknown anthropic model: '{s}'")),
535 }
536 }
537}
538
539impl CodexModel {
540 #[allow(clippy::too_many_lines)]
541 fn model_id(self) -> &'static str {
542 match self {
543 Self::Gpt5Codex => "gpt-5-codex",
544 Self::Gpt51Codex => "gpt-5.1-codex",
545 Self::Gpt51CodexMax => "gpt-5.1-codex-max",
546 Self::Gpt51CodexMini => "gpt-5.1-codex-mini",
547 Self::Gpt52Codex => "gpt-5.2-codex",
548 Self::Gpt53Codex => "gpt-5.3-codex",
549 Self::Gpt53CodexSpark => "gpt-5.3-codex-spark",
550 Self::Gpt54 => "gpt-5.4",
551 Self::Gpt54Mini => "gpt-5.4-mini",
552 Self::Gpt54Nano => "gpt-5.4-nano",
553 Self::Gpt54Pro => "gpt-5.4-pro",
554 }
555 }
556
557 #[allow(clippy::too_many_lines)]
558 fn display_name(self) -> &'static str {
559 match self {
560 Self::Gpt5Codex => "GPT-5-Codex",
561 Self::Gpt51Codex => "GPT-5.1 Codex",
562 Self::Gpt51CodexMax => "GPT-5.1 Codex Max",
563 Self::Gpt51CodexMini => "GPT-5.1 Codex mini",
564 Self::Gpt52Codex => "GPT-5.2 Codex",
565 Self::Gpt53Codex => "GPT-5.3 Codex",
566 Self::Gpt53CodexSpark => "GPT-5.3 Codex Spark",
567 Self::Gpt54 => "GPT-5.4",
568 Self::Gpt54Pro => "GPT-5.4 Pro",
569 Self::Gpt54Mini => "GPT-5.4 mini",
570 Self::Gpt54Nano => "GPT-5.4 nano",
571 }
572 }
573
574 fn context_window(self) -> u32 {
575 match self {
576 Self::Gpt54 | Self::Gpt54Pro => 1_050_000,
577 Self::Gpt53CodexSpark => 128_000,
578 Self::Gpt5Codex | Self::Gpt51Codex | Self::Gpt51CodexMax | Self::Gpt51CodexMini | Self::Gpt52Codex | Self::Gpt53Codex | Self::Gpt54Mini | Self::Gpt54Nano => 400_000,
579 }
580 }
581
582 pub fn reasoning_levels(self) -> &'static [ReasoningEffort] {
583 match self {
584 Self::Gpt5Codex | Self::Gpt51Codex | Self::Gpt51CodexMax | Self::Gpt51CodexMini | Self::Gpt52Codex | Self::Gpt53Codex | Self::Gpt53CodexSpark | Self::Gpt54 | Self::Gpt54Mini | Self::Gpt54Nano | Self::Gpt54Pro => &[ReasoningEffort::Low, ReasoningEffort::Medium, ReasoningEffort::High, ReasoningEffort::Xhigh],
585 }
586 }
587
588 pub fn supports_reasoning(self) -> bool {
589 !self.reasoning_levels().is_empty()
590 }
591
592 pub fn supports_image(self) -> bool {
593 match self {
594 Self::Gpt5Codex | Self::Gpt51Codex | Self::Gpt51CodexMax | Self::Gpt51CodexMini | Self::Gpt52Codex | Self::Gpt53Codex | Self::Gpt53CodexSpark | Self::Gpt54 | Self::Gpt54Mini | Self::Gpt54Nano | Self::Gpt54Pro => true,
595 }
596 }
597
598 pub fn supports_audio(self) -> bool {
599 match self {
600 Self::Gpt5Codex | Self::Gpt51Codex | Self::Gpt51CodexMax | Self::Gpt51CodexMini | Self::Gpt52Codex | Self::Gpt53Codex | Self::Gpt53CodexSpark | Self::Gpt54 | Self::Gpt54Mini | Self::Gpt54Nano | Self::Gpt54Pro => false,
601 }
602 }
603
604 const ALL: &[CodexModel] = &[
605 Self::Gpt5Codex,
606 Self::Gpt51Codex,
607 Self::Gpt51CodexMax,
608 Self::Gpt51CodexMini,
609 Self::Gpt52Codex,
610 Self::Gpt53Codex,
611 Self::Gpt53CodexSpark,
612 Self::Gpt54,
613 Self::Gpt54Mini,
614 Self::Gpt54Nano,
615 Self::Gpt54Pro,
616 ];
617}
618
619impl std::str::FromStr for CodexModel {
620 type Err = String;
621
622 #[allow(clippy::too_many_lines)]
623 fn from_str(s: &str) -> Result<Self, Self::Err> {
624 match s {
625 "gpt-5-codex" => Ok(Self::Gpt5Codex),
626 "gpt-5.1-codex" => Ok(Self::Gpt51Codex),
627 "gpt-5.1-codex-max" => Ok(Self::Gpt51CodexMax),
628 "gpt-5.1-codex-mini" => Ok(Self::Gpt51CodexMini),
629 "gpt-5.2-codex" => Ok(Self::Gpt52Codex),
630 "gpt-5.3-codex" => Ok(Self::Gpt53Codex),
631 "gpt-5.3-codex-spark" => Ok(Self::Gpt53CodexSpark),
632 "gpt-5.4" => Ok(Self::Gpt54),
633 "gpt-5.4-mini" => Ok(Self::Gpt54Mini),
634 "gpt-5.4-nano" => Ok(Self::Gpt54Nano),
635 "gpt-5.4-pro" => Ok(Self::Gpt54Pro),
636 _ => Err(format!("Unknown codex model: '{s}'")),
637 }
638 }
639}
640
641impl DeepSeekModel {
642 #[allow(clippy::too_many_lines)]
643 fn model_id(self) -> &'static str {
644 match self {
645 Self::DeepseekChat => "deepseek-chat",
646 Self::DeepseekReasoner => "deepseek-reasoner",
647 }
648 }
649
650 #[allow(clippy::too_many_lines)]
651 fn display_name(self) -> &'static str {
652 match self {
653 Self::DeepseekChat => "DeepSeek Chat",
654 Self::DeepseekReasoner => "DeepSeek Reasoner",
655 }
656 }
657
658 fn context_window(self) -> u32 {
659 match self {
660 Self::DeepseekReasoner => 128_000,
661 Self::DeepseekChat => 131_072,
662 }
663 }
664
665 pub fn reasoning_levels(self) -> &'static [ReasoningEffort] {
666 match self {
667 Self::DeepseekChat => &[],
668 Self::DeepseekReasoner => &[ReasoningEffort::Low, ReasoningEffort::Medium, ReasoningEffort::High],
669 }
670 }
671
672 pub fn supports_reasoning(self) -> bool {
673 !self.reasoning_levels().is_empty()
674 }
675
676 pub fn supports_image(self) -> bool {
677 match self {
678 Self::DeepseekChat | Self::DeepseekReasoner => false,
679 }
680 }
681
682 pub fn supports_audio(self) -> bool {
683 match self {
684 Self::DeepseekChat | Self::DeepseekReasoner => false,
685 }
686 }
687
688 const ALL: &[DeepSeekModel] = &[
689 Self::DeepseekChat,
690 Self::DeepseekReasoner,
691 ];
692}
693
694impl std::str::FromStr for DeepSeekModel {
695 type Err = String;
696
697 #[allow(clippy::too_many_lines)]
698 fn from_str(s: &str) -> Result<Self, Self::Err> {
699 match s {
700 "deepseek-chat" => Ok(Self::DeepseekChat),
701 "deepseek-reasoner" => Ok(Self::DeepseekReasoner),
702 _ => Err(format!("Unknown deepseek model: '{s}'")),
703 }
704 }
705}
706
707impl GeminiModel {
708 #[allow(clippy::too_many_lines)]
709 fn model_id(self) -> &'static str {
710 match self {
711 Self::Gemini15Flash => "gemini-1.5-flash",
712 Self::Gemini15Flash8b => "gemini-1.5-flash-8b",
713 Self::Gemini15Pro => "gemini-1.5-pro",
714 Self::Gemini20Flash => "gemini-2.0-flash",
715 Self::Gemini20FlashLite => "gemini-2.0-flash-lite",
716 Self::Gemini25Flash => "gemini-2.5-flash",
717 Self::Gemini25FlashLite => "gemini-2.5-flash-lite",
718 Self::Gemini25FlashLitePreview0617 => "gemini-2.5-flash-lite-preview-06-17",
719 Self::Gemini25FlashLitePreview092025 => "gemini-2.5-flash-lite-preview-09-2025",
720 Self::Gemini25FlashPreview0417 => "gemini-2.5-flash-preview-04-17",
721 Self::Gemini25FlashPreview0520 => "gemini-2.5-flash-preview-05-20",
722 Self::Gemini25FlashPreview092025 => "gemini-2.5-flash-preview-09-2025",
723 Self::Gemini25Pro => "gemini-2.5-pro",
724 Self::Gemini25ProPreview0506 => "gemini-2.5-pro-preview-05-06",
725 Self::Gemini25ProPreview0605 => "gemini-2.5-pro-preview-06-05",
726 Self::Gemini3FlashPreview => "gemini-3-flash-preview",
727 Self::Gemini3ProPreview => "gemini-3-pro-preview",
728 Self::Gemini31FlashLitePreview => "gemini-3.1-flash-lite-preview",
729 Self::Gemini31ProPreview => "gemini-3.1-pro-preview",
730 Self::Gemini31ProPreviewCustomtools => "gemini-3.1-pro-preview-customtools",
731 Self::GeminiLive25Flash => "gemini-live-2.5-flash",
732 Self::GeminiLive25FlashPreviewNativeAudio => "gemini-live-2.5-flash-preview-native-audio",
733 Self::Gemma327bIt => "gemma-3-27b-it",
734 Self::Gemma426bIt => "gemma-4-26b-it",
735 Self::Gemma431bIt => "gemma-4-31b-it",
736 }
737 }
738
739 #[allow(clippy::too_many_lines)]
740 fn display_name(self) -> &'static str {
741 match self {
742 Self::Gemini15Flash => "Gemini 1.5 Flash",
743 Self::Gemini15Flash8b => "Gemini 1.5 Flash-8B",
744 Self::Gemini15Pro => "Gemini 1.5 Pro",
745 Self::Gemini20Flash => "Gemini 2.0 Flash",
746 Self::Gemini20FlashLite => "Gemini 2.0 Flash Lite",
747 Self::Gemini25Flash => "Gemini 2.5 Flash",
748 Self::Gemini25FlashLite => "Gemini 2.5 Flash Lite",
749 Self::Gemini25FlashLitePreview0617 => "Gemini 2.5 Flash Lite Preview 06-17",
750 Self::Gemini25FlashLitePreview092025 => "Gemini 2.5 Flash Lite Preview 09-25",
751 Self::Gemini25FlashPreview0417 => "Gemini 2.5 Flash Preview 04-17",
752 Self::Gemini25FlashPreview0520 => "Gemini 2.5 Flash Preview 05-20",
753 Self::Gemini25FlashPreview092025 => "Gemini 2.5 Flash Preview 09-25",
754 Self::Gemini25Pro => "Gemini 2.5 Pro",
755 Self::Gemini25ProPreview0506 => "Gemini 2.5 Pro Preview 05-06",
756 Self::Gemini25ProPreview0605 => "Gemini 2.5 Pro Preview 06-05",
757 Self::Gemini3FlashPreview => "Gemini 3 Flash Preview",
758 Self::Gemini3ProPreview => "Gemini 3 Pro Preview",
759 Self::Gemini31FlashLitePreview => "Gemini 3.1 Flash Lite Preview",
760 Self::Gemini31ProPreview => "Gemini 3.1 Pro Preview",
761 Self::Gemini31ProPreviewCustomtools => "Gemini 3.1 Pro Preview Custom Tools",
762 Self::GeminiLive25Flash => "Gemini Live 2.5 Flash",
763 Self::GeminiLive25FlashPreviewNativeAudio => "Gemini Live 2.5 Flash Preview Native Audio",
764 Self::Gemma327bIt => "Gemma 3 27B",
765 Self::Gemma426bIt => "Gemma 4 26B",
766 Self::Gemma431bIt => "Gemma 4 31B",
767 }
768 }
769
770 fn context_window(self) -> u32 {
771 match self {
772 Self::Gemini15Flash | Self::Gemini15Flash8b | Self::Gemini15Pro | Self::Gemini3ProPreview => 1_000_000,
773 Self::Gemini20Flash | Self::Gemini20FlashLite | Self::Gemini25Flash | Self::Gemini25FlashLite | Self::Gemini25FlashLitePreview0617 | Self::Gemini25FlashLitePreview092025 | Self::Gemini25FlashPreview0417 | Self::Gemini25FlashPreview0520 | Self::Gemini25FlashPreview092025 | Self::Gemini25Pro | Self::Gemini25ProPreview0506 | Self::Gemini25ProPreview0605 | Self::Gemini3FlashPreview | Self::Gemini31FlashLitePreview | Self::Gemini31ProPreview | Self::Gemini31ProPreviewCustomtools => 1_048_576,
774 Self::GeminiLive25Flash => 128_000,
775 Self::GeminiLive25FlashPreviewNativeAudio | Self::Gemma327bIt => 131_072,
776 Self::Gemma426bIt | Self::Gemma431bIt => 256_000,
777 }
778 }
779
780 pub fn reasoning_levels(self) -> &'static [ReasoningEffort] {
781 match self {
782 Self::Gemini15Flash | Self::Gemini15Flash8b | Self::Gemini15Pro | Self::Gemini20Flash | Self::Gemini20FlashLite | Self::Gemma327bIt => &[],
783 Self::Gemini25Flash | Self::Gemini25FlashLite | Self::Gemini25FlashLitePreview0617 | Self::Gemini25FlashLitePreview092025 | Self::Gemini25FlashPreview0417 | Self::Gemini25FlashPreview0520 | Self::Gemini25FlashPreview092025 | Self::Gemini25Pro | Self::Gemini25ProPreview0506 | Self::Gemini25ProPreview0605 | Self::Gemini3FlashPreview | Self::Gemini3ProPreview | Self::Gemini31FlashLitePreview | Self::Gemini31ProPreview | Self::Gemini31ProPreviewCustomtools | Self::GeminiLive25Flash | Self::GeminiLive25FlashPreviewNativeAudio | Self::Gemma426bIt | Self::Gemma431bIt => &[ReasoningEffort::Low, ReasoningEffort::Medium, ReasoningEffort::High],
784 }
785 }
786
787 pub fn supports_reasoning(self) -> bool {
788 !self.reasoning_levels().is_empty()
789 }
790
791 pub fn supports_image(self) -> bool {
792 match self {
793 Self::GeminiLive25FlashPreviewNativeAudio => false,
794 Self::Gemini15Flash | Self::Gemini15Flash8b | Self::Gemini15Pro | Self::Gemini20Flash | Self::Gemini20FlashLite | Self::Gemini25Flash | Self::Gemini25FlashLite | Self::Gemini25FlashLitePreview0617 | Self::Gemini25FlashLitePreview092025 | Self::Gemini25FlashPreview0417 | Self::Gemini25FlashPreview0520 | Self::Gemini25FlashPreview092025 | Self::Gemini25Pro | Self::Gemini25ProPreview0506 | Self::Gemini25ProPreview0605 | Self::Gemini3FlashPreview | Self::Gemini3ProPreview | Self::Gemini31FlashLitePreview | Self::Gemini31ProPreview | Self::Gemini31ProPreviewCustomtools | Self::GeminiLive25Flash | Self::Gemma327bIt | Self::Gemma426bIt | Self::Gemma431bIt => true,
795 }
796 }
797
798 pub fn supports_audio(self) -> bool {
799 match self {
800 Self::Gemma327bIt | Self::Gemma426bIt | Self::Gemma431bIt => false,
801 Self::Gemini15Flash | Self::Gemini15Flash8b | Self::Gemini15Pro | Self::Gemini20Flash | Self::Gemini20FlashLite | Self::Gemini25Flash | Self::Gemini25FlashLite | Self::Gemini25FlashLitePreview0617 | Self::Gemini25FlashLitePreview092025 | Self::Gemini25FlashPreview0417 | Self::Gemini25FlashPreview0520 | Self::Gemini25FlashPreview092025 | Self::Gemini25Pro | Self::Gemini25ProPreview0506 | Self::Gemini25ProPreview0605 | Self::Gemini3FlashPreview | Self::Gemini3ProPreview | Self::Gemini31FlashLitePreview | Self::Gemini31ProPreview | Self::Gemini31ProPreviewCustomtools | Self::GeminiLive25Flash | Self::GeminiLive25FlashPreviewNativeAudio => true,
802 }
803 }
804
805 const ALL: &[GeminiModel] = &[
806 Self::Gemini15Flash,
807 Self::Gemini15Flash8b,
808 Self::Gemini15Pro,
809 Self::Gemini20Flash,
810 Self::Gemini20FlashLite,
811 Self::Gemini25Flash,
812 Self::Gemini25FlashLite,
813 Self::Gemini25FlashLitePreview0617,
814 Self::Gemini25FlashLitePreview092025,
815 Self::Gemini25FlashPreview0417,
816 Self::Gemini25FlashPreview0520,
817 Self::Gemini25FlashPreview092025,
818 Self::Gemini25Pro,
819 Self::Gemini25ProPreview0506,
820 Self::Gemini25ProPreview0605,
821 Self::Gemini3FlashPreview,
822 Self::Gemini3ProPreview,
823 Self::Gemini31FlashLitePreview,
824 Self::Gemini31ProPreview,
825 Self::Gemini31ProPreviewCustomtools,
826 Self::GeminiLive25Flash,
827 Self::GeminiLive25FlashPreviewNativeAudio,
828 Self::Gemma327bIt,
829 Self::Gemma426bIt,
830 Self::Gemma431bIt,
831 ];
832}
833
834impl std::str::FromStr for GeminiModel {
835 type Err = String;
836
837 #[allow(clippy::too_many_lines)]
838 fn from_str(s: &str) -> Result<Self, Self::Err> {
839 match s {
840 "gemini-1.5-flash" => Ok(Self::Gemini15Flash),
841 "gemini-1.5-flash-8b" => Ok(Self::Gemini15Flash8b),
842 "gemini-1.5-pro" => Ok(Self::Gemini15Pro),
843 "gemini-2.0-flash" => Ok(Self::Gemini20Flash),
844 "gemini-2.0-flash-lite" => Ok(Self::Gemini20FlashLite),
845 "gemini-2.5-flash" => Ok(Self::Gemini25Flash),
846 "gemini-2.5-flash-lite" => Ok(Self::Gemini25FlashLite),
847 "gemini-2.5-flash-lite-preview-06-17" => Ok(Self::Gemini25FlashLitePreview0617),
848 "gemini-2.5-flash-lite-preview-09-2025" => Ok(Self::Gemini25FlashLitePreview092025),
849 "gemini-2.5-flash-preview-04-17" => Ok(Self::Gemini25FlashPreview0417),
850 "gemini-2.5-flash-preview-05-20" => Ok(Self::Gemini25FlashPreview0520),
851 "gemini-2.5-flash-preview-09-2025" => Ok(Self::Gemini25FlashPreview092025),
852 "gemini-2.5-pro" => Ok(Self::Gemini25Pro),
853 "gemini-2.5-pro-preview-05-06" => Ok(Self::Gemini25ProPreview0506),
854 "gemini-2.5-pro-preview-06-05" => Ok(Self::Gemini25ProPreview0605),
855 "gemini-3-flash-preview" => Ok(Self::Gemini3FlashPreview),
856 "gemini-3-pro-preview" => Ok(Self::Gemini3ProPreview),
857 "gemini-3.1-flash-lite-preview" => Ok(Self::Gemini31FlashLitePreview),
858 "gemini-3.1-pro-preview" => Ok(Self::Gemini31ProPreview),
859 "gemini-3.1-pro-preview-customtools" => Ok(Self::Gemini31ProPreviewCustomtools),
860 "gemini-live-2.5-flash" => Ok(Self::GeminiLive25Flash),
861 "gemini-live-2.5-flash-preview-native-audio" => Ok(Self::GeminiLive25FlashPreviewNativeAudio),
862 "gemma-3-27b-it" => Ok(Self::Gemma327bIt),
863 "gemma-4-26b-it" => Ok(Self::Gemma426bIt),
864 "gemma-4-31b-it" => Ok(Self::Gemma431bIt),
865 _ => Err(format!("Unknown gemini model: '{s}'")),
866 }
867 }
868}
869
870impl MoonshotModel {
871 #[allow(clippy::too_many_lines)]
872 fn model_id(self) -> &'static str {
873 match self {
874 Self::KimiK20711Preview => "kimi-k2-0711-preview",
875 Self::KimiK20905Preview => "kimi-k2-0905-preview",
876 Self::KimiK2Thinking => "kimi-k2-thinking",
877 Self::KimiK2ThinkingTurbo => "kimi-k2-thinking-turbo",
878 Self::KimiK2TurboPreview => "kimi-k2-turbo-preview",
879 Self::KimiK25 => "kimi-k2.5",
880 Self::KimiK26 => "kimi-k2.6",
881 }
882 }
883
884 #[allow(clippy::too_many_lines)]
885 fn display_name(self) -> &'static str {
886 match self {
887 Self::KimiK20711Preview => "Kimi K2 0711",
888 Self::KimiK20905Preview => "Kimi K2 0905",
889 Self::KimiK2Thinking => "Kimi K2 Thinking",
890 Self::KimiK2ThinkingTurbo => "Kimi K2 Thinking Turbo",
891 Self::KimiK2TurboPreview => "Kimi K2 Turbo",
892 Self::KimiK25 => "Kimi K2.5",
893 Self::KimiK26 => "Kimi K2.6",
894 }
895 }
896
897 fn context_window(self) -> u32 {
898 match self {
899 Self::KimiK20711Preview => 131_072,
900 Self::KimiK20905Preview | Self::KimiK2Thinking | Self::KimiK2ThinkingTurbo | Self::KimiK2TurboPreview | Self::KimiK25 | Self::KimiK26 => 262_144,
901 }
902 }
903
904 pub fn reasoning_levels(self) -> &'static [ReasoningEffort] {
905 match self {
906 Self::KimiK20711Preview | Self::KimiK20905Preview | Self::KimiK2TurboPreview => &[],
907 Self::KimiK2Thinking | Self::KimiK2ThinkingTurbo | Self::KimiK25 | Self::KimiK26 => &[ReasoningEffort::Low, ReasoningEffort::Medium, ReasoningEffort::High],
908 }
909 }
910
911 pub fn supports_reasoning(self) -> bool {
912 !self.reasoning_levels().is_empty()
913 }
914
915 pub fn supports_image(self) -> bool {
916 match self {
917 Self::KimiK20711Preview | Self::KimiK20905Preview | Self::KimiK2Thinking | Self::KimiK2ThinkingTurbo | Self::KimiK2TurboPreview => false,
918 Self::KimiK25 | Self::KimiK26 => true,
919 }
920 }
921
922 pub fn supports_audio(self) -> bool {
923 match self {
924 Self::KimiK20711Preview | Self::KimiK20905Preview | Self::KimiK2Thinking | Self::KimiK2ThinkingTurbo | Self::KimiK2TurboPreview | Self::KimiK25 | Self::KimiK26 => false,
925 }
926 }
927
928 const ALL: &[MoonshotModel] = &[
929 Self::KimiK20711Preview,
930 Self::KimiK20905Preview,
931 Self::KimiK2Thinking,
932 Self::KimiK2ThinkingTurbo,
933 Self::KimiK2TurboPreview,
934 Self::KimiK25,
935 Self::KimiK26,
936 ];
937}
938
939impl std::str::FromStr for MoonshotModel {
940 type Err = String;
941
942 #[allow(clippy::too_many_lines)]
943 fn from_str(s: &str) -> Result<Self, Self::Err> {
944 match s {
945 "kimi-k2-0711-preview" => Ok(Self::KimiK20711Preview),
946 "kimi-k2-0905-preview" => Ok(Self::KimiK20905Preview),
947 "kimi-k2-thinking" => Ok(Self::KimiK2Thinking),
948 "kimi-k2-thinking-turbo" => Ok(Self::KimiK2ThinkingTurbo),
949 "kimi-k2-turbo-preview" => Ok(Self::KimiK2TurboPreview),
950 "kimi-k2.5" => Ok(Self::KimiK25),
951 "kimi-k2.6" => Ok(Self::KimiK26),
952 _ => Err(format!("Unknown moonshot model: '{s}'")),
953 }
954 }
955}
956
957impl OpenaiModel {
958 #[allow(clippy::too_many_lines)]
959 fn model_id(self) -> &'static str {
960 match self {
961 Self::Gpt4 => "gpt-4",
962 Self::Gpt4Turbo => "gpt-4-turbo",
963 Self::Gpt41 => "gpt-4.1",
964 Self::Gpt41Mini => "gpt-4.1-mini",
965 Self::Gpt41Nano => "gpt-4.1-nano",
966 Self::Gpt4o => "gpt-4o",
967 Self::Gpt4o20240513 => "gpt-4o-2024-05-13",
968 Self::Gpt4o20240806 => "gpt-4o-2024-08-06",
969 Self::Gpt4o20241120 => "gpt-4o-2024-11-20",
970 Self::Gpt4oMini => "gpt-4o-mini",
971 Self::Gpt5 => "gpt-5",
972 Self::Gpt5Codex => "gpt-5-codex",
973 Self::Gpt5Mini => "gpt-5-mini",
974 Self::Gpt5Nano => "gpt-5-nano",
975 Self::Gpt5Pro => "gpt-5-pro",
976 Self::Gpt51 => "gpt-5.1",
977 Self::Gpt51Codex => "gpt-5.1-codex",
978 Self::Gpt51CodexMax => "gpt-5.1-codex-max",
979 Self::Gpt51CodexMini => "gpt-5.1-codex-mini",
980 Self::Gpt52 => "gpt-5.2",
981 Self::Gpt52Codex => "gpt-5.2-codex",
982 Self::Gpt52Pro => "gpt-5.2-pro",
983 Self::Gpt53Codex => "gpt-5.3-codex",
984 Self::Gpt53CodexSpark => "gpt-5.3-codex-spark",
985 Self::Gpt54 => "gpt-5.4",
986 Self::Gpt54Mini => "gpt-5.4-mini",
987 Self::Gpt54Nano => "gpt-5.4-nano",
988 Self::Gpt54Pro => "gpt-5.4-pro",
989 Self::O1 => "o1",
990 Self::O1Pro => "o1-pro",
991 Self::O3 => "o3",
992 Self::O3DeepResearch => "o3-deep-research",
993 Self::O3Mini => "o3-mini",
994 Self::O3Pro => "o3-pro",
995 Self::O4Mini => "o4-mini",
996 Self::O4MiniDeepResearch => "o4-mini-deep-research",
997 }
998 }
999
1000 #[allow(clippy::too_many_lines)]
1001 fn display_name(self) -> &'static str {
1002 match self {
1003 Self::Gpt4 => "GPT-4",
1004 Self::Gpt4Turbo => "GPT-4 Turbo",
1005 Self::Gpt41 => "GPT-4.1",
1006 Self::Gpt41Mini => "GPT-4.1 mini",
1007 Self::Gpt41Nano => "GPT-4.1 nano",
1008 Self::Gpt4o => "GPT-4o",
1009 Self::Gpt4o20240513 => "GPT-4o (2024-05-13)",
1010 Self::Gpt4o20240806 => "GPT-4o (2024-08-06)",
1011 Self::Gpt4o20241120 => "GPT-4o (2024-11-20)",
1012 Self::Gpt4oMini => "GPT-4o mini",
1013 Self::Gpt5 => "GPT-5",
1014 Self::Gpt5Mini => "GPT-5 Mini",
1015 Self::Gpt5Nano => "GPT-5 Nano",
1016 Self::Gpt5Pro => "GPT-5 Pro",
1017 Self::Gpt5Codex => "GPT-5-Codex",
1018 Self::Gpt51 => "GPT-5.1",
1019 Self::Gpt51Codex => "GPT-5.1 Codex",
1020 Self::Gpt51CodexMax => "GPT-5.1 Codex Max",
1021 Self::Gpt51CodexMini => "GPT-5.1 Codex mini",
1022 Self::Gpt52 => "GPT-5.2",
1023 Self::Gpt52Codex => "GPT-5.2 Codex",
1024 Self::Gpt52Pro => "GPT-5.2 Pro",
1025 Self::Gpt53Codex => "GPT-5.3 Codex",
1026 Self::Gpt53CodexSpark => "GPT-5.3 Codex Spark",
1027 Self::Gpt54 => "GPT-5.4",
1028 Self::Gpt54Pro => "GPT-5.4 Pro",
1029 Self::Gpt54Mini => "GPT-5.4 mini",
1030 Self::Gpt54Nano => "GPT-5.4 nano",
1031 Self::O1 => "o1",
1032 Self::O1Pro => "o1-pro",
1033 Self::O3 => "o3",
1034 Self::O3DeepResearch => "o3-deep-research",
1035 Self::O3Mini => "o3-mini",
1036 Self::O3Pro => "o3-pro",
1037 Self::O4Mini => "o4-mini",
1038 Self::O4MiniDeepResearch => "o4-mini-deep-research",
1039 }
1040 }
1041
1042 fn context_window(self) -> u32 {
1043 match self {
1044 Self::Gpt41 | Self::Gpt41Mini | Self::Gpt41Nano => 1_047_576,
1045 Self::Gpt54 | Self::Gpt54Pro => 1_050_000,
1046 Self::Gpt4Turbo | Self::Gpt4o | Self::Gpt4o20240513 | Self::Gpt4o20240806 | Self::Gpt4o20241120 | Self::Gpt4oMini | Self::Gpt53CodexSpark => 128_000,
1047 Self::O1 | Self::O1Pro | Self::O3 | Self::O3DeepResearch | Self::O3Mini | Self::O3Pro | Self::O4Mini | Self::O4MiniDeepResearch => 200_000,
1048 Self::Gpt5 | Self::Gpt5Codex | Self::Gpt5Mini | Self::Gpt5Nano | Self::Gpt5Pro | Self::Gpt51 | Self::Gpt51Codex | Self::Gpt51CodexMax | Self::Gpt51CodexMini | Self::Gpt52 | Self::Gpt52Codex | Self::Gpt52Pro | Self::Gpt53Codex | Self::Gpt54Mini | Self::Gpt54Nano => 400_000,
1049 Self::Gpt4 => 8192,
1050 }
1051 }
1052
1053 pub fn reasoning_levels(self) -> &'static [ReasoningEffort] {
1054 match self {
1055 Self::Gpt4 | Self::Gpt4Turbo | Self::Gpt41 | Self::Gpt41Mini | Self::Gpt41Nano | Self::Gpt4o | Self::Gpt4o20240513 | Self::Gpt4o20240806 | Self::Gpt4o20241120 | Self::Gpt4oMini => &[],
1056 Self::Gpt5 | Self::Gpt5Codex | Self::Gpt5Mini | Self::Gpt5Nano | Self::Gpt5Pro | Self::Gpt51 | Self::Gpt51Codex | Self::Gpt51CodexMax | Self::Gpt51CodexMini | Self::Gpt52 | Self::Gpt52Codex | Self::Gpt52Pro | Self::Gpt53Codex | Self::Gpt53CodexSpark | Self::Gpt54 | Self::Gpt54Mini | Self::Gpt54Nano | Self::Gpt54Pro | Self::O1 | Self::O1Pro | Self::O3 | Self::O3DeepResearch | Self::O3Mini | Self::O3Pro | Self::O4Mini | Self::O4MiniDeepResearch => &[ReasoningEffort::Low, ReasoningEffort::Medium, ReasoningEffort::High],
1057 }
1058 }
1059
1060 pub fn supports_reasoning(self) -> bool {
1061 !self.reasoning_levels().is_empty()
1062 }
1063
1064 pub fn supports_image(self) -> bool {
1065 match self {
1066 Self::Gpt4 | Self::O3Mini => false,
1067 Self::Gpt4Turbo | Self::Gpt41 | Self::Gpt41Mini | Self::Gpt41Nano | Self::Gpt4o | Self::Gpt4o20240513 | Self::Gpt4o20240806 | Self::Gpt4o20241120 | Self::Gpt4oMini | Self::Gpt5 | Self::Gpt5Codex | Self::Gpt5Mini | Self::Gpt5Nano | Self::Gpt5Pro | Self::Gpt51 | Self::Gpt51Codex | Self::Gpt51CodexMax | Self::Gpt51CodexMini | Self::Gpt52 | Self::Gpt52Codex | Self::Gpt52Pro | Self::Gpt53Codex | Self::Gpt53CodexSpark | Self::Gpt54 | Self::Gpt54Mini | Self::Gpt54Nano | Self::Gpt54Pro | Self::O1 | Self::O1Pro | Self::O3 | Self::O3DeepResearch | Self::O3Pro | Self::O4Mini | Self::O4MiniDeepResearch => true,
1068 }
1069 }
1070
1071 pub fn supports_audio(self) -> bool {
1072 match self {
1073 Self::Gpt4 | Self::Gpt4Turbo | Self::Gpt41 | Self::Gpt41Mini | Self::Gpt41Nano | Self::Gpt4o | Self::Gpt4o20240513 | Self::Gpt4o20240806 | Self::Gpt4o20241120 | Self::Gpt4oMini | Self::Gpt5 | Self::Gpt5Codex | Self::Gpt5Mini | Self::Gpt5Nano | Self::Gpt5Pro | Self::Gpt51 | Self::Gpt51Codex | Self::Gpt51CodexMax | Self::Gpt51CodexMini | Self::Gpt52 | Self::Gpt52Codex | Self::Gpt52Pro | Self::Gpt53Codex | Self::Gpt53CodexSpark | Self::Gpt54 | Self::Gpt54Mini | Self::Gpt54Nano | Self::Gpt54Pro | Self::O1 | Self::O1Pro | Self::O3 | Self::O3DeepResearch | Self::O3Mini | Self::O3Pro | Self::O4Mini | Self::O4MiniDeepResearch => false,
1074 }
1075 }
1076
1077 const ALL: &[OpenaiModel] = &[
1078 Self::Gpt4,
1079 Self::Gpt4Turbo,
1080 Self::Gpt41,
1081 Self::Gpt41Mini,
1082 Self::Gpt41Nano,
1083 Self::Gpt4o,
1084 Self::Gpt4o20240513,
1085 Self::Gpt4o20240806,
1086 Self::Gpt4o20241120,
1087 Self::Gpt4oMini,
1088 Self::Gpt5,
1089 Self::Gpt5Codex,
1090 Self::Gpt5Mini,
1091 Self::Gpt5Nano,
1092 Self::Gpt5Pro,
1093 Self::Gpt51,
1094 Self::Gpt51Codex,
1095 Self::Gpt51CodexMax,
1096 Self::Gpt51CodexMini,
1097 Self::Gpt52,
1098 Self::Gpt52Codex,
1099 Self::Gpt52Pro,
1100 Self::Gpt53Codex,
1101 Self::Gpt53CodexSpark,
1102 Self::Gpt54,
1103 Self::Gpt54Mini,
1104 Self::Gpt54Nano,
1105 Self::Gpt54Pro,
1106 Self::O1,
1107 Self::O1Pro,
1108 Self::O3,
1109 Self::O3DeepResearch,
1110 Self::O3Mini,
1111 Self::O3Pro,
1112 Self::O4Mini,
1113 Self::O4MiniDeepResearch,
1114 ];
1115}
1116
1117impl std::str::FromStr for OpenaiModel {
1118 type Err = String;
1119
1120 #[allow(clippy::too_many_lines)]
1121 fn from_str(s: &str) -> Result<Self, Self::Err> {
1122 match s {
1123 "gpt-4" => Ok(Self::Gpt4),
1124 "gpt-4-turbo" => Ok(Self::Gpt4Turbo),
1125 "gpt-4.1" => Ok(Self::Gpt41),
1126 "gpt-4.1-mini" => Ok(Self::Gpt41Mini),
1127 "gpt-4.1-nano" => Ok(Self::Gpt41Nano),
1128 "gpt-4o" => Ok(Self::Gpt4o),
1129 "gpt-4o-2024-05-13" => Ok(Self::Gpt4o20240513),
1130 "gpt-4o-2024-08-06" => Ok(Self::Gpt4o20240806),
1131 "gpt-4o-2024-11-20" => Ok(Self::Gpt4o20241120),
1132 "gpt-4o-mini" => Ok(Self::Gpt4oMini),
1133 "gpt-5" => Ok(Self::Gpt5),
1134 "gpt-5-codex" => Ok(Self::Gpt5Codex),
1135 "gpt-5-mini" => Ok(Self::Gpt5Mini),
1136 "gpt-5-nano" => Ok(Self::Gpt5Nano),
1137 "gpt-5-pro" => Ok(Self::Gpt5Pro),
1138 "gpt-5.1" => Ok(Self::Gpt51),
1139 "gpt-5.1-codex" => Ok(Self::Gpt51Codex),
1140 "gpt-5.1-codex-max" => Ok(Self::Gpt51CodexMax),
1141 "gpt-5.1-codex-mini" => Ok(Self::Gpt51CodexMini),
1142 "gpt-5.2" => Ok(Self::Gpt52),
1143 "gpt-5.2-codex" => Ok(Self::Gpt52Codex),
1144 "gpt-5.2-pro" => Ok(Self::Gpt52Pro),
1145 "gpt-5.3-codex" => Ok(Self::Gpt53Codex),
1146 "gpt-5.3-codex-spark" => Ok(Self::Gpt53CodexSpark),
1147 "gpt-5.4" => Ok(Self::Gpt54),
1148 "gpt-5.4-mini" => Ok(Self::Gpt54Mini),
1149 "gpt-5.4-nano" => Ok(Self::Gpt54Nano),
1150 "gpt-5.4-pro" => Ok(Self::Gpt54Pro),
1151 "o1" => Ok(Self::O1),
1152 "o1-pro" => Ok(Self::O1Pro),
1153 "o3" => Ok(Self::O3),
1154 "o3-deep-research" => Ok(Self::O3DeepResearch),
1155 "o3-mini" => Ok(Self::O3Mini),
1156 "o3-pro" => Ok(Self::O3Pro),
1157 "o4-mini" => Ok(Self::O4Mini),
1158 "o4-mini-deep-research" => Ok(Self::O4MiniDeepResearch),
1159 _ => Err(format!("Unknown openai model: '{s}'")),
1160 }
1161 }
1162}
1163
1164impl OpenRouterModel {
1165 #[allow(clippy::too_many_lines)]
1166 fn model_id(self) -> &'static str {
1167 match self {
1168 Self::AnthropicClaude35Haiku => "anthropic/claude-3.5-haiku",
1169 Self::AnthropicClaude37Sonnet => "anthropic/claude-3.7-sonnet",
1170 Self::AnthropicClaudeHaiku45 => "anthropic/claude-haiku-4.5",
1171 Self::AnthropicClaudeOpus4 => "anthropic/claude-opus-4",
1172 Self::AnthropicClaudeOpus41 => "anthropic/claude-opus-4.1",
1173 Self::AnthropicClaudeOpus45 => "anthropic/claude-opus-4.5",
1174 Self::AnthropicClaudeOpus46 => "anthropic/claude-opus-4.6",
1175 Self::AnthropicClaudeOpus47 => "anthropic/claude-opus-4.7",
1176 Self::AnthropicClaudeSonnet4 => "anthropic/claude-sonnet-4",
1177 Self::AnthropicClaudeSonnet45 => "anthropic/claude-sonnet-4.5",
1178 Self::AnthropicClaudeSonnet46 => "anthropic/claude-sonnet-4.6",
1179 Self::ArceeAiTrinityLargePreviewFree => "arcee-ai/trinity-large-preview:free",
1180 Self::ArceeAiTrinityLargeThinking => "arcee-ai/trinity-large-thinking",
1181 Self::DeepseekDeepseekChatV31 => "deepseek/deepseek-chat-v3.1",
1182 Self::DeepseekDeepseekR1 => "deepseek/deepseek-r1",
1183 Self::DeepseekDeepseekV31Terminus => "deepseek/deepseek-v3.1-terminus",
1184 Self::DeepseekDeepseekV31TerminusExacto => "deepseek/deepseek-v3.1-terminus:exacto",
1185 Self::DeepseekDeepseekV32 => "deepseek/deepseek-v3.2",
1186 Self::DeepseekDeepseekV32Speciale => "deepseek/deepseek-v3.2-speciale",
1187 Self::GoogleGemini20Flash001 => "google/gemini-2.0-flash-001",
1188 Self::GoogleGemini25Flash => "google/gemini-2.5-flash",
1189 Self::GoogleGemini25FlashLite => "google/gemini-2.5-flash-lite",
1190 Self::GoogleGemini25FlashLitePreview092025 => "google/gemini-2.5-flash-lite-preview-09-2025",
1191 Self::GoogleGemini25FlashPreview092025 => "google/gemini-2.5-flash-preview-09-2025",
1192 Self::GoogleGemini25Pro => "google/gemini-2.5-pro",
1193 Self::GoogleGemini25ProPreview0506 => "google/gemini-2.5-pro-preview-05-06",
1194 Self::GoogleGemini25ProPreview0605 => "google/gemini-2.5-pro-preview-06-05",
1195 Self::GoogleGemini3FlashPreview => "google/gemini-3-flash-preview",
1196 Self::GoogleGemini3ProPreview => "google/gemini-3-pro-preview",
1197 Self::GoogleGemini31FlashLitePreview => "google/gemini-3.1-flash-lite-preview",
1198 Self::GoogleGemini31ProPreview => "google/gemini-3.1-pro-preview",
1199 Self::GoogleGemini31ProPreviewCustomtools => "google/gemini-3.1-pro-preview-customtools",
1200 Self::GoogleGemma327bIt => "google/gemma-3-27b-it",
1201 Self::GoogleGemma327bItFree => "google/gemma-3-27b-it:free",
1202 Self::GoogleGemma426bA4bIt => "google/gemma-4-26b-a4b-it",
1203 Self::GoogleGemma426bA4bItFree => "google/gemma-4-26b-a4b-it:free",
1204 Self::GoogleGemma431bIt => "google/gemma-4-31b-it",
1205 Self::GoogleGemma431bItFree => "google/gemma-4-31b-it:free",
1206 Self::InceptionMercury2 => "inception/mercury-2",
1207 Self::MetaLlamaLlama3370bInstructFree => "meta-llama/llama-3.3-70b-instruct:free",
1208 Self::MinimaxMinimax01 => "minimax/minimax-01",
1209 Self::MinimaxMinimaxM1 => "minimax/minimax-m1",
1210 Self::MinimaxMinimaxM2 => "minimax/minimax-m2",
1211 Self::MinimaxMinimaxM21 => "minimax/minimax-m2.1",
1212 Self::MinimaxMinimaxM25 => "minimax/minimax-m2.5",
1213 Self::MinimaxMinimaxM25Free => "minimax/minimax-m2.5:free",
1214 Self::MinimaxMinimaxM27 => "minimax/minimax-m2.7",
1215 Self::MistralaiCodestral2508 => "mistralai/codestral-2508",
1216 Self::MistralaiDevstral2512 => "mistralai/devstral-2512",
1217 Self::MistralaiDevstralMedium2507 => "mistralai/devstral-medium-2507",
1218 Self::MistralaiDevstralSmall2505 => "mistralai/devstral-small-2505",
1219 Self::MistralaiDevstralSmall2507 => "mistralai/devstral-small-2507",
1220 Self::MistralaiMistralMedium3 => "mistralai/mistral-medium-3",
1221 Self::MistralaiMistralMedium31 => "mistralai/mistral-medium-3.1",
1222 Self::MistralaiMistralSmall2603 => "mistralai/mistral-small-2603",
1223 Self::MistralaiMistralSmall3124bInstruct => "mistralai/mistral-small-3.1-24b-instruct",
1224 Self::MistralaiMistralSmall3224bInstruct => "mistralai/mistral-small-3.2-24b-instruct",
1225 Self::MoonshotaiKimiK2 => "moonshotai/kimi-k2",
1226 Self::MoonshotaiKimiK20905 => "moonshotai/kimi-k2-0905",
1227 Self::MoonshotaiKimiK20905Exacto => "moonshotai/kimi-k2-0905:exacto",
1228 Self::MoonshotaiKimiK2Thinking => "moonshotai/kimi-k2-thinking",
1229 Self::MoonshotaiKimiK25 => "moonshotai/kimi-k2.5",
1230 Self::MoonshotaiKimiK26 => "moonshotai/kimi-k2.6",
1231 Self::NousresearchHermes4405b => "nousresearch/hermes-4-405b",
1232 Self::NousresearchHermes470b => "nousresearch/hermes-4-70b",
1233 Self::NvidiaNemotron3Nano30bA3bFree => "nvidia/nemotron-3-nano-30b-a3b:free",
1234 Self::NvidiaNemotron3Super120bA12b => "nvidia/nemotron-3-super-120b-a12b",
1235 Self::NvidiaNemotron3Super120bA12bFree => "nvidia/nemotron-3-super-120b-a12b:free",
1236 Self::NvidiaNemotronNano12bV2VlFree => "nvidia/nemotron-nano-12b-v2-vl:free",
1237 Self::NvidiaNemotronNano9bV2 => "nvidia/nemotron-nano-9b-v2",
1238 Self::NvidiaNemotronNano9bV2Free => "nvidia/nemotron-nano-9b-v2:free",
1239 Self::OpenaiGpt41 => "openai/gpt-4.1",
1240 Self::OpenaiGpt41Mini => "openai/gpt-4.1-mini",
1241 Self::OpenaiGpt4oMini => "openai/gpt-4o-mini",
1242 Self::OpenaiGpt5 => "openai/gpt-5",
1243 Self::OpenaiGpt5Codex => "openai/gpt-5-codex",
1244 Self::OpenaiGpt5Image => "openai/gpt-5-image",
1245 Self::OpenaiGpt5Mini => "openai/gpt-5-mini",
1246 Self::OpenaiGpt5Nano => "openai/gpt-5-nano",
1247 Self::OpenaiGpt5Pro => "openai/gpt-5-pro",
1248 Self::OpenaiGpt51 => "openai/gpt-5.1",
1249 Self::OpenaiGpt51Chat => "openai/gpt-5.1-chat",
1250 Self::OpenaiGpt51Codex => "openai/gpt-5.1-codex",
1251 Self::OpenaiGpt51CodexMax => "openai/gpt-5.1-codex-max",
1252 Self::OpenaiGpt51CodexMini => "openai/gpt-5.1-codex-mini",
1253 Self::OpenaiGpt52 => "openai/gpt-5.2",
1254 Self::OpenaiGpt52Chat => "openai/gpt-5.2-chat",
1255 Self::OpenaiGpt52Codex => "openai/gpt-5.2-codex",
1256 Self::OpenaiGpt52Pro => "openai/gpt-5.2-pro",
1257 Self::OpenaiGpt53Codex => "openai/gpt-5.3-codex",
1258 Self::OpenaiGpt54 => "openai/gpt-5.4",
1259 Self::OpenaiGpt54Mini => "openai/gpt-5.4-mini",
1260 Self::OpenaiGpt54Nano => "openai/gpt-5.4-nano",
1261 Self::OpenaiGpt54Pro => "openai/gpt-5.4-pro",
1262 Self::OpenaiGptOss120b => "openai/gpt-oss-120b",
1263 Self::OpenaiGptOss120bExacto => "openai/gpt-oss-120b:exacto",
1264 Self::OpenaiGptOss120bFree => "openai/gpt-oss-120b:free",
1265 Self::OpenaiGptOss20b => "openai/gpt-oss-20b",
1266 Self::OpenaiGptOss20bFree => "openai/gpt-oss-20b:free",
1267 Self::OpenaiGptOssSafeguard20b => "openai/gpt-oss-safeguard-20b",
1268 Self::OpenaiO4Mini => "openai/o4-mini",
1269 Self::OpenrouterElephantAlpha => "openrouter/elephant-alpha",
1270 Self::OpenrouterFree => "openrouter/free",
1271 Self::PrimeIntellectIntellect3 => "prime-intellect/intellect-3",
1272 Self::QwenQwen3235bA22b0725 => "qwen/qwen3-235b-a22b-07-25",
1273 Self::QwenQwen3235bA22bThinking2507 => "qwen/qwen3-235b-a22b-thinking-2507",
1274 Self::QwenQwen330bA3bInstruct2507 => "qwen/qwen3-30b-a3b-instruct-2507",
1275 Self::QwenQwen330bA3bThinking2507 => "qwen/qwen3-30b-a3b-thinking-2507",
1276 Self::QwenQwen3Coder => "qwen/qwen3-coder",
1277 Self::QwenQwen3Coder30bA3bInstruct => "qwen/qwen3-coder-30b-a3b-instruct",
1278 Self::QwenQwen3CoderFlash => "qwen/qwen3-coder-flash",
1279 Self::QwenQwen3CoderExacto => "qwen/qwen3-coder:exacto",
1280 Self::QwenQwen3Max => "qwen/qwen3-max",
1281 Self::QwenQwen3Next80bA3bInstruct => "qwen/qwen3-next-80b-a3b-instruct",
1282 Self::QwenQwen3Next80bA3bThinking => "qwen/qwen3-next-80b-a3b-thinking",
1283 Self::QwenQwen35397bA17b => "qwen/qwen3.5-397b-a17b",
1284 Self::QwenQwen35Flash0223 => "qwen/qwen3.5-flash-02-23",
1285 Self::QwenQwen35Plus0215 => "qwen/qwen3.5-plus-02-15",
1286 Self::QwenQwen36Plus => "qwen/qwen3.6-plus",
1287 Self::StepfunStep35Flash => "stepfun/step-3.5-flash",
1288 Self::XAiGrok3 => "x-ai/grok-3",
1289 Self::XAiGrok3Beta => "x-ai/grok-3-beta",
1290 Self::XAiGrok3Mini => "x-ai/grok-3-mini",
1291 Self::XAiGrok3MiniBeta => "x-ai/grok-3-mini-beta",
1292 Self::XAiGrok4 => "x-ai/grok-4",
1293 Self::XAiGrok4Fast => "x-ai/grok-4-fast",
1294 Self::XAiGrok41Fast => "x-ai/grok-4.1-fast",
1295 Self::XAiGrok420Beta => "x-ai/grok-4.20-beta",
1296 Self::XAiGrokCodeFast1 => "x-ai/grok-code-fast-1",
1297 Self::XiaomiMimoV2Flash => "xiaomi/mimo-v2-flash",
1298 Self::XiaomiMimoV2Omni => "xiaomi/mimo-v2-omni",
1299 Self::XiaomiMimoV2Pro => "xiaomi/mimo-v2-pro",
1300 Self::ZAiGlm45 => "z-ai/glm-4.5",
1301 Self::ZAiGlm45Air => "z-ai/glm-4.5-air",
1302 Self::ZAiGlm45v => "z-ai/glm-4.5v",
1303 Self::ZAiGlm46 => "z-ai/glm-4.6",
1304 Self::ZAiGlm46Exacto => "z-ai/glm-4.6:exacto",
1305 Self::ZAiGlm47 => "z-ai/glm-4.7",
1306 Self::ZAiGlm47Flash => "z-ai/glm-4.7-flash",
1307 Self::ZAiGlm5 => "z-ai/glm-5",
1308 Self::ZAiGlm5Turbo => "z-ai/glm-5-turbo",
1309 Self::ZAiGlm51 => "z-ai/glm-5.1",
1310 }
1311 }
1312
1313 #[allow(clippy::too_many_lines)]
1314 fn display_name(self) -> &'static str {
1315 match self {
1316 Self::AnthropicClaude35Haiku => "Claude Haiku 3.5",
1317 Self::AnthropicClaudeHaiku45 => "Claude Haiku 4.5",
1318 Self::AnthropicClaudeOpus4 => "Claude Opus 4",
1319 Self::AnthropicClaudeOpus41 => "Claude Opus 4.1",
1320 Self::AnthropicClaudeOpus45 => "Claude Opus 4.5",
1321 Self::AnthropicClaudeOpus46 => "Claude Opus 4.6",
1322 Self::AnthropicClaudeOpus47 => "Claude Opus 4.7",
1323 Self::AnthropicClaude37Sonnet => "Claude Sonnet 3.7",
1324 Self::AnthropicClaudeSonnet4 => "Claude Sonnet 4",
1325 Self::AnthropicClaudeSonnet45 => "Claude Sonnet 4.5",
1326 Self::AnthropicClaudeSonnet46 => "Claude Sonnet 4.6",
1327 Self::MistralaiCodestral2508 => "Codestral 2508",
1328 Self::DeepseekDeepseekV31Terminus => "DeepSeek V3.1 Terminus",
1329 Self::DeepseekDeepseekV31TerminusExacto => "DeepSeek V3.1 Terminus (exacto)",
1330 Self::DeepseekDeepseekV32 => "DeepSeek V3.2",
1331 Self::DeepseekDeepseekV32Speciale => "DeepSeek V3.2 Speciale",
1332 Self::DeepseekDeepseekChatV31 => "DeepSeek-V3.1",
1333 Self::DeepseekDeepseekR1 => "DeepSeek: R1",
1334 Self::MistralaiDevstral2512 => "Devstral 2 2512",
1335 Self::MistralaiDevstralMedium2507 => "Devstral Medium",
1336 Self::MistralaiDevstralSmall2505 => "Devstral Small",
1337 Self::MistralaiDevstralSmall2507 => "Devstral Small 1.1",
1338 Self::OpenrouterElephantAlpha => "Elephant (free)",
1339 Self::OpenrouterFree => "Free Models Router",
1340 Self::ZAiGlm45 => "GLM 4.5",
1341 Self::ZAiGlm45Air => "GLM 4.5 Air",
1342 Self::ZAiGlm45v => "GLM 4.5V",
1343 Self::ZAiGlm46 => "GLM 4.6",
1344 Self::ZAiGlm46Exacto => "GLM 4.6 (exacto)",
1345 Self::ZAiGlm47 => "GLM-4.7",
1346 Self::ZAiGlm47Flash => "GLM-4.7-Flash",
1347 Self::ZAiGlm5 => "GLM-5",
1348 Self::ZAiGlm5Turbo => "GLM-5-Turbo",
1349 Self::ZAiGlm51 => "GLM-5.1",
1350 Self::OpenaiGptOss120b => "GPT OSS 120B",
1351 Self::OpenaiGptOss120bExacto => "GPT OSS 120B (exacto)",
1352 Self::OpenaiGptOss20b => "GPT OSS 20B",
1353 Self::OpenaiGptOssSafeguard20b => "GPT OSS Safeguard 20B",
1354 Self::OpenaiGpt41 => "GPT-4.1",
1355 Self::OpenaiGpt41Mini => "GPT-4.1 Mini",
1356 Self::OpenaiGpt4oMini => "GPT-4o-mini",
1357 Self::OpenaiGpt5 => "GPT-5",
1358 Self::OpenaiGpt5Codex => "GPT-5 Codex",
1359 Self::OpenaiGpt5Image => "GPT-5 Image",
1360 Self::OpenaiGpt5Mini => "GPT-5 Mini",
1361 Self::OpenaiGpt5Nano => "GPT-5 Nano",
1362 Self::OpenaiGpt5Pro => "GPT-5 Pro",
1363 Self::OpenaiGpt51 => "GPT-5.1",
1364 Self::OpenaiGpt51Chat => "GPT-5.1 Chat",
1365 Self::OpenaiGpt51Codex => "GPT-5.1-Codex",
1366 Self::OpenaiGpt51CodexMax => "GPT-5.1-Codex-Max",
1367 Self::OpenaiGpt51CodexMini => "GPT-5.1-Codex-Mini",
1368 Self::OpenaiGpt52 => "GPT-5.2",
1369 Self::OpenaiGpt52Chat => "GPT-5.2 Chat",
1370 Self::OpenaiGpt52Pro => "GPT-5.2 Pro",
1371 Self::OpenaiGpt52Codex => "GPT-5.2-Codex",
1372 Self::OpenaiGpt53Codex => "GPT-5.3-Codex",
1373 Self::OpenaiGpt54 => "GPT-5.4",
1374 Self::OpenaiGpt54Mini => "GPT-5.4 Mini",
1375 Self::OpenaiGpt54Nano => "GPT-5.4 Nano",
1376 Self::OpenaiGpt54Pro => "GPT-5.4 Pro",
1377 Self::GoogleGemini20Flash001 => "Gemini 2.0 Flash",
1378 Self::GoogleGemini25Flash => "Gemini 2.5 Flash",
1379 Self::GoogleGemini25FlashLite => "Gemini 2.5 Flash Lite",
1380 Self::GoogleGemini25FlashLitePreview092025 => "Gemini 2.5 Flash Lite Preview 09-25",
1381 Self::GoogleGemini25FlashPreview092025 => "Gemini 2.5 Flash Preview 09-25",
1382 Self::GoogleGemini25Pro => "Gemini 2.5 Pro",
1383 Self::GoogleGemini25ProPreview0506 => "Gemini 2.5 Pro Preview 05-06",
1384 Self::GoogleGemini25ProPreview0605 => "Gemini 2.5 Pro Preview 06-05",
1385 Self::GoogleGemini3FlashPreview => "Gemini 3 Flash Preview",
1386 Self::GoogleGemini3ProPreview => "Gemini 3 Pro Preview",
1387 Self::GoogleGemini31FlashLitePreview => "Gemini 3.1 Flash Lite Preview",
1388 Self::GoogleGemini31ProPreview => "Gemini 3.1 Pro Preview",
1389 Self::GoogleGemini31ProPreviewCustomtools => "Gemini 3.1 Pro Preview Custom Tools",
1390 Self::GoogleGemma327bIt => "Gemma 3 27B",
1391 Self::GoogleGemma327bItFree => "Gemma 3 27B (free)",
1392 Self::GoogleGemma426bA4bIt => "Gemma 4 26B A4B",
1393 Self::GoogleGemma426bA4bItFree => "Gemma 4 26B A4B (free)",
1394 Self::GoogleGemma431bIt => "Gemma 4 31B",
1395 Self::GoogleGemma431bItFree => "Gemma 4 31B (free)",
1396 Self::XAiGrok3 => "Grok 3",
1397 Self::XAiGrok3Beta => "Grok 3 Beta",
1398 Self::XAiGrok3Mini => "Grok 3 Mini",
1399 Self::XAiGrok3MiniBeta => "Grok 3 Mini Beta",
1400 Self::XAiGrok4 => "Grok 4",
1401 Self::XAiGrok4Fast => "Grok 4 Fast",
1402 Self::XAiGrok41Fast => "Grok 4.1 Fast",
1403 Self::XAiGrok420Beta => "Grok 4.20 Beta",
1404 Self::XAiGrokCodeFast1 => "Grok Code Fast 1",
1405 Self::NousresearchHermes4405b => "Hermes 4 405B",
1406 Self::NousresearchHermes470b => "Hermes 4 70B",
1407 Self::PrimeIntellectIntellect3 => "Intellect 3",
1408 Self::MoonshotaiKimiK2 => "Kimi K2",
1409 Self::MoonshotaiKimiK20905 => "Kimi K2 Instruct 0905",
1410 Self::MoonshotaiKimiK20905Exacto => "Kimi K2 Instruct 0905 (exacto)",
1411 Self::MoonshotaiKimiK2Thinking => "Kimi K2 Thinking",
1412 Self::MoonshotaiKimiK25 => "Kimi K2.5",
1413 Self::MoonshotaiKimiK26 => "Kimi K2.6",
1414 Self::MetaLlamaLlama3370bInstructFree => "Llama 3.3 70B Instruct (free)",
1415 Self::InceptionMercury2 => "Mercury 2",
1416 Self::XiaomiMimoV2Flash => "MiMo-V2-Flash",
1417 Self::XiaomiMimoV2Omni => "MiMo-V2-Omni",
1418 Self::XiaomiMimoV2Pro => "MiMo-V2-Pro",
1419 Self::MinimaxMinimaxM1 => "MiniMax M1",
1420 Self::MinimaxMinimaxM2 => "MiniMax M2",
1421 Self::MinimaxMinimaxM21 => "MiniMax M2.1",
1422 Self::MinimaxMinimaxM25 => "MiniMax M2.5",
1423 Self::MinimaxMinimaxM25Free => "MiniMax M2.5 (free)",
1424 Self::MinimaxMinimaxM27 => "MiniMax M2.7",
1425 Self::MinimaxMinimax01 => "MiniMax-01",
1426 Self::MistralaiMistralMedium3 => "Mistral Medium 3",
1427 Self::MistralaiMistralMedium31 => "Mistral Medium 3.1",
1428 Self::MistralaiMistralSmall3124bInstruct => "Mistral Small 3.1 24B Instruct",
1429 Self::MistralaiMistralSmall3224bInstruct => "Mistral Small 3.2 24B Instruct",
1430 Self::MistralaiMistralSmall2603 => "Mistral Small 4",
1431 Self::NvidiaNemotron3Nano30bA3bFree => "Nemotron 3 Nano 30B A3B (free)",
1432 Self::NvidiaNemotron3Super120bA12b => "Nemotron 3 Super",
1433 Self::NvidiaNemotron3Super120bA12bFree => "Nemotron 3 Super (free)",
1434 Self::NvidiaNemotronNano12bV2VlFree => "Nemotron Nano 12B 2 VL (free)",
1435 Self::NvidiaNemotronNano9bV2Free => "Nemotron Nano 9B V2 (free)",
1436 Self::QwenQwen3235bA22b0725 => "Qwen3 235B A22B Instruct 2507",
1437 Self::QwenQwen3235bA22bThinking2507 => "Qwen3 235B A22B Thinking 2507",
1438 Self::QwenQwen330bA3bInstruct2507 => "Qwen3 30B A3B Instruct 2507",
1439 Self::QwenQwen330bA3bThinking2507 => "Qwen3 30B A3B Thinking 2507",
1440 Self::QwenQwen3Coder => "Qwen3 Coder",
1441 Self::QwenQwen3CoderExacto => "Qwen3 Coder (exacto)",
1442 Self::QwenQwen3Coder30bA3bInstruct => "Qwen3 Coder 30B A3B Instruct",
1443 Self::QwenQwen3CoderFlash => "Qwen3 Coder Flash",
1444 Self::QwenQwen3Max => "Qwen3 Max",
1445 Self::QwenQwen3Next80bA3bInstruct => "Qwen3 Next 80B A3B Instruct",
1446 Self::QwenQwen3Next80bA3bThinking => "Qwen3 Next 80B A3B Thinking",
1447 Self::QwenQwen35397bA17b => "Qwen3.5 397B A17B",
1448 Self::QwenQwen35Plus0215 => "Qwen3.5 Plus 2026-02-15",
1449 Self::QwenQwen36Plus => "Qwen3.6 Plus",
1450 Self::QwenQwen35Flash0223 => "Qwen: Qwen3.5-Flash",
1451 Self::StepfunStep35Flash => "Step 3.5 Flash",
1452 Self::ArceeAiTrinityLargePreviewFree => "Trinity Large Preview",
1453 Self::ArceeAiTrinityLargeThinking => "Trinity Large Thinking",
1454 Self::OpenaiGptOss120bFree => "gpt-oss-120b (free)",
1455 Self::OpenaiGptOss20bFree => "gpt-oss-20b (free)",
1456 Self::NvidiaNemotronNano9bV2 => "nvidia-nemotron-nano-9b-v2",
1457 Self::OpenaiO4Mini => "o4 Mini",
1458 }
1459 }
1460
1461 fn context_window(self) -> u32 {
1462 match self {
1463 Self::AnthropicClaudeOpus46 | Self::AnthropicClaudeOpus47 | Self::AnthropicClaudeSonnet45 | Self::AnthropicClaudeSonnet46 | Self::MinimaxMinimax01 | Self::MinimaxMinimaxM1 | Self::QwenQwen35Flash0223 | Self::QwenQwen35Plus0215 | Self::QwenQwen36Plus => 1_000_000,
1464 Self::OpenaiGpt41 | Self::OpenaiGpt41Mini => 1_047_576,
1465 Self::GoogleGemini20Flash001 | Self::GoogleGemini25Flash | Self::GoogleGemini25FlashLite | Self::GoogleGemini25FlashLitePreview092025 | Self::GoogleGemini25FlashPreview092025 | Self::GoogleGemini25Pro | Self::GoogleGemini25ProPreview0506 | Self::GoogleGemini25ProPreview0605 | Self::GoogleGemini3FlashPreview | Self::GoogleGemini31FlashLitePreview | Self::GoogleGemini31ProPreview | Self::GoogleGemini31ProPreviewCustomtools | Self::XiaomiMimoV2Pro => 1_048_576,
1466 Self::GoogleGemini3ProPreview | Self::OpenaiGpt54 | Self::OpenaiGpt54Pro => 1_050_000,
1467 Self::InceptionMercury2 | Self::MistralaiDevstralSmall2505 | Self::MistralaiMistralSmall3124bInstruct | Self::NvidiaNemotronNano12bV2VlFree | Self::NvidiaNemotronNano9bV2Free | Self::OpenaiGpt4oMini | Self::OpenaiGpt51Chat | Self::OpenaiGpt52Chat | Self::QwenQwen3CoderFlash | Self::ZAiGlm45 | Self::ZAiGlm45Air => 128_000,
1468 Self::ArceeAiTrinityLargePreviewFree | Self::DeepseekDeepseekV31Terminus | Self::DeepseekDeepseekV31TerminusExacto | Self::GoogleGemma327bItFree | Self::MetaLlamaLlama3370bInstructFree | Self::MistralaiDevstralMedium2507 | Self::MistralaiDevstralSmall2507 | Self::MistralaiMistralMedium3 | Self::MoonshotaiKimiK2 | Self::NousresearchHermes4405b | Self::NousresearchHermes470b | Self::NvidiaNemotronNano9bV2 | Self::OpenaiGptOss120b | Self::OpenaiGptOss120bExacto | Self::OpenaiGptOss120bFree | Self::OpenaiGptOss20b | Self::OpenaiGptOss20bFree | Self::OpenaiGptOssSafeguard20b | Self::PrimeIntellectIntellect3 | Self::QwenQwen3CoderExacto | Self::XAiGrok3 | Self::XAiGrok3Beta | Self::XAiGrok3Mini | Self::XAiGrok3MiniBeta => 131_072,
1469 Self::QwenQwen3Coder30bA3bInstruct => 160_000,
1470 Self::DeepseekDeepseekChatV31 | Self::DeepseekDeepseekV32 | Self::DeepseekDeepseekV32Speciale => 163_840,
1471 Self::MinimaxMinimaxM2 => 196_600,
1472 Self::AnthropicClaude35Haiku | Self::AnthropicClaude37Sonnet | Self::AnthropicClaudeHaiku45 | Self::AnthropicClaudeOpus4 | Self::AnthropicClaudeOpus41 | Self::AnthropicClaudeOpus45 | Self::AnthropicClaudeSonnet4 | Self::OpenaiO4Mini | Self::OpenrouterFree | Self::ZAiGlm46 | Self::ZAiGlm46Exacto | Self::ZAiGlm47Flash => 200_000,
1473 Self::XAiGrok4Fast | Self::XAiGrok41Fast | Self::XAiGrok420Beta => 2_000_000,
1474 Self::ZAiGlm5 | Self::ZAiGlm5Turbo | Self::ZAiGlm51 => 202_752,
1475 Self::MinimaxMinimaxM21 | Self::MinimaxMinimaxM25 | Self::MinimaxMinimaxM25Free | Self::MinimaxMinimaxM27 | Self::ZAiGlm47 => 204_800,
1476 Self::MistralaiCodestral2508 | Self::NvidiaNemotron3Nano30bA3bFree | Self::StepfunStep35Flash | Self::XAiGrok4 | Self::XAiGrokCodeFast1 => 256_000,
1477 Self::QwenQwen330bA3bInstruct2507 | Self::QwenQwen330bA3bThinking2507 => 262_000,
1478 Self::ArceeAiTrinityLargeThinking | Self::GoogleGemma426bA4bIt | Self::GoogleGemma426bA4bItFree | Self::GoogleGemma431bIt | Self::GoogleGemma431bItFree | Self::MistralaiDevstral2512 | Self::MistralaiMistralMedium31 | Self::MistralaiMistralSmall2603 | Self::MoonshotaiKimiK20905 | Self::MoonshotaiKimiK20905Exacto | Self::MoonshotaiKimiK2Thinking | Self::MoonshotaiKimiK25 | Self::MoonshotaiKimiK26 | Self::NvidiaNemotron3Super120bA12b | Self::NvidiaNemotron3Super120bA12bFree | Self::OpenrouterElephantAlpha | Self::QwenQwen3235bA22b0725 | Self::QwenQwen3235bA22bThinking2507 | Self::QwenQwen3Coder | Self::QwenQwen3Max | Self::QwenQwen3Next80bA3bInstruct | Self::QwenQwen3Next80bA3bThinking | Self::QwenQwen35397bA17b | Self::XiaomiMimoV2Flash | Self::XiaomiMimoV2Omni => 262_144,
1479 Self::OpenaiGpt5 | Self::OpenaiGpt5Codex | Self::OpenaiGpt5Image | Self::OpenaiGpt5Mini | Self::OpenaiGpt5Nano | Self::OpenaiGpt5Pro | Self::OpenaiGpt51 | Self::OpenaiGpt51Codex | Self::OpenaiGpt51CodexMax | Self::OpenaiGpt51CodexMini | Self::OpenaiGpt52 | Self::OpenaiGpt52Codex | Self::OpenaiGpt52Pro | Self::OpenaiGpt53Codex | Self::OpenaiGpt54Mini | Self::OpenaiGpt54Nano => 400_000,
1480 Self::DeepseekDeepseekR1 | Self::ZAiGlm45v => 64_000,
1481 Self::GoogleGemma327bIt | Self::MistralaiMistralSmall3224bInstruct => 96_000,
1482 }
1483 }
1484
1485 pub fn reasoning_levels(self) -> &'static [ReasoningEffort] {
1486 match self {
1487 Self::AnthropicClaude35Haiku | Self::ArceeAiTrinityLargePreviewFree | Self::GoogleGemini20Flash001 | Self::GoogleGemma327bIt | Self::GoogleGemma327bItFree | Self::MetaLlamaLlama3370bInstructFree | Self::MistralaiCodestral2508 | Self::MistralaiDevstral2512 | Self::MistralaiDevstralMedium2507 | Self::MistralaiDevstralSmall2505 | Self::MistralaiDevstralSmall2507 | Self::MistralaiMistralMedium3 | Self::MistralaiMistralMedium31 | Self::MistralaiMistralSmall3124bInstruct | Self::MistralaiMistralSmall3224bInstruct | Self::MoonshotaiKimiK2 | Self::MoonshotaiKimiK20905 | Self::MoonshotaiKimiK20905Exacto | Self::OpenaiGpt41 | Self::OpenaiGpt41Mini | Self::OpenaiGpt4oMini | Self::OpenaiGpt54Nano | Self::QwenQwen3235bA22b0725 | Self::QwenQwen330bA3bInstruct2507 | Self::QwenQwen3Coder | Self::QwenQwen3Coder30bA3bInstruct | Self::QwenQwen3CoderFlash | Self::QwenQwen3CoderExacto | Self::QwenQwen3Next80bA3bInstruct | Self::XAiGrok3 | Self::XAiGrok3Beta => &[],
1488 Self::AnthropicClaude37Sonnet | Self::AnthropicClaudeHaiku45 | Self::AnthropicClaudeOpus4 | Self::AnthropicClaudeOpus41 | Self::AnthropicClaudeOpus45 | Self::AnthropicClaudeOpus46 | Self::AnthropicClaudeOpus47 | Self::AnthropicClaudeSonnet4 | Self::AnthropicClaudeSonnet45 | Self::AnthropicClaudeSonnet46 | Self::ArceeAiTrinityLargeThinking | Self::DeepseekDeepseekChatV31 | Self::DeepseekDeepseekR1 | Self::DeepseekDeepseekV31Terminus | Self::DeepseekDeepseekV31TerminusExacto | Self::DeepseekDeepseekV32 | Self::DeepseekDeepseekV32Speciale | Self::GoogleGemini25Flash | Self::GoogleGemini25FlashLite | Self::GoogleGemini25FlashLitePreview092025 | Self::GoogleGemini25FlashPreview092025 | Self::GoogleGemini25Pro | Self::GoogleGemini25ProPreview0506 | Self::GoogleGemini25ProPreview0605 | Self::GoogleGemini3FlashPreview | Self::GoogleGemini3ProPreview | Self::GoogleGemini31FlashLitePreview | Self::GoogleGemini31ProPreview | Self::GoogleGemini31ProPreviewCustomtools | Self::GoogleGemma426bA4bIt | Self::GoogleGemma426bA4bItFree | Self::GoogleGemma431bIt | Self::GoogleGemma431bItFree | Self::InceptionMercury2 | Self::MinimaxMinimax01 | Self::MinimaxMinimaxM1 | Self::MinimaxMinimaxM2 | Self::MinimaxMinimaxM21 | Self::MinimaxMinimaxM25 | Self::MinimaxMinimaxM25Free | Self::MinimaxMinimaxM27 | Self::MistralaiMistralSmall2603 | Self::MoonshotaiKimiK2Thinking | Self::MoonshotaiKimiK25 | Self::MoonshotaiKimiK26 | Self::NousresearchHermes4405b | Self::NousresearchHermes470b | Self::NvidiaNemotron3Nano30bA3bFree | Self::NvidiaNemotron3Super120bA12b | Self::NvidiaNemotron3Super120bA12bFree | Self::NvidiaNemotronNano12bV2VlFree | Self::NvidiaNemotronNano9bV2 | Self::NvidiaNemotronNano9bV2Free | Self::OpenaiGpt5 | Self::OpenaiGpt5Codex | Self::OpenaiGpt5Image | Self::OpenaiGpt5Mini | Self::OpenaiGpt5Nano | Self::OpenaiGpt5Pro | Self::OpenaiGpt51 | Self::OpenaiGpt51Chat | Self::OpenaiGpt51Codex | Self::OpenaiGpt51CodexMax | Self::OpenaiGpt51CodexMini | Self::OpenaiGpt52 | Self::OpenaiGpt52Chat | Self::OpenaiGpt52Codex | Self::OpenaiGpt52Pro | Self::OpenaiGpt53Codex | Self::OpenaiGpt54 | Self::OpenaiGpt54Mini | Self::OpenaiGpt54Pro | Self::OpenaiGptOss120b | Self::OpenaiGptOss120bExacto | Self::OpenaiGptOss120bFree | Self::OpenaiGptOss20b | Self::OpenaiGptOss20bFree | Self::OpenaiGptOssSafeguard20b | Self::OpenaiO4Mini | Self::OpenrouterElephantAlpha | Self::OpenrouterFree | Self::PrimeIntellectIntellect3 | Self::QwenQwen3235bA22bThinking2507 | Self::QwenQwen330bA3bThinking2507 | Self::QwenQwen3Max | Self::QwenQwen3Next80bA3bThinking | Self::QwenQwen35397bA17b | Self::QwenQwen35Flash0223 | Self::QwenQwen35Plus0215 | Self::QwenQwen36Plus | Self::StepfunStep35Flash | Self::XAiGrok3Mini | Self::XAiGrok3MiniBeta | Self::XAiGrok4 | Self::XAiGrok4Fast | Self::XAiGrok41Fast | Self::XAiGrok420Beta | Self::XAiGrokCodeFast1 | Self::XiaomiMimoV2Flash | Self::XiaomiMimoV2Omni | Self::XiaomiMimoV2Pro | Self::ZAiGlm45 | Self::ZAiGlm45Air | Self::ZAiGlm45v | Self::ZAiGlm46 | Self::ZAiGlm46Exacto | Self::ZAiGlm47 | Self::ZAiGlm47Flash | Self::ZAiGlm5 | Self::ZAiGlm5Turbo | Self::ZAiGlm51 => &[ReasoningEffort::Low, ReasoningEffort::Medium, ReasoningEffort::High],
1489 }
1490 }
1491
1492 pub fn supports_reasoning(self) -> bool {
1493 !self.reasoning_levels().is_empty()
1494 }
1495
1496 pub fn supports_image(self) -> bool {
1497 match self {
1498 Self::ArceeAiTrinityLargePreviewFree | Self::ArceeAiTrinityLargeThinking | Self::DeepseekDeepseekChatV31 | Self::DeepseekDeepseekR1 | Self::DeepseekDeepseekV31Terminus | Self::DeepseekDeepseekV31TerminusExacto | Self::DeepseekDeepseekV32 | Self::DeepseekDeepseekV32Speciale | Self::InceptionMercury2 | Self::MetaLlamaLlama3370bInstructFree | Self::MinimaxMinimaxM1 | Self::MinimaxMinimaxM2 | Self::MinimaxMinimaxM21 | Self::MinimaxMinimaxM25 | Self::MinimaxMinimaxM25Free | Self::MinimaxMinimaxM27 | Self::MistralaiCodestral2508 | Self::MistralaiDevstral2512 | Self::MistralaiDevstralMedium2507 | Self::MistralaiDevstralSmall2505 | Self::MistralaiDevstralSmall2507 | Self::MoonshotaiKimiK2 | Self::MoonshotaiKimiK20905 | Self::MoonshotaiKimiK20905Exacto | Self::MoonshotaiKimiK2Thinking | Self::NousresearchHermes4405b | Self::NousresearchHermes470b | Self::NvidiaNemotron3Nano30bA3bFree | Self::NvidiaNemotron3Super120bA12b | Self::NvidiaNemotron3Super120bA12bFree | Self::NvidiaNemotronNano9bV2 | Self::NvidiaNemotronNano9bV2Free | Self::OpenaiGptOss120b | Self::OpenaiGptOss120bExacto | Self::OpenaiGptOss120bFree | Self::OpenaiGptOss20b | Self::OpenaiGptOss20bFree | Self::OpenaiGptOssSafeguard20b | Self::OpenrouterElephantAlpha | Self::PrimeIntellectIntellect3 | Self::QwenQwen3235bA22b0725 | Self::QwenQwen3235bA22bThinking2507 | Self::QwenQwen330bA3bInstruct2507 | Self::QwenQwen330bA3bThinking2507 | Self::QwenQwen3Coder | Self::QwenQwen3Coder30bA3bInstruct | Self::QwenQwen3CoderFlash | Self::QwenQwen3CoderExacto | Self::QwenQwen3Max | Self::QwenQwen3Next80bA3bInstruct | Self::QwenQwen3Next80bA3bThinking | Self::StepfunStep35Flash | Self::XAiGrok3 | Self::XAiGrok3Beta | Self::XAiGrok3Mini | Self::XAiGrok3MiniBeta | Self::XAiGrok4 | Self::XAiGrokCodeFast1 | Self::XiaomiMimoV2Flash | Self::XiaomiMimoV2Pro | Self::ZAiGlm45 | Self::ZAiGlm45Air | Self::ZAiGlm46 | Self::ZAiGlm46Exacto | Self::ZAiGlm47 | Self::ZAiGlm47Flash | Self::ZAiGlm5 | Self::ZAiGlm5Turbo | Self::ZAiGlm51 => false,
1499 Self::AnthropicClaude35Haiku | Self::AnthropicClaude37Sonnet | Self::AnthropicClaudeHaiku45 | Self::AnthropicClaudeOpus4 | Self::AnthropicClaudeOpus41 | Self::AnthropicClaudeOpus45 | Self::AnthropicClaudeOpus46 | Self::AnthropicClaudeOpus47 | Self::AnthropicClaudeSonnet4 | Self::AnthropicClaudeSonnet45 | Self::AnthropicClaudeSonnet46 | Self::GoogleGemini20Flash001 | Self::GoogleGemini25Flash | Self::GoogleGemini25FlashLite | Self::GoogleGemini25FlashLitePreview092025 | Self::GoogleGemini25FlashPreview092025 | Self::GoogleGemini25Pro | Self::GoogleGemini25ProPreview0506 | Self::GoogleGemini25ProPreview0605 | Self::GoogleGemini3FlashPreview | Self::GoogleGemini3ProPreview | Self::GoogleGemini31FlashLitePreview | Self::GoogleGemini31ProPreview | Self::GoogleGemini31ProPreviewCustomtools | Self::GoogleGemma327bIt | Self::GoogleGemma327bItFree | Self::GoogleGemma426bA4bIt | Self::GoogleGemma426bA4bItFree | Self::GoogleGemma431bIt | Self::GoogleGemma431bItFree | Self::MinimaxMinimax01 | Self::MistralaiMistralMedium3 | Self::MistralaiMistralMedium31 | Self::MistralaiMistralSmall2603 | Self::MistralaiMistralSmall3124bInstruct | Self::MistralaiMistralSmall3224bInstruct | Self::MoonshotaiKimiK25 | Self::MoonshotaiKimiK26 | Self::NvidiaNemotronNano12bV2VlFree | Self::OpenaiGpt41 | Self::OpenaiGpt41Mini | Self::OpenaiGpt4oMini | Self::OpenaiGpt5 | Self::OpenaiGpt5Codex | Self::OpenaiGpt5Image | Self::OpenaiGpt5Mini | Self::OpenaiGpt5Nano | Self::OpenaiGpt5Pro | Self::OpenaiGpt51 | Self::OpenaiGpt51Chat | Self::OpenaiGpt51Codex | Self::OpenaiGpt51CodexMax | Self::OpenaiGpt51CodexMini | Self::OpenaiGpt52 | Self::OpenaiGpt52Chat | Self::OpenaiGpt52Codex | Self::OpenaiGpt52Pro | Self::OpenaiGpt53Codex | Self::OpenaiGpt54 | Self::OpenaiGpt54Mini | Self::OpenaiGpt54Nano | Self::OpenaiGpt54Pro | Self::OpenaiO4Mini | Self::OpenrouterFree | Self::QwenQwen35397bA17b | Self::QwenQwen35Flash0223 | Self::QwenQwen35Plus0215 | Self::QwenQwen36Plus | Self::XAiGrok4Fast | Self::XAiGrok41Fast | Self::XAiGrok420Beta | Self::XiaomiMimoV2Omni | Self::ZAiGlm45v => true,
1500 }
1501 }
1502
1503 pub fn supports_audio(self) -> bool {
1504 match self {
1505 Self::AnthropicClaude35Haiku | Self::AnthropicClaude37Sonnet | Self::AnthropicClaudeHaiku45 | Self::AnthropicClaudeOpus4 | Self::AnthropicClaudeOpus41 | Self::AnthropicClaudeOpus45 | Self::AnthropicClaudeOpus46 | Self::AnthropicClaudeOpus47 | Self::AnthropicClaudeSonnet4 | Self::AnthropicClaudeSonnet45 | Self::AnthropicClaudeSonnet46 | Self::ArceeAiTrinityLargePreviewFree | Self::ArceeAiTrinityLargeThinking | Self::DeepseekDeepseekChatV31 | Self::DeepseekDeepseekR1 | Self::DeepseekDeepseekV31Terminus | Self::DeepseekDeepseekV31TerminusExacto | Self::DeepseekDeepseekV32 | Self::DeepseekDeepseekV32Speciale | Self::GoogleGemma327bIt | Self::GoogleGemma327bItFree | Self::GoogleGemma426bA4bIt | Self::GoogleGemma426bA4bItFree | Self::GoogleGemma431bIt | Self::GoogleGemma431bItFree | Self::InceptionMercury2 | Self::MetaLlamaLlama3370bInstructFree | Self::MinimaxMinimax01 | Self::MinimaxMinimaxM1 | Self::MinimaxMinimaxM2 | Self::MinimaxMinimaxM21 | Self::MinimaxMinimaxM25 | Self::MinimaxMinimaxM25Free | Self::MinimaxMinimaxM27 | Self::MistralaiCodestral2508 | Self::MistralaiDevstral2512 | Self::MistralaiDevstralMedium2507 | Self::MistralaiDevstralSmall2505 | Self::MistralaiDevstralSmall2507 | Self::MistralaiMistralMedium3 | Self::MistralaiMistralMedium31 | Self::MistralaiMistralSmall2603 | Self::MistralaiMistralSmall3124bInstruct | Self::MistralaiMistralSmall3224bInstruct | Self::MoonshotaiKimiK2 | Self::MoonshotaiKimiK20905 | Self::MoonshotaiKimiK20905Exacto | Self::MoonshotaiKimiK2Thinking | Self::MoonshotaiKimiK25 | Self::MoonshotaiKimiK26 | Self::NousresearchHermes4405b | Self::NousresearchHermes470b | Self::NvidiaNemotron3Nano30bA3bFree | Self::NvidiaNemotron3Super120bA12b | Self::NvidiaNemotron3Super120bA12bFree | Self::NvidiaNemotronNano12bV2VlFree | Self::NvidiaNemotronNano9bV2 | Self::NvidiaNemotronNano9bV2Free | Self::OpenaiGpt41 | Self::OpenaiGpt41Mini | Self::OpenaiGpt4oMini | Self::OpenaiGpt5 | Self::OpenaiGpt5Codex | Self::OpenaiGpt5Image | Self::OpenaiGpt5Mini | Self::OpenaiGpt5Nano | Self::OpenaiGpt5Pro | Self::OpenaiGpt51 | Self::OpenaiGpt51Chat | Self::OpenaiGpt51Codex | Self::OpenaiGpt51CodexMax | Self::OpenaiGpt51CodexMini | Self::OpenaiGpt52 | Self::OpenaiGpt52Chat | Self::OpenaiGpt52Codex | Self::OpenaiGpt52Pro | Self::OpenaiGpt53Codex | Self::OpenaiGpt54 | Self::OpenaiGpt54Mini | Self::OpenaiGpt54Nano | Self::OpenaiGpt54Pro | Self::OpenaiGptOss120b | Self::OpenaiGptOss120bExacto | Self::OpenaiGptOss120bFree | Self::OpenaiGptOss20b | Self::OpenaiGptOss20bFree | Self::OpenaiGptOssSafeguard20b | Self::OpenaiO4Mini | Self::OpenrouterElephantAlpha | Self::OpenrouterFree | Self::PrimeIntellectIntellect3 | Self::QwenQwen3235bA22b0725 | Self::QwenQwen3235bA22bThinking2507 | Self::QwenQwen330bA3bInstruct2507 | Self::QwenQwen330bA3bThinking2507 | Self::QwenQwen3Coder | Self::QwenQwen3Coder30bA3bInstruct | Self::QwenQwen3CoderFlash | Self::QwenQwen3CoderExacto | Self::QwenQwen3Max | Self::QwenQwen3Next80bA3bInstruct | Self::QwenQwen3Next80bA3bThinking | Self::QwenQwen35397bA17b | Self::QwenQwen35Flash0223 | Self::QwenQwen35Plus0215 | Self::QwenQwen36Plus | Self::StepfunStep35Flash | Self::XAiGrok3 | Self::XAiGrok3Beta | Self::XAiGrok3Mini | Self::XAiGrok3MiniBeta | Self::XAiGrok4 | Self::XAiGrok4Fast | Self::XAiGrok41Fast | Self::XAiGrok420Beta | Self::XAiGrokCodeFast1 | Self::XiaomiMimoV2Flash | Self::XiaomiMimoV2Pro | Self::ZAiGlm45 | Self::ZAiGlm45Air | Self::ZAiGlm45v | Self::ZAiGlm46 | Self::ZAiGlm46Exacto | Self::ZAiGlm47 | Self::ZAiGlm47Flash | Self::ZAiGlm5 | Self::ZAiGlm5Turbo | Self::ZAiGlm51 => false,
1506 Self::GoogleGemini20Flash001 | Self::GoogleGemini25Flash | Self::GoogleGemini25FlashLite | Self::GoogleGemini25FlashLitePreview092025 | Self::GoogleGemini25FlashPreview092025 | Self::GoogleGemini25Pro | Self::GoogleGemini25ProPreview0506 | Self::GoogleGemini25ProPreview0605 | Self::GoogleGemini3FlashPreview | Self::GoogleGemini3ProPreview | Self::GoogleGemini31FlashLitePreview | Self::GoogleGemini31ProPreview | Self::GoogleGemini31ProPreviewCustomtools | Self::XiaomiMimoV2Omni => true,
1507 }
1508 }
1509
1510 const ALL: &[OpenRouterModel] = &[
1511 Self::AnthropicClaude35Haiku,
1512 Self::AnthropicClaude37Sonnet,
1513 Self::AnthropicClaudeHaiku45,
1514 Self::AnthropicClaudeOpus4,
1515 Self::AnthropicClaudeOpus41,
1516 Self::AnthropicClaudeOpus45,
1517 Self::AnthropicClaudeOpus46,
1518 Self::AnthropicClaudeOpus47,
1519 Self::AnthropicClaudeSonnet4,
1520 Self::AnthropicClaudeSonnet45,
1521 Self::AnthropicClaudeSonnet46,
1522 Self::ArceeAiTrinityLargePreviewFree,
1523 Self::ArceeAiTrinityLargeThinking,
1524 Self::DeepseekDeepseekChatV31,
1525 Self::DeepseekDeepseekR1,
1526 Self::DeepseekDeepseekV31Terminus,
1527 Self::DeepseekDeepseekV31TerminusExacto,
1528 Self::DeepseekDeepseekV32,
1529 Self::DeepseekDeepseekV32Speciale,
1530 Self::GoogleGemini20Flash001,
1531 Self::GoogleGemini25Flash,
1532 Self::GoogleGemini25FlashLite,
1533 Self::GoogleGemini25FlashLitePreview092025,
1534 Self::GoogleGemini25FlashPreview092025,
1535 Self::GoogleGemini25Pro,
1536 Self::GoogleGemini25ProPreview0506,
1537 Self::GoogleGemini25ProPreview0605,
1538 Self::GoogleGemini3FlashPreview,
1539 Self::GoogleGemini3ProPreview,
1540 Self::GoogleGemini31FlashLitePreview,
1541 Self::GoogleGemini31ProPreview,
1542 Self::GoogleGemini31ProPreviewCustomtools,
1543 Self::GoogleGemma327bIt,
1544 Self::GoogleGemma327bItFree,
1545 Self::GoogleGemma426bA4bIt,
1546 Self::GoogleGemma426bA4bItFree,
1547 Self::GoogleGemma431bIt,
1548 Self::GoogleGemma431bItFree,
1549 Self::InceptionMercury2,
1550 Self::MetaLlamaLlama3370bInstructFree,
1551 Self::MinimaxMinimax01,
1552 Self::MinimaxMinimaxM1,
1553 Self::MinimaxMinimaxM2,
1554 Self::MinimaxMinimaxM21,
1555 Self::MinimaxMinimaxM25,
1556 Self::MinimaxMinimaxM25Free,
1557 Self::MinimaxMinimaxM27,
1558 Self::MistralaiCodestral2508,
1559 Self::MistralaiDevstral2512,
1560 Self::MistralaiDevstralMedium2507,
1561 Self::MistralaiDevstralSmall2505,
1562 Self::MistralaiDevstralSmall2507,
1563 Self::MistralaiMistralMedium3,
1564 Self::MistralaiMistralMedium31,
1565 Self::MistralaiMistralSmall2603,
1566 Self::MistralaiMistralSmall3124bInstruct,
1567 Self::MistralaiMistralSmall3224bInstruct,
1568 Self::MoonshotaiKimiK2,
1569 Self::MoonshotaiKimiK20905,
1570 Self::MoonshotaiKimiK20905Exacto,
1571 Self::MoonshotaiKimiK2Thinking,
1572 Self::MoonshotaiKimiK25,
1573 Self::MoonshotaiKimiK26,
1574 Self::NousresearchHermes4405b,
1575 Self::NousresearchHermes470b,
1576 Self::NvidiaNemotron3Nano30bA3bFree,
1577 Self::NvidiaNemotron3Super120bA12b,
1578 Self::NvidiaNemotron3Super120bA12bFree,
1579 Self::NvidiaNemotronNano12bV2VlFree,
1580 Self::NvidiaNemotronNano9bV2,
1581 Self::NvidiaNemotronNano9bV2Free,
1582 Self::OpenaiGpt41,
1583 Self::OpenaiGpt41Mini,
1584 Self::OpenaiGpt4oMini,
1585 Self::OpenaiGpt5,
1586 Self::OpenaiGpt5Codex,
1587 Self::OpenaiGpt5Image,
1588 Self::OpenaiGpt5Mini,
1589 Self::OpenaiGpt5Nano,
1590 Self::OpenaiGpt5Pro,
1591 Self::OpenaiGpt51,
1592 Self::OpenaiGpt51Chat,
1593 Self::OpenaiGpt51Codex,
1594 Self::OpenaiGpt51CodexMax,
1595 Self::OpenaiGpt51CodexMini,
1596 Self::OpenaiGpt52,
1597 Self::OpenaiGpt52Chat,
1598 Self::OpenaiGpt52Codex,
1599 Self::OpenaiGpt52Pro,
1600 Self::OpenaiGpt53Codex,
1601 Self::OpenaiGpt54,
1602 Self::OpenaiGpt54Mini,
1603 Self::OpenaiGpt54Nano,
1604 Self::OpenaiGpt54Pro,
1605 Self::OpenaiGptOss120b,
1606 Self::OpenaiGptOss120bExacto,
1607 Self::OpenaiGptOss120bFree,
1608 Self::OpenaiGptOss20b,
1609 Self::OpenaiGptOss20bFree,
1610 Self::OpenaiGptOssSafeguard20b,
1611 Self::OpenaiO4Mini,
1612 Self::OpenrouterElephantAlpha,
1613 Self::OpenrouterFree,
1614 Self::PrimeIntellectIntellect3,
1615 Self::QwenQwen3235bA22b0725,
1616 Self::QwenQwen3235bA22bThinking2507,
1617 Self::QwenQwen330bA3bInstruct2507,
1618 Self::QwenQwen330bA3bThinking2507,
1619 Self::QwenQwen3Coder,
1620 Self::QwenQwen3Coder30bA3bInstruct,
1621 Self::QwenQwen3CoderFlash,
1622 Self::QwenQwen3CoderExacto,
1623 Self::QwenQwen3Max,
1624 Self::QwenQwen3Next80bA3bInstruct,
1625 Self::QwenQwen3Next80bA3bThinking,
1626 Self::QwenQwen35397bA17b,
1627 Self::QwenQwen35Flash0223,
1628 Self::QwenQwen35Plus0215,
1629 Self::QwenQwen36Plus,
1630 Self::StepfunStep35Flash,
1631 Self::XAiGrok3,
1632 Self::XAiGrok3Beta,
1633 Self::XAiGrok3Mini,
1634 Self::XAiGrok3MiniBeta,
1635 Self::XAiGrok4,
1636 Self::XAiGrok4Fast,
1637 Self::XAiGrok41Fast,
1638 Self::XAiGrok420Beta,
1639 Self::XAiGrokCodeFast1,
1640 Self::XiaomiMimoV2Flash,
1641 Self::XiaomiMimoV2Omni,
1642 Self::XiaomiMimoV2Pro,
1643 Self::ZAiGlm45,
1644 Self::ZAiGlm45Air,
1645 Self::ZAiGlm45v,
1646 Self::ZAiGlm46,
1647 Self::ZAiGlm46Exacto,
1648 Self::ZAiGlm47,
1649 Self::ZAiGlm47Flash,
1650 Self::ZAiGlm5,
1651 Self::ZAiGlm5Turbo,
1652 Self::ZAiGlm51,
1653 ];
1654}
1655
1656impl std::str::FromStr for OpenRouterModel {
1657 type Err = String;
1658
1659 #[allow(clippy::too_many_lines)]
1660 fn from_str(s: &str) -> Result<Self, Self::Err> {
1661 match s {
1662 "anthropic/claude-3.5-haiku" => Ok(Self::AnthropicClaude35Haiku),
1663 "anthropic/claude-3.7-sonnet" => Ok(Self::AnthropicClaude37Sonnet),
1664 "anthropic/claude-haiku-4.5" => Ok(Self::AnthropicClaudeHaiku45),
1665 "anthropic/claude-opus-4" => Ok(Self::AnthropicClaudeOpus4),
1666 "anthropic/claude-opus-4.1" => Ok(Self::AnthropicClaudeOpus41),
1667 "anthropic/claude-opus-4.5" => Ok(Self::AnthropicClaudeOpus45),
1668 "anthropic/claude-opus-4.6" => Ok(Self::AnthropicClaudeOpus46),
1669 "anthropic/claude-opus-4.7" => Ok(Self::AnthropicClaudeOpus47),
1670 "anthropic/claude-sonnet-4" => Ok(Self::AnthropicClaudeSonnet4),
1671 "anthropic/claude-sonnet-4.5" => Ok(Self::AnthropicClaudeSonnet45),
1672 "anthropic/claude-sonnet-4.6" => Ok(Self::AnthropicClaudeSonnet46),
1673 "arcee-ai/trinity-large-preview:free" => Ok(Self::ArceeAiTrinityLargePreviewFree),
1674 "arcee-ai/trinity-large-thinking" => Ok(Self::ArceeAiTrinityLargeThinking),
1675 "deepseek/deepseek-chat-v3.1" => Ok(Self::DeepseekDeepseekChatV31),
1676 "deepseek/deepseek-r1" => Ok(Self::DeepseekDeepseekR1),
1677 "deepseek/deepseek-v3.1-terminus" => Ok(Self::DeepseekDeepseekV31Terminus),
1678 "deepseek/deepseek-v3.1-terminus:exacto" => Ok(Self::DeepseekDeepseekV31TerminusExacto),
1679 "deepseek/deepseek-v3.2" => Ok(Self::DeepseekDeepseekV32),
1680 "deepseek/deepseek-v3.2-speciale" => Ok(Self::DeepseekDeepseekV32Speciale),
1681 "google/gemini-2.0-flash-001" => Ok(Self::GoogleGemini20Flash001),
1682 "google/gemini-2.5-flash" => Ok(Self::GoogleGemini25Flash),
1683 "google/gemini-2.5-flash-lite" => Ok(Self::GoogleGemini25FlashLite),
1684 "google/gemini-2.5-flash-lite-preview-09-2025" => Ok(Self::GoogleGemini25FlashLitePreview092025),
1685 "google/gemini-2.5-flash-preview-09-2025" => Ok(Self::GoogleGemini25FlashPreview092025),
1686 "google/gemini-2.5-pro" => Ok(Self::GoogleGemini25Pro),
1687 "google/gemini-2.5-pro-preview-05-06" => Ok(Self::GoogleGemini25ProPreview0506),
1688 "google/gemini-2.5-pro-preview-06-05" => Ok(Self::GoogleGemini25ProPreview0605),
1689 "google/gemini-3-flash-preview" => Ok(Self::GoogleGemini3FlashPreview),
1690 "google/gemini-3-pro-preview" => Ok(Self::GoogleGemini3ProPreview),
1691 "google/gemini-3.1-flash-lite-preview" => Ok(Self::GoogleGemini31FlashLitePreview),
1692 "google/gemini-3.1-pro-preview" => Ok(Self::GoogleGemini31ProPreview),
1693 "google/gemini-3.1-pro-preview-customtools" => Ok(Self::GoogleGemini31ProPreviewCustomtools),
1694 "google/gemma-3-27b-it" => Ok(Self::GoogleGemma327bIt),
1695 "google/gemma-3-27b-it:free" => Ok(Self::GoogleGemma327bItFree),
1696 "google/gemma-4-26b-a4b-it" => Ok(Self::GoogleGemma426bA4bIt),
1697 "google/gemma-4-26b-a4b-it:free" => Ok(Self::GoogleGemma426bA4bItFree),
1698 "google/gemma-4-31b-it" => Ok(Self::GoogleGemma431bIt),
1699 "google/gemma-4-31b-it:free" => Ok(Self::GoogleGemma431bItFree),
1700 "inception/mercury-2" => Ok(Self::InceptionMercury2),
1701 "meta-llama/llama-3.3-70b-instruct:free" => Ok(Self::MetaLlamaLlama3370bInstructFree),
1702 "minimax/minimax-01" => Ok(Self::MinimaxMinimax01),
1703 "minimax/minimax-m1" => Ok(Self::MinimaxMinimaxM1),
1704 "minimax/minimax-m2" => Ok(Self::MinimaxMinimaxM2),
1705 "minimax/minimax-m2.1" => Ok(Self::MinimaxMinimaxM21),
1706 "minimax/minimax-m2.5" => Ok(Self::MinimaxMinimaxM25),
1707 "minimax/minimax-m2.5:free" => Ok(Self::MinimaxMinimaxM25Free),
1708 "minimax/minimax-m2.7" => Ok(Self::MinimaxMinimaxM27),
1709 "mistralai/codestral-2508" => Ok(Self::MistralaiCodestral2508),
1710 "mistralai/devstral-2512" => Ok(Self::MistralaiDevstral2512),
1711 "mistralai/devstral-medium-2507" => Ok(Self::MistralaiDevstralMedium2507),
1712 "mistralai/devstral-small-2505" => Ok(Self::MistralaiDevstralSmall2505),
1713 "mistralai/devstral-small-2507" => Ok(Self::MistralaiDevstralSmall2507),
1714 "mistralai/mistral-medium-3" => Ok(Self::MistralaiMistralMedium3),
1715 "mistralai/mistral-medium-3.1" => Ok(Self::MistralaiMistralMedium31),
1716 "mistralai/mistral-small-2603" => Ok(Self::MistralaiMistralSmall2603),
1717 "mistralai/mistral-small-3.1-24b-instruct" => Ok(Self::MistralaiMistralSmall3124bInstruct),
1718 "mistralai/mistral-small-3.2-24b-instruct" => Ok(Self::MistralaiMistralSmall3224bInstruct),
1719 "moonshotai/kimi-k2" => Ok(Self::MoonshotaiKimiK2),
1720 "moonshotai/kimi-k2-0905" => Ok(Self::MoonshotaiKimiK20905),
1721 "moonshotai/kimi-k2-0905:exacto" => Ok(Self::MoonshotaiKimiK20905Exacto),
1722 "moonshotai/kimi-k2-thinking" => Ok(Self::MoonshotaiKimiK2Thinking),
1723 "moonshotai/kimi-k2.5" => Ok(Self::MoonshotaiKimiK25),
1724 "moonshotai/kimi-k2.6" => Ok(Self::MoonshotaiKimiK26),
1725 "nousresearch/hermes-4-405b" => Ok(Self::NousresearchHermes4405b),
1726 "nousresearch/hermes-4-70b" => Ok(Self::NousresearchHermes470b),
1727 "nvidia/nemotron-3-nano-30b-a3b:free" => Ok(Self::NvidiaNemotron3Nano30bA3bFree),
1728 "nvidia/nemotron-3-super-120b-a12b" => Ok(Self::NvidiaNemotron3Super120bA12b),
1729 "nvidia/nemotron-3-super-120b-a12b:free" => Ok(Self::NvidiaNemotron3Super120bA12bFree),
1730 "nvidia/nemotron-nano-12b-v2-vl:free" => Ok(Self::NvidiaNemotronNano12bV2VlFree),
1731 "nvidia/nemotron-nano-9b-v2" => Ok(Self::NvidiaNemotronNano9bV2),
1732 "nvidia/nemotron-nano-9b-v2:free" => Ok(Self::NvidiaNemotronNano9bV2Free),
1733 "openai/gpt-4.1" => Ok(Self::OpenaiGpt41),
1734 "openai/gpt-4.1-mini" => Ok(Self::OpenaiGpt41Mini),
1735 "openai/gpt-4o-mini" => Ok(Self::OpenaiGpt4oMini),
1736 "openai/gpt-5" => Ok(Self::OpenaiGpt5),
1737 "openai/gpt-5-codex" => Ok(Self::OpenaiGpt5Codex),
1738 "openai/gpt-5-image" => Ok(Self::OpenaiGpt5Image),
1739 "openai/gpt-5-mini" => Ok(Self::OpenaiGpt5Mini),
1740 "openai/gpt-5-nano" => Ok(Self::OpenaiGpt5Nano),
1741 "openai/gpt-5-pro" => Ok(Self::OpenaiGpt5Pro),
1742 "openai/gpt-5.1" => Ok(Self::OpenaiGpt51),
1743 "openai/gpt-5.1-chat" => Ok(Self::OpenaiGpt51Chat),
1744 "openai/gpt-5.1-codex" => Ok(Self::OpenaiGpt51Codex),
1745 "openai/gpt-5.1-codex-max" => Ok(Self::OpenaiGpt51CodexMax),
1746 "openai/gpt-5.1-codex-mini" => Ok(Self::OpenaiGpt51CodexMini),
1747 "openai/gpt-5.2" => Ok(Self::OpenaiGpt52),
1748 "openai/gpt-5.2-chat" => Ok(Self::OpenaiGpt52Chat),
1749 "openai/gpt-5.2-codex" => Ok(Self::OpenaiGpt52Codex),
1750 "openai/gpt-5.2-pro" => Ok(Self::OpenaiGpt52Pro),
1751 "openai/gpt-5.3-codex" => Ok(Self::OpenaiGpt53Codex),
1752 "openai/gpt-5.4" => Ok(Self::OpenaiGpt54),
1753 "openai/gpt-5.4-mini" => Ok(Self::OpenaiGpt54Mini),
1754 "openai/gpt-5.4-nano" => Ok(Self::OpenaiGpt54Nano),
1755 "openai/gpt-5.4-pro" => Ok(Self::OpenaiGpt54Pro),
1756 "openai/gpt-oss-120b" => Ok(Self::OpenaiGptOss120b),
1757 "openai/gpt-oss-120b:exacto" => Ok(Self::OpenaiGptOss120bExacto),
1758 "openai/gpt-oss-120b:free" => Ok(Self::OpenaiGptOss120bFree),
1759 "openai/gpt-oss-20b" => Ok(Self::OpenaiGptOss20b),
1760 "openai/gpt-oss-20b:free" => Ok(Self::OpenaiGptOss20bFree),
1761 "openai/gpt-oss-safeguard-20b" => Ok(Self::OpenaiGptOssSafeguard20b),
1762 "openai/o4-mini" => Ok(Self::OpenaiO4Mini),
1763 "openrouter/elephant-alpha" => Ok(Self::OpenrouterElephantAlpha),
1764 "openrouter/free" => Ok(Self::OpenrouterFree),
1765 "prime-intellect/intellect-3" => Ok(Self::PrimeIntellectIntellect3),
1766 "qwen/qwen3-235b-a22b-07-25" => Ok(Self::QwenQwen3235bA22b0725),
1767 "qwen/qwen3-235b-a22b-thinking-2507" => Ok(Self::QwenQwen3235bA22bThinking2507),
1768 "qwen/qwen3-30b-a3b-instruct-2507" => Ok(Self::QwenQwen330bA3bInstruct2507),
1769 "qwen/qwen3-30b-a3b-thinking-2507" => Ok(Self::QwenQwen330bA3bThinking2507),
1770 "qwen/qwen3-coder" => Ok(Self::QwenQwen3Coder),
1771 "qwen/qwen3-coder-30b-a3b-instruct" => Ok(Self::QwenQwen3Coder30bA3bInstruct),
1772 "qwen/qwen3-coder-flash" => Ok(Self::QwenQwen3CoderFlash),
1773 "qwen/qwen3-coder:exacto" => Ok(Self::QwenQwen3CoderExacto),
1774 "qwen/qwen3-max" => Ok(Self::QwenQwen3Max),
1775 "qwen/qwen3-next-80b-a3b-instruct" => Ok(Self::QwenQwen3Next80bA3bInstruct),
1776 "qwen/qwen3-next-80b-a3b-thinking" => Ok(Self::QwenQwen3Next80bA3bThinking),
1777 "qwen/qwen3.5-397b-a17b" => Ok(Self::QwenQwen35397bA17b),
1778 "qwen/qwen3.5-flash-02-23" => Ok(Self::QwenQwen35Flash0223),
1779 "qwen/qwen3.5-plus-02-15" => Ok(Self::QwenQwen35Plus0215),
1780 "qwen/qwen3.6-plus" => Ok(Self::QwenQwen36Plus),
1781 "stepfun/step-3.5-flash" => Ok(Self::StepfunStep35Flash),
1782 "x-ai/grok-3" => Ok(Self::XAiGrok3),
1783 "x-ai/grok-3-beta" => Ok(Self::XAiGrok3Beta),
1784 "x-ai/grok-3-mini" => Ok(Self::XAiGrok3Mini),
1785 "x-ai/grok-3-mini-beta" => Ok(Self::XAiGrok3MiniBeta),
1786 "x-ai/grok-4" => Ok(Self::XAiGrok4),
1787 "x-ai/grok-4-fast" => Ok(Self::XAiGrok4Fast),
1788 "x-ai/grok-4.1-fast" => Ok(Self::XAiGrok41Fast),
1789 "x-ai/grok-4.20-beta" => Ok(Self::XAiGrok420Beta),
1790 "x-ai/grok-code-fast-1" => Ok(Self::XAiGrokCodeFast1),
1791 "xiaomi/mimo-v2-flash" => Ok(Self::XiaomiMimoV2Flash),
1792 "xiaomi/mimo-v2-omni" => Ok(Self::XiaomiMimoV2Omni),
1793 "xiaomi/mimo-v2-pro" => Ok(Self::XiaomiMimoV2Pro),
1794 "z-ai/glm-4.5" => Ok(Self::ZAiGlm45),
1795 "z-ai/glm-4.5-air" => Ok(Self::ZAiGlm45Air),
1796 "z-ai/glm-4.5v" => Ok(Self::ZAiGlm45v),
1797 "z-ai/glm-4.6" => Ok(Self::ZAiGlm46),
1798 "z-ai/glm-4.6:exacto" => Ok(Self::ZAiGlm46Exacto),
1799 "z-ai/glm-4.7" => Ok(Self::ZAiGlm47),
1800 "z-ai/glm-4.7-flash" => Ok(Self::ZAiGlm47Flash),
1801 "z-ai/glm-5" => Ok(Self::ZAiGlm5),
1802 "z-ai/glm-5-turbo" => Ok(Self::ZAiGlm5Turbo),
1803 "z-ai/glm-5.1" => Ok(Self::ZAiGlm51),
1804 _ => Err(format!("Unknown openrouter model: '{s}'")),
1805 }
1806 }
1807}
1808
1809impl ZAiModel {
1810 #[allow(clippy::too_many_lines)]
1811 fn model_id(self) -> &'static str {
1812 match self {
1813 Self::Glm45 => "glm-4.5",
1814 Self::Glm45Air => "glm-4.5-air",
1815 Self::Glm45Flash => "glm-4.5-flash",
1816 Self::Glm45v => "glm-4.5v",
1817 Self::Glm46 => "glm-4.6",
1818 Self::Glm46v => "glm-4.6v",
1819 Self::Glm47 => "glm-4.7",
1820 Self::Glm47Flash => "glm-4.7-flash",
1821 Self::Glm47Flashx => "glm-4.7-flashx",
1822 Self::Glm5 => "glm-5",
1823 Self::Glm5Turbo => "glm-5-turbo",
1824 Self::Glm51 => "glm-5.1",
1825 Self::Glm5vTurbo => "glm-5v-turbo",
1826 }
1827 }
1828
1829 #[allow(clippy::too_many_lines)]
1830 fn display_name(self) -> &'static str {
1831 match self {
1832 Self::Glm45 => "GLM-4.5",
1833 Self::Glm45Air => "GLM-4.5-Air",
1834 Self::Glm45Flash => "GLM-4.5-Flash",
1835 Self::Glm45v => "GLM-4.5V",
1836 Self::Glm46 => "GLM-4.6",
1837 Self::Glm46v => "GLM-4.6V",
1838 Self::Glm47 => "GLM-4.7",
1839 Self::Glm47Flash => "GLM-4.7-Flash",
1840 Self::Glm47Flashx => "GLM-4.7-FlashX",
1841 Self::Glm5 => "GLM-5",
1842 Self::Glm5Turbo => "GLM-5-Turbo",
1843 Self::Glm51 => "GLM-5.1",
1844 Self::Glm5vTurbo => "glm-5v-turbo",
1845 }
1846 }
1847
1848 fn context_window(self) -> u32 {
1849 match self {
1850 Self::Glm46v => 128_000,
1851 Self::Glm45 | Self::Glm45Air | Self::Glm45Flash => 131_072,
1852 Self::Glm47Flash | Self::Glm47Flashx | Self::Glm5Turbo | Self::Glm51 | Self::Glm5vTurbo => 200_000,
1853 Self::Glm46 | Self::Glm47 | Self::Glm5 => 204_800,
1854 Self::Glm45v => 64_000,
1855 }
1856 }
1857
1858 pub fn reasoning_levels(self) -> &'static [ReasoningEffort] {
1859 match self {
1860 Self::Glm45 | Self::Glm45Air | Self::Glm45Flash | Self::Glm45v | Self::Glm46 | Self::Glm46v | Self::Glm47 | Self::Glm47Flash | Self::Glm47Flashx | Self::Glm5 | Self::Glm5Turbo | Self::Glm51 | Self::Glm5vTurbo => &[ReasoningEffort::Low, ReasoningEffort::Medium, ReasoningEffort::High],
1861 }
1862 }
1863
1864 pub fn supports_reasoning(self) -> bool {
1865 !self.reasoning_levels().is_empty()
1866 }
1867
1868 pub fn supports_image(self) -> bool {
1869 match self {
1870 Self::Glm45 | Self::Glm45Air | Self::Glm45Flash | Self::Glm46 | Self::Glm47 | Self::Glm47Flash | Self::Glm47Flashx | Self::Glm5 | Self::Glm5Turbo | Self::Glm51 => false,
1871 Self::Glm45v | Self::Glm46v | Self::Glm5vTurbo => true,
1872 }
1873 }
1874
1875 pub fn supports_audio(self) -> bool {
1876 match self {
1877 Self::Glm45 | Self::Glm45Air | Self::Glm45Flash | Self::Glm45v | Self::Glm46 | Self::Glm46v | Self::Glm47 | Self::Glm47Flash | Self::Glm47Flashx | Self::Glm5 | Self::Glm5Turbo | Self::Glm51 | Self::Glm5vTurbo => false,
1878 }
1879 }
1880
1881 const ALL: &[ZAiModel] = &[
1882 Self::Glm45,
1883 Self::Glm45Air,
1884 Self::Glm45Flash,
1885 Self::Glm45v,
1886 Self::Glm46,
1887 Self::Glm46v,
1888 Self::Glm47,
1889 Self::Glm47Flash,
1890 Self::Glm47Flashx,
1891 Self::Glm5,
1892 Self::Glm5Turbo,
1893 Self::Glm51,
1894 Self::Glm5vTurbo,
1895 ];
1896}
1897
1898impl std::str::FromStr for ZAiModel {
1899 type Err = String;
1900
1901 #[allow(clippy::too_many_lines)]
1902 fn from_str(s: &str) -> Result<Self, Self::Err> {
1903 match s {
1904 "glm-4.5" => Ok(Self::Glm45),
1905 "glm-4.5-air" => Ok(Self::Glm45Air),
1906 "glm-4.5-flash" => Ok(Self::Glm45Flash),
1907 "glm-4.5v" => Ok(Self::Glm45v),
1908 "glm-4.6" => Ok(Self::Glm46),
1909 "glm-4.6v" => Ok(Self::Glm46v),
1910 "glm-4.7" => Ok(Self::Glm47),
1911 "glm-4.7-flash" => Ok(Self::Glm47Flash),
1912 "glm-4.7-flashx" => Ok(Self::Glm47Flashx),
1913 "glm-5" => Ok(Self::Glm5),
1914 "glm-5-turbo" => Ok(Self::Glm5Turbo),
1915 "glm-5.1" => Ok(Self::Glm51),
1916 "glm-5v-turbo" => Ok(Self::Glm5vTurbo),
1917 _ => Err(format!("Unknown zai model: '{s}'")),
1918 }
1919 }
1920}
1921
1922impl BedrockModel {
1923 #[allow(clippy::too_many_lines)]
1924 fn model_id(self) -> &'static str {
1925 match self {
1926 Self::AmazonNova2LiteV10 => "amazon.nova-2-lite-v1:0",
1927 Self::AmazonNovaLiteV10 => "amazon.nova-lite-v1:0",
1928 Self::AmazonNovaMicroV10 => "amazon.nova-micro-v1:0",
1929 Self::AmazonNovaPremierV10 => "amazon.nova-premier-v1:0",
1930 Self::AmazonNovaProV10 => "amazon.nova-pro-v1:0",
1931 Self::AnthropicClaude35Haiku20241022V10 => "anthropic.claude-3-5-haiku-20241022-v1:0",
1932 Self::AnthropicClaude35Sonnet20240620V10 => "anthropic.claude-3-5-sonnet-20240620-v1:0",
1933 Self::AnthropicClaude35Sonnet20241022V20 => "anthropic.claude-3-5-sonnet-20241022-v2:0",
1934 Self::AnthropicClaude37Sonnet20250219V10 => "anthropic.claude-3-7-sonnet-20250219-v1:0",
1935 Self::AnthropicClaude3Haiku20240307V10 => "anthropic.claude-3-haiku-20240307-v1:0",
1936 Self::AnthropicClaudeHaiku4520251001V10 => "anthropic.claude-haiku-4-5-20251001-v1:0",
1937 Self::AnthropicClaudeOpus4120250805V10 => "anthropic.claude-opus-4-1-20250805-v1:0",
1938 Self::AnthropicClaudeOpus420250514V10 => "anthropic.claude-opus-4-20250514-v1:0",
1939 Self::AnthropicClaudeOpus4520251101V10 => "anthropic.claude-opus-4-5-20251101-v1:0",
1940 Self::AnthropicClaudeOpus46V1 => "anthropic.claude-opus-4-6-v1",
1941 Self::AnthropicClaudeOpus47 => "anthropic.claude-opus-4-7",
1942 Self::AnthropicClaudeSonnet420250514V10 => "anthropic.claude-sonnet-4-20250514-v1:0",
1943 Self::AnthropicClaudeSonnet4520250929V10 => "anthropic.claude-sonnet-4-5-20250929-v1:0",
1944 Self::AnthropicClaudeSonnet46 => "anthropic.claude-sonnet-4-6",
1945 Self::DeepseekR1V10 => "deepseek.r1-v1:0",
1946 Self::DeepseekV3V10 => "deepseek.v3-v1:0",
1947 Self::DeepseekV32 => "deepseek.v3.2",
1948 Self::EuAnthropicClaudeHaiku4520251001V10 => "eu.anthropic.claude-haiku-4-5-20251001-v1:0",
1949 Self::EuAnthropicClaudeOpus4520251101V10 => "eu.anthropic.claude-opus-4-5-20251101-v1:0",
1950 Self::EuAnthropicClaudeOpus46V1 => "eu.anthropic.claude-opus-4-6-v1",
1951 Self::EuAnthropicClaudeOpus47 => "eu.anthropic.claude-opus-4-7",
1952 Self::EuAnthropicClaudeSonnet420250514V10 => "eu.anthropic.claude-sonnet-4-20250514-v1:0",
1953 Self::EuAnthropicClaudeSonnet4520250929V10 => "eu.anthropic.claude-sonnet-4-5-20250929-v1:0",
1954 Self::EuAnthropicClaudeSonnet46 => "eu.anthropic.claude-sonnet-4-6",
1955 Self::GlobalAnthropicClaudeHaiku4520251001V10 => "global.anthropic.claude-haiku-4-5-20251001-v1:0",
1956 Self::GlobalAnthropicClaudeOpus4520251101V10 => "global.anthropic.claude-opus-4-5-20251101-v1:0",
1957 Self::GlobalAnthropicClaudeOpus46V1 => "global.anthropic.claude-opus-4-6-v1",
1958 Self::GlobalAnthropicClaudeOpus47 => "global.anthropic.claude-opus-4-7",
1959 Self::GlobalAnthropicClaudeSonnet420250514V10 => "global.anthropic.claude-sonnet-4-20250514-v1:0",
1960 Self::GlobalAnthropicClaudeSonnet4520250929V10 => "global.anthropic.claude-sonnet-4-5-20250929-v1:0",
1961 Self::GlobalAnthropicClaudeSonnet46 => "global.anthropic.claude-sonnet-4-6",
1962 Self::GoogleGemma327bIt => "google.gemma-3-27b-it",
1963 Self::GoogleGemma34bIt => "google.gemma-3-4b-it",
1964 Self::MetaLlama31405bInstructV10 => "meta.llama3-1-405b-instruct-v1:0",
1965 Self::MetaLlama3170bInstructV10 => "meta.llama3-1-70b-instruct-v1:0",
1966 Self::MetaLlama318bInstructV10 => "meta.llama3-1-8b-instruct-v1:0",
1967 Self::MetaLlama3211bInstructV10 => "meta.llama3-2-11b-instruct-v1:0",
1968 Self::MetaLlama321bInstructV10 => "meta.llama3-2-1b-instruct-v1:0",
1969 Self::MetaLlama323bInstructV10 => "meta.llama3-2-3b-instruct-v1:0",
1970 Self::MetaLlama3290bInstructV10 => "meta.llama3-2-90b-instruct-v1:0",
1971 Self::MetaLlama3370bInstructV10 => "meta.llama3-3-70b-instruct-v1:0",
1972 Self::MetaLlama4Maverick17bInstructV10 => "meta.llama4-maverick-17b-instruct-v1:0",
1973 Self::MetaLlama4Scout17bInstructV10 => "meta.llama4-scout-17b-instruct-v1:0",
1974 Self::MinimaxMinimaxM2 => "minimax.minimax-m2",
1975 Self::MinimaxMinimaxM21 => "minimax.minimax-m2.1",
1976 Self::MinimaxMinimaxM25 => "minimax.minimax-m2.5",
1977 Self::MistralDevstral2123b => "mistral.devstral-2-123b",
1978 Self::MistralMagistralSmall2509 => "mistral.magistral-small-2509",
1979 Self::MistralMinistral314bInstruct => "mistral.ministral-3-14b-instruct",
1980 Self::MistralMinistral33bInstruct => "mistral.ministral-3-3b-instruct",
1981 Self::MistralMinistral38bInstruct => "mistral.ministral-3-8b-instruct",
1982 Self::MistralMistralLarge3675bInstruct => "mistral.mistral-large-3-675b-instruct",
1983 Self::MistralPixtralLarge2502V10 => "mistral.pixtral-large-2502-v1:0",
1984 Self::MistralVoxtralMini3b2507 => "mistral.voxtral-mini-3b-2507",
1985 Self::MistralVoxtralSmall24b2507 => "mistral.voxtral-small-24b-2507",
1986 Self::MoonshotKimiK2Thinking => "moonshot.kimi-k2-thinking",
1987 Self::MoonshotaiKimiK25 => "moonshotai.kimi-k2.5",
1988 Self::NvidiaNemotronNano12bV2 => "nvidia.nemotron-nano-12b-v2",
1989 Self::NvidiaNemotronNano330b => "nvidia.nemotron-nano-3-30b",
1990 Self::NvidiaNemotronNano9bV2 => "nvidia.nemotron-nano-9b-v2",
1991 Self::NvidiaNemotronSuper3120b => "nvidia.nemotron-super-3-120b",
1992 Self::OpenaiGptOss120b10 => "openai.gpt-oss-120b-1:0",
1993 Self::OpenaiGptOss20b10 => "openai.gpt-oss-20b-1:0",
1994 Self::OpenaiGptOssSafeguard120b => "openai.gpt-oss-safeguard-120b",
1995 Self::OpenaiGptOssSafeguard20b => "openai.gpt-oss-safeguard-20b",
1996 Self::QwenQwen3235bA22b2507V10 => "qwen.qwen3-235b-a22b-2507-v1:0",
1997 Self::QwenQwen332bV10 => "qwen.qwen3-32b-v1:0",
1998 Self::QwenQwen3Coder30bA3bV10 => "qwen.qwen3-coder-30b-a3b-v1:0",
1999 Self::QwenQwen3Coder480bA35bV10 => "qwen.qwen3-coder-480b-a35b-v1:0",
2000 Self::QwenQwen3CoderNext => "qwen.qwen3-coder-next",
2001 Self::QwenQwen3Next80bA3b => "qwen.qwen3-next-80b-a3b",
2002 Self::QwenQwen3Vl235bA22b => "qwen.qwen3-vl-235b-a22b",
2003 Self::UsAnthropicClaudeHaiku4520251001V10 => "us.anthropic.claude-haiku-4-5-20251001-v1:0",
2004 Self::UsAnthropicClaudeOpus4120250805V10 => "us.anthropic.claude-opus-4-1-20250805-v1:0",
2005 Self::UsAnthropicClaudeOpus420250514V10 => "us.anthropic.claude-opus-4-20250514-v1:0",
2006 Self::UsAnthropicClaudeOpus4520251101V10 => "us.anthropic.claude-opus-4-5-20251101-v1:0",
2007 Self::UsAnthropicClaudeOpus46V1 => "us.anthropic.claude-opus-4-6-v1",
2008 Self::UsAnthropicClaudeOpus47 => "us.anthropic.claude-opus-4-7",
2009 Self::UsAnthropicClaudeSonnet420250514V10 => "us.anthropic.claude-sonnet-4-20250514-v1:0",
2010 Self::UsAnthropicClaudeSonnet4520250929V10 => "us.anthropic.claude-sonnet-4-5-20250929-v1:0",
2011 Self::UsAnthropicClaudeSonnet46 => "us.anthropic.claude-sonnet-4-6",
2012 Self::WriterPalmyraX4V10 => "writer.palmyra-x4-v1:0",
2013 Self::WriterPalmyraX5V10 => "writer.palmyra-x5-v1:0",
2014 Self::ZaiGlm47 => "zai.glm-4.7",
2015 Self::ZaiGlm47Flash => "zai.glm-4.7-flash",
2016 Self::ZaiGlm5 => "zai.glm-5",
2017 }
2018 }
2019
2020 #[allow(clippy::too_many_lines)]
2021 fn display_name(self) -> &'static str {
2022 match self {
2023 Self::AnthropicClaude3Haiku20240307V10 => "Claude Haiku 3",
2024 Self::AnthropicClaude35Haiku20241022V10 => "Claude Haiku 3.5",
2025 Self::AnthropicClaudeHaiku4520251001V10 => "Claude Haiku 4.5",
2026 Self::EuAnthropicClaudeHaiku4520251001V10 => "Claude Haiku 4.5 (EU)",
2027 Self::GlobalAnthropicClaudeHaiku4520251001V10 => "Claude Haiku 4.5 (Global)",
2028 Self::UsAnthropicClaudeHaiku4520251001V10 => "Claude Haiku 4.5 (US)",
2029 Self::AnthropicClaudeOpus420250514V10 => "Claude Opus 4",
2030 Self::UsAnthropicClaudeOpus420250514V10 => "Claude Opus 4 (US)",
2031 Self::AnthropicClaudeOpus4120250805V10 => "Claude Opus 4.1",
2032 Self::UsAnthropicClaudeOpus4120250805V10 => "Claude Opus 4.1 (US)",
2033 Self::AnthropicClaudeOpus4520251101V10 => "Claude Opus 4.5",
2034 Self::EuAnthropicClaudeOpus4520251101V10 => "Claude Opus 4.5 (EU)",
2035 Self::GlobalAnthropicClaudeOpus4520251101V10 => "Claude Opus 4.5 (Global)",
2036 Self::UsAnthropicClaudeOpus4520251101V10 => "Claude Opus 4.5 (US)",
2037 Self::AnthropicClaudeOpus46V1 => "Claude Opus 4.6",
2038 Self::EuAnthropicClaudeOpus46V1 => "Claude Opus 4.6 (EU)",
2039 Self::GlobalAnthropicClaudeOpus46V1 => "Claude Opus 4.6 (Global)",
2040 Self::UsAnthropicClaudeOpus46V1 => "Claude Opus 4.6 (US)",
2041 Self::AnthropicClaudeOpus47 => "Claude Opus 4.7",
2042 Self::EuAnthropicClaudeOpus47 => "Claude Opus 4.7 (EU)",
2043 Self::GlobalAnthropicClaudeOpus47 => "Claude Opus 4.7 (Global)",
2044 Self::UsAnthropicClaudeOpus47 => "Claude Opus 4.7 (US)",
2045 Self::AnthropicClaude35Sonnet20240620V10 => "Claude Sonnet 3.5",
2046 Self::AnthropicClaude35Sonnet20241022V20 => "Claude Sonnet 3.5 v2",
2047 Self::AnthropicClaude37Sonnet20250219V10 => "Claude Sonnet 3.7",
2048 Self::AnthropicClaudeSonnet420250514V10 => "Claude Sonnet 4",
2049 Self::EuAnthropicClaudeSonnet420250514V10 => "Claude Sonnet 4 (EU)",
2050 Self::GlobalAnthropicClaudeSonnet420250514V10 => "Claude Sonnet 4 (Global)",
2051 Self::UsAnthropicClaudeSonnet420250514V10 => "Claude Sonnet 4 (US)",
2052 Self::AnthropicClaudeSonnet4520250929V10 => "Claude Sonnet 4.5",
2053 Self::EuAnthropicClaudeSonnet4520250929V10 => "Claude Sonnet 4.5 (EU)",
2054 Self::GlobalAnthropicClaudeSonnet4520250929V10 => "Claude Sonnet 4.5 (Global)",
2055 Self::UsAnthropicClaudeSonnet4520250929V10 => "Claude Sonnet 4.5 (US)",
2056 Self::AnthropicClaudeSonnet46 => "Claude Sonnet 4.6",
2057 Self::EuAnthropicClaudeSonnet46 => "Claude Sonnet 4.6 (EU)",
2058 Self::GlobalAnthropicClaudeSonnet46 => "Claude Sonnet 4.6 (Global)",
2059 Self::UsAnthropicClaudeSonnet46 => "Claude Sonnet 4.6 (US)",
2060 Self::DeepseekR1V10 => "DeepSeek-R1",
2061 Self::DeepseekV3V10 => "DeepSeek-V3.1",
2062 Self::DeepseekV32 => "DeepSeek-V3.2",
2063 Self::MistralDevstral2123b => "Devstral 2 123B",
2064 Self::ZaiGlm47 => "GLM-4.7",
2065 Self::ZaiGlm47Flash => "GLM-4.7-Flash",
2066 Self::ZaiGlm5 => "GLM-5",
2067 Self::OpenaiGptOssSafeguard120b => "GPT OSS Safeguard 120B",
2068 Self::OpenaiGptOssSafeguard20b => "GPT OSS Safeguard 20B",
2069 Self::GoogleGemma34bIt => "Gemma 3 4B IT",
2070 Self::GoogleGemma327bIt => "Google Gemma 3 27B Instruct",
2071 Self::MoonshotKimiK2Thinking => "Kimi K2 Thinking",
2072 Self::MoonshotaiKimiK25 => "Kimi K2.5",
2073 Self::MetaLlama31405bInstructV10 => "Llama 3.1 405B Instruct",
2074 Self::MetaLlama3170bInstructV10 => "Llama 3.1 70B Instruct",
2075 Self::MetaLlama318bInstructV10 => "Llama 3.1 8B Instruct",
2076 Self::MetaLlama3211bInstructV10 => "Llama 3.2 11B Instruct",
2077 Self::MetaLlama321bInstructV10 => "Llama 3.2 1B Instruct",
2078 Self::MetaLlama323bInstructV10 => "Llama 3.2 3B Instruct",
2079 Self::MetaLlama3290bInstructV10 => "Llama 3.2 90B Instruct",
2080 Self::MetaLlama3370bInstructV10 => "Llama 3.3 70B Instruct",
2081 Self::MetaLlama4Maverick17bInstructV10 => "Llama 4 Maverick 17B Instruct",
2082 Self::MetaLlama4Scout17bInstructV10 => "Llama 4 Scout 17B Instruct",
2083 Self::MistralMagistralSmall2509 => "Magistral Small 1.2",
2084 Self::MinimaxMinimaxM2 => "MiniMax M2",
2085 Self::MinimaxMinimaxM21 => "MiniMax M2.1",
2086 Self::MinimaxMinimaxM25 => "MiniMax M2.5",
2087 Self::MistralMinistral314bInstruct => "Ministral 14B 3.0",
2088 Self::MistralMinistral33bInstruct => "Ministral 3 3B",
2089 Self::MistralMinistral38bInstruct => "Ministral 3 8B",
2090 Self::MistralMistralLarge3675bInstruct => "Mistral Large 3",
2091 Self::NvidiaNemotronSuper3120b => "NVIDIA Nemotron 3 Super 120B A12B",
2092 Self::NvidiaNemotronNano12bV2 => "NVIDIA Nemotron Nano 12B v2 VL BF16",
2093 Self::NvidiaNemotronNano330b => "NVIDIA Nemotron Nano 3 30B",
2094 Self::NvidiaNemotronNano9bV2 => "NVIDIA Nemotron Nano 9B v2",
2095 Self::AmazonNova2LiteV10 => "Nova 2 Lite",
2096 Self::AmazonNovaLiteV10 => "Nova Lite",
2097 Self::AmazonNovaMicroV10 => "Nova Micro",
2098 Self::AmazonNovaPremierV10 => "Nova Premier",
2099 Self::AmazonNovaProV10 => "Nova Pro",
2100 Self::WriterPalmyraX4V10 => "Palmyra X4",
2101 Self::WriterPalmyraX5V10 => "Palmyra X5",
2102 Self::MistralPixtralLarge2502V10 => "Pixtral Large (25.02)",
2103 Self::QwenQwen3Next80bA3b => "Qwen/Qwen3-Next-80B-A3B-Instruct",
2104 Self::QwenQwen3Vl235bA22b => "Qwen/Qwen3-VL-235B-A22B-Instruct",
2105 Self::QwenQwen3235bA22b2507V10 => "Qwen3 235B A22B 2507",
2106 Self::QwenQwen332bV10 => "Qwen3 32B (dense)",
2107 Self::QwenQwen3Coder30bA3bV10 => "Qwen3 Coder 30B A3B Instruct",
2108 Self::QwenQwen3Coder480bA35bV10 => "Qwen3 Coder 480B A35B Instruct",
2109 Self::QwenQwen3CoderNext => "Qwen3 Coder Next",
2110 Self::MistralVoxtralMini3b2507 => "Voxtral Mini 3B 2507",
2111 Self::MistralVoxtralSmall24b2507 => "Voxtral Small 24B 2507",
2112 Self::OpenaiGptOss120b10 => "gpt-oss-120b",
2113 Self::OpenaiGptOss20b10 => "gpt-oss-20b",
2114 }
2115 }
2116
2117 fn context_window(self) -> u32 {
2118 match self {
2119 Self::AmazonNovaPremierV10 | Self::AnthropicClaudeOpus46V1 | Self::AnthropicClaudeOpus47 | Self::AnthropicClaudeSonnet46 | Self::EuAnthropicClaudeOpus46V1 | Self::EuAnthropicClaudeOpus47 | Self::EuAnthropicClaudeSonnet46 | Self::GlobalAnthropicClaudeOpus46V1 | Self::GlobalAnthropicClaudeOpus47 | Self::GlobalAnthropicClaudeSonnet46 | Self::MetaLlama4Maverick17bInstructV10 | Self::UsAnthropicClaudeOpus46V1 | Self::UsAnthropicClaudeOpus47 | Self::UsAnthropicClaudeSonnet46 => 1_000_000,
2120 Self::WriterPalmyraX5V10 => 1_040_000,
2121 Self::WriterPalmyraX4V10 => 122_880,
2122 Self::AmazonNova2LiteV10 | Self::AmazonNovaMicroV10 | Self::DeepseekR1V10 | Self::GoogleGemma34bIt | Self::MetaLlama31405bInstructV10 | Self::MetaLlama3170bInstructV10 | Self::MetaLlama318bInstructV10 | Self::MetaLlama3211bInstructV10 | Self::MetaLlama3290bInstructV10 | Self::MetaLlama3370bInstructV10 | Self::MistralMagistralSmall2509 | Self::MistralMinistral314bInstruct | Self::MistralMinistral38bInstruct | Self::MistralPixtralLarge2502V10 | Self::MistralVoxtralMini3b2507 | Self::NvidiaNemotronNano12bV2 | Self::NvidiaNemotronNano330b | Self::NvidiaNemotronNano9bV2 | Self::OpenaiGptOss120b10 | Self::OpenaiGptOss20b10 | Self::OpenaiGptOssSafeguard120b | Self::OpenaiGptOssSafeguard20b => 128_000,
2123 Self::MetaLlama321bInstructV10 | Self::MetaLlama323bInstructV10 => 131_000,
2124 Self::QwenQwen3Coder480bA35bV10 | Self::QwenQwen3CoderNext => 131_072,
2125 Self::QwenQwen332bV10 => 16_384,
2126 Self::DeepseekV3V10 | Self::DeepseekV32 => 163_840,
2127 Self::MinimaxMinimaxM25 => 196_608,
2128 Self::AnthropicClaude35Haiku20241022V10 | Self::AnthropicClaude35Sonnet20240620V10 | Self::AnthropicClaude35Sonnet20241022V20 | Self::AnthropicClaude37Sonnet20250219V10 | Self::AnthropicClaude3Haiku20240307V10 | Self::AnthropicClaudeHaiku4520251001V10 | Self::AnthropicClaudeOpus4120250805V10 | Self::AnthropicClaudeOpus420250514V10 | Self::AnthropicClaudeOpus4520251101V10 | Self::AnthropicClaudeSonnet420250514V10 | Self::AnthropicClaudeSonnet4520250929V10 | Self::EuAnthropicClaudeHaiku4520251001V10 | Self::EuAnthropicClaudeOpus4520251101V10 | Self::EuAnthropicClaudeSonnet420250514V10 | Self::EuAnthropicClaudeSonnet4520250929V10 | Self::GlobalAnthropicClaudeHaiku4520251001V10 | Self::GlobalAnthropicClaudeOpus4520251101V10 | Self::GlobalAnthropicClaudeSonnet420250514V10 | Self::GlobalAnthropicClaudeSonnet4520250929V10 | Self::UsAnthropicClaudeHaiku4520251001V10 | Self::UsAnthropicClaudeOpus4120250805V10 | Self::UsAnthropicClaudeOpus420250514V10 | Self::UsAnthropicClaudeOpus4520251101V10 | Self::UsAnthropicClaudeSonnet420250514V10 | Self::UsAnthropicClaudeSonnet4520250929V10 | Self::ZaiGlm47Flash => 200_000,
2129 Self::GoogleGemma327bIt | Self::ZaiGlm5 => 202_752,
2130 Self::MinimaxMinimaxM2 => 204_608,
2131 Self::MinimaxMinimaxM21 | Self::ZaiGlm47 => 204_800,
2132 Self::MistralDevstral2123b | Self::MistralMinistral33bInstruct | Self::MistralMistralLarge3675bInstruct | Self::MoonshotKimiK2Thinking | Self::MoonshotaiKimiK25 => 256_000,
2133 Self::QwenQwen3Next80bA3b | Self::QwenQwen3Vl235bA22b => 262_000,
2134 Self::NvidiaNemotronSuper3120b | Self::QwenQwen3235bA22b2507V10 | Self::QwenQwen3Coder30bA3bV10 => 262_144,
2135 Self::AmazonNovaLiteV10 | Self::AmazonNovaProV10 => 300_000,
2136 Self::MistralVoxtralSmall24b2507 => 32_000,
2137 Self::MetaLlama4Scout17bInstructV10 => 3_500_000,
2138 }
2139 }
2140
2141 pub fn reasoning_levels(self) -> &'static [ReasoningEffort] {
2142 match self {
2143 Self::AmazonNova2LiteV10 | Self::AmazonNovaLiteV10 | Self::AmazonNovaMicroV10 | Self::AmazonNovaProV10 | Self::AnthropicClaude35Haiku20241022V10 | Self::AnthropicClaude35Sonnet20240620V10 | Self::AnthropicClaude35Sonnet20241022V20 | Self::AnthropicClaude37Sonnet20250219V10 | Self::AnthropicClaude3Haiku20240307V10 | Self::GoogleGemma327bIt | Self::GoogleGemma34bIt | Self::MetaLlama31405bInstructV10 | Self::MetaLlama3170bInstructV10 | Self::MetaLlama318bInstructV10 | Self::MetaLlama3211bInstructV10 | Self::MetaLlama321bInstructV10 | Self::MetaLlama323bInstructV10 | Self::MetaLlama3290bInstructV10 | Self::MetaLlama3370bInstructV10 | Self::MetaLlama4Maverick17bInstructV10 | Self::MetaLlama4Scout17bInstructV10 | Self::MistralDevstral2123b | Self::MistralMinistral314bInstruct | Self::MistralMinistral33bInstruct | Self::MistralMinistral38bInstruct | Self::MistralMistralLarge3675bInstruct | Self::MistralPixtralLarge2502V10 | Self::MistralVoxtralMini3b2507 | Self::MistralVoxtralSmall24b2507 | Self::NvidiaNemotronNano12bV2 | Self::NvidiaNemotronNano9bV2 | Self::OpenaiGptOss120b10 | Self::OpenaiGptOss20b10 | Self::OpenaiGptOssSafeguard120b | Self::OpenaiGptOssSafeguard20b | Self::QwenQwen3235bA22b2507V10 | Self::QwenQwen3Coder30bA3bV10 | Self::QwenQwen3Coder480bA35bV10 | Self::QwenQwen3Next80bA3b | Self::QwenQwen3Vl235bA22b => &[],
2144 Self::AmazonNovaPremierV10 | Self::AnthropicClaudeHaiku4520251001V10 | Self::AnthropicClaudeOpus4120250805V10 | Self::AnthropicClaudeOpus420250514V10 | Self::AnthropicClaudeOpus4520251101V10 | Self::AnthropicClaudeOpus46V1 | Self::AnthropicClaudeOpus47 | Self::AnthropicClaudeSonnet420250514V10 | Self::AnthropicClaudeSonnet4520250929V10 | Self::AnthropicClaudeSonnet46 | Self::DeepseekR1V10 | Self::DeepseekV3V10 | Self::DeepseekV32 | Self::EuAnthropicClaudeHaiku4520251001V10 | Self::EuAnthropicClaudeOpus4520251101V10 | Self::EuAnthropicClaudeOpus46V1 | Self::EuAnthropicClaudeOpus47 | Self::EuAnthropicClaudeSonnet420250514V10 | Self::EuAnthropicClaudeSonnet4520250929V10 | Self::EuAnthropicClaudeSonnet46 | Self::GlobalAnthropicClaudeHaiku4520251001V10 | Self::GlobalAnthropicClaudeOpus4520251101V10 | Self::GlobalAnthropicClaudeOpus46V1 | Self::GlobalAnthropicClaudeOpus47 | Self::GlobalAnthropicClaudeSonnet420250514V10 | Self::GlobalAnthropicClaudeSonnet4520250929V10 | Self::GlobalAnthropicClaudeSonnet46 | Self::MinimaxMinimaxM2 | Self::MinimaxMinimaxM21 | Self::MinimaxMinimaxM25 | Self::MistralMagistralSmall2509 | Self::MoonshotKimiK2Thinking | Self::MoonshotaiKimiK25 | Self::NvidiaNemotronNano330b | Self::NvidiaNemotronSuper3120b | Self::QwenQwen332bV10 | Self::QwenQwen3CoderNext | Self::UsAnthropicClaudeHaiku4520251001V10 | Self::UsAnthropicClaudeOpus4120250805V10 | Self::UsAnthropicClaudeOpus420250514V10 | Self::UsAnthropicClaudeOpus4520251101V10 | Self::UsAnthropicClaudeOpus46V1 | Self::UsAnthropicClaudeOpus47 | Self::UsAnthropicClaudeSonnet420250514V10 | Self::UsAnthropicClaudeSonnet4520250929V10 | Self::UsAnthropicClaudeSonnet46 | Self::WriterPalmyraX4V10 | Self::WriterPalmyraX5V10 | Self::ZaiGlm47 | Self::ZaiGlm47Flash | Self::ZaiGlm5 => &[ReasoningEffort::Low, ReasoningEffort::Medium, ReasoningEffort::High],
2145 }
2146 }
2147
2148 pub fn supports_reasoning(self) -> bool {
2149 !self.reasoning_levels().is_empty()
2150 }
2151
2152 pub fn supports_image(self) -> bool {
2153 match self {
2154 Self::AmazonNovaMicroV10 | Self::DeepseekR1V10 | Self::DeepseekV3V10 | Self::DeepseekV32 | Self::MetaLlama31405bInstructV10 | Self::MetaLlama3170bInstructV10 | Self::MetaLlama318bInstructV10 | Self::MetaLlama321bInstructV10 | Self::MetaLlama323bInstructV10 | Self::MetaLlama3370bInstructV10 | Self::MinimaxMinimaxM2 | Self::MinimaxMinimaxM21 | Self::MinimaxMinimaxM25 | Self::MistralDevstral2123b | Self::MistralMinistral314bInstruct | Self::MistralMinistral38bInstruct | Self::MistralVoxtralMini3b2507 | Self::MistralVoxtralSmall24b2507 | Self::MoonshotKimiK2Thinking | Self::NvidiaNemotronNano330b | Self::NvidiaNemotronNano9bV2 | Self::NvidiaNemotronSuper3120b | Self::OpenaiGptOss120b10 | Self::OpenaiGptOss20b10 | Self::OpenaiGptOssSafeguard120b | Self::OpenaiGptOssSafeguard20b | Self::QwenQwen3235bA22b2507V10 | Self::QwenQwen332bV10 | Self::QwenQwen3Coder30bA3bV10 | Self::QwenQwen3Coder480bA35bV10 | Self::QwenQwen3CoderNext | Self::QwenQwen3Next80bA3b | Self::WriterPalmyraX4V10 | Self::WriterPalmyraX5V10 | Self::ZaiGlm47 | Self::ZaiGlm47Flash | Self::ZaiGlm5 => false,
2155 Self::AmazonNova2LiteV10 | Self::AmazonNovaLiteV10 | Self::AmazonNovaPremierV10 | Self::AmazonNovaProV10 | Self::AnthropicClaude35Haiku20241022V10 | Self::AnthropicClaude35Sonnet20240620V10 | Self::AnthropicClaude35Sonnet20241022V20 | Self::AnthropicClaude37Sonnet20250219V10 | Self::AnthropicClaude3Haiku20240307V10 | Self::AnthropicClaudeHaiku4520251001V10 | Self::AnthropicClaudeOpus4120250805V10 | Self::AnthropicClaudeOpus420250514V10 | Self::AnthropicClaudeOpus4520251101V10 | Self::AnthropicClaudeOpus46V1 | Self::AnthropicClaudeOpus47 | Self::AnthropicClaudeSonnet420250514V10 | Self::AnthropicClaudeSonnet4520250929V10 | Self::AnthropicClaudeSonnet46 | Self::EuAnthropicClaudeHaiku4520251001V10 | Self::EuAnthropicClaudeOpus4520251101V10 | Self::EuAnthropicClaudeOpus46V1 | Self::EuAnthropicClaudeOpus47 | Self::EuAnthropicClaudeSonnet420250514V10 | Self::EuAnthropicClaudeSonnet4520250929V10 | Self::EuAnthropicClaudeSonnet46 | Self::GlobalAnthropicClaudeHaiku4520251001V10 | Self::GlobalAnthropicClaudeOpus4520251101V10 | Self::GlobalAnthropicClaudeOpus46V1 | Self::GlobalAnthropicClaudeOpus47 | Self::GlobalAnthropicClaudeSonnet420250514V10 | Self::GlobalAnthropicClaudeSonnet4520250929V10 | Self::GlobalAnthropicClaudeSonnet46 | Self::GoogleGemma327bIt | Self::GoogleGemma34bIt | Self::MetaLlama3211bInstructV10 | Self::MetaLlama3290bInstructV10 | Self::MetaLlama4Maverick17bInstructV10 | Self::MetaLlama4Scout17bInstructV10 | Self::MistralMagistralSmall2509 | Self::MistralMinistral33bInstruct | Self::MistralMistralLarge3675bInstruct | Self::MistralPixtralLarge2502V10 | Self::MoonshotaiKimiK25 | Self::NvidiaNemotronNano12bV2 | Self::QwenQwen3Vl235bA22b | Self::UsAnthropicClaudeHaiku4520251001V10 | Self::UsAnthropicClaudeOpus4120250805V10 | Self::UsAnthropicClaudeOpus420250514V10 | Self::UsAnthropicClaudeOpus4520251101V10 | Self::UsAnthropicClaudeOpus46V1 | Self::UsAnthropicClaudeOpus47 | Self::UsAnthropicClaudeSonnet420250514V10 | Self::UsAnthropicClaudeSonnet4520250929V10 | Self::UsAnthropicClaudeSonnet46 => true,
2156 }
2157 }
2158
2159 pub fn supports_audio(self) -> bool {
2160 match self {
2161 Self::AmazonNova2LiteV10 | Self::AmazonNovaLiteV10 | Self::AmazonNovaMicroV10 | Self::AmazonNovaPremierV10 | Self::AmazonNovaProV10 | Self::AnthropicClaude35Haiku20241022V10 | Self::AnthropicClaude35Sonnet20240620V10 | Self::AnthropicClaude35Sonnet20241022V20 | Self::AnthropicClaude37Sonnet20250219V10 | Self::AnthropicClaude3Haiku20240307V10 | Self::AnthropicClaudeHaiku4520251001V10 | Self::AnthropicClaudeOpus4120250805V10 | Self::AnthropicClaudeOpus420250514V10 | Self::AnthropicClaudeOpus4520251101V10 | Self::AnthropicClaudeOpus46V1 | Self::AnthropicClaudeOpus47 | Self::AnthropicClaudeSonnet420250514V10 | Self::AnthropicClaudeSonnet4520250929V10 | Self::AnthropicClaudeSonnet46 | Self::DeepseekR1V10 | Self::DeepseekV3V10 | Self::DeepseekV32 | Self::EuAnthropicClaudeHaiku4520251001V10 | Self::EuAnthropicClaudeOpus4520251101V10 | Self::EuAnthropicClaudeOpus46V1 | Self::EuAnthropicClaudeOpus47 | Self::EuAnthropicClaudeSonnet420250514V10 | Self::EuAnthropicClaudeSonnet4520250929V10 | Self::EuAnthropicClaudeSonnet46 | Self::GlobalAnthropicClaudeHaiku4520251001V10 | Self::GlobalAnthropicClaudeOpus4520251101V10 | Self::GlobalAnthropicClaudeOpus46V1 | Self::GlobalAnthropicClaudeOpus47 | Self::GlobalAnthropicClaudeSonnet420250514V10 | Self::GlobalAnthropicClaudeSonnet4520250929V10 | Self::GlobalAnthropicClaudeSonnet46 | Self::GoogleGemma327bIt | Self::GoogleGemma34bIt | Self::MetaLlama31405bInstructV10 | Self::MetaLlama3170bInstructV10 | Self::MetaLlama318bInstructV10 | Self::MetaLlama3211bInstructV10 | Self::MetaLlama321bInstructV10 | Self::MetaLlama323bInstructV10 | Self::MetaLlama3290bInstructV10 | Self::MetaLlama3370bInstructV10 | Self::MetaLlama4Maverick17bInstructV10 | Self::MetaLlama4Scout17bInstructV10 | Self::MinimaxMinimaxM2 | Self::MinimaxMinimaxM21 | Self::MinimaxMinimaxM25 | Self::MistralDevstral2123b | Self::MistralMagistralSmall2509 | Self::MistralMinistral314bInstruct | Self::MistralMinistral33bInstruct | Self::MistralMinistral38bInstruct | Self::MistralMistralLarge3675bInstruct | Self::MistralPixtralLarge2502V10 | Self::MoonshotKimiK2Thinking | Self::MoonshotaiKimiK25 | Self::NvidiaNemotronNano12bV2 | Self::NvidiaNemotronNano330b | Self::NvidiaNemotronNano9bV2 | Self::NvidiaNemotronSuper3120b | Self::OpenaiGptOss120b10 | Self::OpenaiGptOss20b10 | Self::OpenaiGptOssSafeguard120b | Self::OpenaiGptOssSafeguard20b | Self::QwenQwen3235bA22b2507V10 | Self::QwenQwen332bV10 | Self::QwenQwen3Coder30bA3bV10 | Self::QwenQwen3Coder480bA35bV10 | Self::QwenQwen3CoderNext | Self::QwenQwen3Next80bA3b | Self::QwenQwen3Vl235bA22b | Self::UsAnthropicClaudeHaiku4520251001V10 | Self::UsAnthropicClaudeOpus4120250805V10 | Self::UsAnthropicClaudeOpus420250514V10 | Self::UsAnthropicClaudeOpus4520251101V10 | Self::UsAnthropicClaudeOpus46V1 | Self::UsAnthropicClaudeOpus47 | Self::UsAnthropicClaudeSonnet420250514V10 | Self::UsAnthropicClaudeSonnet4520250929V10 | Self::UsAnthropicClaudeSonnet46 | Self::WriterPalmyraX4V10 | Self::WriterPalmyraX5V10 | Self::ZaiGlm47 | Self::ZaiGlm47Flash | Self::ZaiGlm5 => false,
2162 Self::MistralVoxtralMini3b2507 | Self::MistralVoxtralSmall24b2507 => true,
2163 }
2164 }
2165
2166 const ALL: &[BedrockModel] = &[
2167 Self::AmazonNova2LiteV10,
2168 Self::AmazonNovaLiteV10,
2169 Self::AmazonNovaMicroV10,
2170 Self::AmazonNovaPremierV10,
2171 Self::AmazonNovaProV10,
2172 Self::AnthropicClaude35Haiku20241022V10,
2173 Self::AnthropicClaude35Sonnet20240620V10,
2174 Self::AnthropicClaude35Sonnet20241022V20,
2175 Self::AnthropicClaude37Sonnet20250219V10,
2176 Self::AnthropicClaude3Haiku20240307V10,
2177 Self::AnthropicClaudeHaiku4520251001V10,
2178 Self::AnthropicClaudeOpus4120250805V10,
2179 Self::AnthropicClaudeOpus420250514V10,
2180 Self::AnthropicClaudeOpus4520251101V10,
2181 Self::AnthropicClaudeOpus46V1,
2182 Self::AnthropicClaudeOpus47,
2183 Self::AnthropicClaudeSonnet420250514V10,
2184 Self::AnthropicClaudeSonnet4520250929V10,
2185 Self::AnthropicClaudeSonnet46,
2186 Self::DeepseekR1V10,
2187 Self::DeepseekV3V10,
2188 Self::DeepseekV32,
2189 Self::EuAnthropicClaudeHaiku4520251001V10,
2190 Self::EuAnthropicClaudeOpus4520251101V10,
2191 Self::EuAnthropicClaudeOpus46V1,
2192 Self::EuAnthropicClaudeOpus47,
2193 Self::EuAnthropicClaudeSonnet420250514V10,
2194 Self::EuAnthropicClaudeSonnet4520250929V10,
2195 Self::EuAnthropicClaudeSonnet46,
2196 Self::GlobalAnthropicClaudeHaiku4520251001V10,
2197 Self::GlobalAnthropicClaudeOpus4520251101V10,
2198 Self::GlobalAnthropicClaudeOpus46V1,
2199 Self::GlobalAnthropicClaudeOpus47,
2200 Self::GlobalAnthropicClaudeSonnet420250514V10,
2201 Self::GlobalAnthropicClaudeSonnet4520250929V10,
2202 Self::GlobalAnthropicClaudeSonnet46,
2203 Self::GoogleGemma327bIt,
2204 Self::GoogleGemma34bIt,
2205 Self::MetaLlama31405bInstructV10,
2206 Self::MetaLlama3170bInstructV10,
2207 Self::MetaLlama318bInstructV10,
2208 Self::MetaLlama3211bInstructV10,
2209 Self::MetaLlama321bInstructV10,
2210 Self::MetaLlama323bInstructV10,
2211 Self::MetaLlama3290bInstructV10,
2212 Self::MetaLlama3370bInstructV10,
2213 Self::MetaLlama4Maverick17bInstructV10,
2214 Self::MetaLlama4Scout17bInstructV10,
2215 Self::MinimaxMinimaxM2,
2216 Self::MinimaxMinimaxM21,
2217 Self::MinimaxMinimaxM25,
2218 Self::MistralDevstral2123b,
2219 Self::MistralMagistralSmall2509,
2220 Self::MistralMinistral314bInstruct,
2221 Self::MistralMinistral33bInstruct,
2222 Self::MistralMinistral38bInstruct,
2223 Self::MistralMistralLarge3675bInstruct,
2224 Self::MistralPixtralLarge2502V10,
2225 Self::MistralVoxtralMini3b2507,
2226 Self::MistralVoxtralSmall24b2507,
2227 Self::MoonshotKimiK2Thinking,
2228 Self::MoonshotaiKimiK25,
2229 Self::NvidiaNemotronNano12bV2,
2230 Self::NvidiaNemotronNano330b,
2231 Self::NvidiaNemotronNano9bV2,
2232 Self::NvidiaNemotronSuper3120b,
2233 Self::OpenaiGptOss120b10,
2234 Self::OpenaiGptOss20b10,
2235 Self::OpenaiGptOssSafeguard120b,
2236 Self::OpenaiGptOssSafeguard20b,
2237 Self::QwenQwen3235bA22b2507V10,
2238 Self::QwenQwen332bV10,
2239 Self::QwenQwen3Coder30bA3bV10,
2240 Self::QwenQwen3Coder480bA35bV10,
2241 Self::QwenQwen3CoderNext,
2242 Self::QwenQwen3Next80bA3b,
2243 Self::QwenQwen3Vl235bA22b,
2244 Self::UsAnthropicClaudeHaiku4520251001V10,
2245 Self::UsAnthropicClaudeOpus4120250805V10,
2246 Self::UsAnthropicClaudeOpus420250514V10,
2247 Self::UsAnthropicClaudeOpus4520251101V10,
2248 Self::UsAnthropicClaudeOpus46V1,
2249 Self::UsAnthropicClaudeOpus47,
2250 Self::UsAnthropicClaudeSonnet420250514V10,
2251 Self::UsAnthropicClaudeSonnet4520250929V10,
2252 Self::UsAnthropicClaudeSonnet46,
2253 Self::WriterPalmyraX4V10,
2254 Self::WriterPalmyraX5V10,
2255 Self::ZaiGlm47,
2256 Self::ZaiGlm47Flash,
2257 Self::ZaiGlm5,
2258 ];
2259}
2260
2261impl std::str::FromStr for BedrockModel {
2262 type Err = String;
2263
2264 #[allow(clippy::too_many_lines)]
2265 fn from_str(s: &str) -> Result<Self, Self::Err> {
2266 match s {
2267 "amazon.nova-2-lite-v1:0" => Ok(Self::AmazonNova2LiteV10),
2268 "amazon.nova-lite-v1:0" => Ok(Self::AmazonNovaLiteV10),
2269 "amazon.nova-micro-v1:0" => Ok(Self::AmazonNovaMicroV10),
2270 "amazon.nova-premier-v1:0" => Ok(Self::AmazonNovaPremierV10),
2271 "amazon.nova-pro-v1:0" => Ok(Self::AmazonNovaProV10),
2272 "anthropic.claude-3-5-haiku-20241022-v1:0" => Ok(Self::AnthropicClaude35Haiku20241022V10),
2273 "anthropic.claude-3-5-sonnet-20240620-v1:0" => Ok(Self::AnthropicClaude35Sonnet20240620V10),
2274 "anthropic.claude-3-5-sonnet-20241022-v2:0" => Ok(Self::AnthropicClaude35Sonnet20241022V20),
2275 "anthropic.claude-3-7-sonnet-20250219-v1:0" => Ok(Self::AnthropicClaude37Sonnet20250219V10),
2276 "anthropic.claude-3-haiku-20240307-v1:0" => Ok(Self::AnthropicClaude3Haiku20240307V10),
2277 "anthropic.claude-haiku-4-5-20251001-v1:0" => Ok(Self::AnthropicClaudeHaiku4520251001V10),
2278 "anthropic.claude-opus-4-1-20250805-v1:0" => Ok(Self::AnthropicClaudeOpus4120250805V10),
2279 "anthropic.claude-opus-4-20250514-v1:0" => Ok(Self::AnthropicClaudeOpus420250514V10),
2280 "anthropic.claude-opus-4-5-20251101-v1:0" => Ok(Self::AnthropicClaudeOpus4520251101V10),
2281 "anthropic.claude-opus-4-6-v1" => Ok(Self::AnthropicClaudeOpus46V1),
2282 "anthropic.claude-opus-4-7" => Ok(Self::AnthropicClaudeOpus47),
2283 "anthropic.claude-sonnet-4-20250514-v1:0" => Ok(Self::AnthropicClaudeSonnet420250514V10),
2284 "anthropic.claude-sonnet-4-5-20250929-v1:0" => Ok(Self::AnthropicClaudeSonnet4520250929V10),
2285 "anthropic.claude-sonnet-4-6" => Ok(Self::AnthropicClaudeSonnet46),
2286 "deepseek.r1-v1:0" => Ok(Self::DeepseekR1V10),
2287 "deepseek.v3-v1:0" => Ok(Self::DeepseekV3V10),
2288 "deepseek.v3.2" => Ok(Self::DeepseekV32),
2289 "eu.anthropic.claude-haiku-4-5-20251001-v1:0" => Ok(Self::EuAnthropicClaudeHaiku4520251001V10),
2290 "eu.anthropic.claude-opus-4-5-20251101-v1:0" => Ok(Self::EuAnthropicClaudeOpus4520251101V10),
2291 "eu.anthropic.claude-opus-4-6-v1" => Ok(Self::EuAnthropicClaudeOpus46V1),
2292 "eu.anthropic.claude-opus-4-7" => Ok(Self::EuAnthropicClaudeOpus47),
2293 "eu.anthropic.claude-sonnet-4-20250514-v1:0" => Ok(Self::EuAnthropicClaudeSonnet420250514V10),
2294 "eu.anthropic.claude-sonnet-4-5-20250929-v1:0" => Ok(Self::EuAnthropicClaudeSonnet4520250929V10),
2295 "eu.anthropic.claude-sonnet-4-6" => Ok(Self::EuAnthropicClaudeSonnet46),
2296 "global.anthropic.claude-haiku-4-5-20251001-v1:0" => Ok(Self::GlobalAnthropicClaudeHaiku4520251001V10),
2297 "global.anthropic.claude-opus-4-5-20251101-v1:0" => Ok(Self::GlobalAnthropicClaudeOpus4520251101V10),
2298 "global.anthropic.claude-opus-4-6-v1" => Ok(Self::GlobalAnthropicClaudeOpus46V1),
2299 "global.anthropic.claude-opus-4-7" => Ok(Self::GlobalAnthropicClaudeOpus47),
2300 "global.anthropic.claude-sonnet-4-20250514-v1:0" => Ok(Self::GlobalAnthropicClaudeSonnet420250514V10),
2301 "global.anthropic.claude-sonnet-4-5-20250929-v1:0" => Ok(Self::GlobalAnthropicClaudeSonnet4520250929V10),
2302 "global.anthropic.claude-sonnet-4-6" => Ok(Self::GlobalAnthropicClaudeSonnet46),
2303 "google.gemma-3-27b-it" => Ok(Self::GoogleGemma327bIt),
2304 "google.gemma-3-4b-it" => Ok(Self::GoogleGemma34bIt),
2305 "meta.llama3-1-405b-instruct-v1:0" => Ok(Self::MetaLlama31405bInstructV10),
2306 "meta.llama3-1-70b-instruct-v1:0" => Ok(Self::MetaLlama3170bInstructV10),
2307 "meta.llama3-1-8b-instruct-v1:0" => Ok(Self::MetaLlama318bInstructV10),
2308 "meta.llama3-2-11b-instruct-v1:0" => Ok(Self::MetaLlama3211bInstructV10),
2309 "meta.llama3-2-1b-instruct-v1:0" => Ok(Self::MetaLlama321bInstructV10),
2310 "meta.llama3-2-3b-instruct-v1:0" => Ok(Self::MetaLlama323bInstructV10),
2311 "meta.llama3-2-90b-instruct-v1:0" => Ok(Self::MetaLlama3290bInstructV10),
2312 "meta.llama3-3-70b-instruct-v1:0" => Ok(Self::MetaLlama3370bInstructV10),
2313 "meta.llama4-maverick-17b-instruct-v1:0" => Ok(Self::MetaLlama4Maverick17bInstructV10),
2314 "meta.llama4-scout-17b-instruct-v1:0" => Ok(Self::MetaLlama4Scout17bInstructV10),
2315 "minimax.minimax-m2" => Ok(Self::MinimaxMinimaxM2),
2316 "minimax.minimax-m2.1" => Ok(Self::MinimaxMinimaxM21),
2317 "minimax.minimax-m2.5" => Ok(Self::MinimaxMinimaxM25),
2318 "mistral.devstral-2-123b" => Ok(Self::MistralDevstral2123b),
2319 "mistral.magistral-small-2509" => Ok(Self::MistralMagistralSmall2509),
2320 "mistral.ministral-3-14b-instruct" => Ok(Self::MistralMinistral314bInstruct),
2321 "mistral.ministral-3-3b-instruct" => Ok(Self::MistralMinistral33bInstruct),
2322 "mistral.ministral-3-8b-instruct" => Ok(Self::MistralMinistral38bInstruct),
2323 "mistral.mistral-large-3-675b-instruct" => Ok(Self::MistralMistralLarge3675bInstruct),
2324 "mistral.pixtral-large-2502-v1:0" => Ok(Self::MistralPixtralLarge2502V10),
2325 "mistral.voxtral-mini-3b-2507" => Ok(Self::MistralVoxtralMini3b2507),
2326 "mistral.voxtral-small-24b-2507" => Ok(Self::MistralVoxtralSmall24b2507),
2327 "moonshot.kimi-k2-thinking" => Ok(Self::MoonshotKimiK2Thinking),
2328 "moonshotai.kimi-k2.5" => Ok(Self::MoonshotaiKimiK25),
2329 "nvidia.nemotron-nano-12b-v2" => Ok(Self::NvidiaNemotronNano12bV2),
2330 "nvidia.nemotron-nano-3-30b" => Ok(Self::NvidiaNemotronNano330b),
2331 "nvidia.nemotron-nano-9b-v2" => Ok(Self::NvidiaNemotronNano9bV2),
2332 "nvidia.nemotron-super-3-120b" => Ok(Self::NvidiaNemotronSuper3120b),
2333 "openai.gpt-oss-120b-1:0" => Ok(Self::OpenaiGptOss120b10),
2334 "openai.gpt-oss-20b-1:0" => Ok(Self::OpenaiGptOss20b10),
2335 "openai.gpt-oss-safeguard-120b" => Ok(Self::OpenaiGptOssSafeguard120b),
2336 "openai.gpt-oss-safeguard-20b" => Ok(Self::OpenaiGptOssSafeguard20b),
2337 "qwen.qwen3-235b-a22b-2507-v1:0" => Ok(Self::QwenQwen3235bA22b2507V10),
2338 "qwen.qwen3-32b-v1:0" => Ok(Self::QwenQwen332bV10),
2339 "qwen.qwen3-coder-30b-a3b-v1:0" => Ok(Self::QwenQwen3Coder30bA3bV10),
2340 "qwen.qwen3-coder-480b-a35b-v1:0" => Ok(Self::QwenQwen3Coder480bA35bV10),
2341 "qwen.qwen3-coder-next" => Ok(Self::QwenQwen3CoderNext),
2342 "qwen.qwen3-next-80b-a3b" => Ok(Self::QwenQwen3Next80bA3b),
2343 "qwen.qwen3-vl-235b-a22b" => Ok(Self::QwenQwen3Vl235bA22b),
2344 "us.anthropic.claude-haiku-4-5-20251001-v1:0" => Ok(Self::UsAnthropicClaudeHaiku4520251001V10),
2345 "us.anthropic.claude-opus-4-1-20250805-v1:0" => Ok(Self::UsAnthropicClaudeOpus4120250805V10),
2346 "us.anthropic.claude-opus-4-20250514-v1:0" => Ok(Self::UsAnthropicClaudeOpus420250514V10),
2347 "us.anthropic.claude-opus-4-5-20251101-v1:0" => Ok(Self::UsAnthropicClaudeOpus4520251101V10),
2348 "us.anthropic.claude-opus-4-6-v1" => Ok(Self::UsAnthropicClaudeOpus46V1),
2349 "us.anthropic.claude-opus-4-7" => Ok(Self::UsAnthropicClaudeOpus47),
2350 "us.anthropic.claude-sonnet-4-20250514-v1:0" => Ok(Self::UsAnthropicClaudeSonnet420250514V10),
2351 "us.anthropic.claude-sonnet-4-5-20250929-v1:0" => Ok(Self::UsAnthropicClaudeSonnet4520250929V10),
2352 "us.anthropic.claude-sonnet-4-6" => Ok(Self::UsAnthropicClaudeSonnet46),
2353 "writer.palmyra-x4-v1:0" => Ok(Self::WriterPalmyraX4V10),
2354 "writer.palmyra-x5-v1:0" => Ok(Self::WriterPalmyraX5V10),
2355 "zai.glm-4.7" => Ok(Self::ZaiGlm47),
2356 "zai.glm-4.7-flash" => Ok(Self::ZaiGlm47Flash),
2357 "zai.glm-5" => Ok(Self::ZaiGlm5),
2358 _ => Err(format!("Unknown bedrock model: '{s}'")),
2359 }
2360 }
2361}
2362
2363#[derive(Debug, Clone, PartialEq, Eq, Hash)]
2365pub enum LlmModel {
2366 Anthropic(AnthropicModel),
2367 Codex(CodexModel),
2368 DeepSeek(DeepSeekModel),
2369 Gemini(GeminiModel),
2370 Moonshot(MoonshotModel),
2371 Openai(OpenaiModel),
2372 OpenRouter(OpenRouterModel),
2373 ZAi(ZAiModel),
2374 Bedrock(BedrockModel),
2375 Ollama(String),
2376 LlamaCpp(String),
2377}
2378
2379impl From<AnthropicModel> for LlmModel {
2380 fn from(m: AnthropicModel) -> Self { LlmModel::Anthropic(m) }
2381}
2382
2383impl From<CodexModel> for LlmModel {
2384 fn from(m: CodexModel) -> Self { LlmModel::Codex(m) }
2385}
2386
2387impl From<DeepSeekModel> for LlmModel {
2388 fn from(m: DeepSeekModel) -> Self { LlmModel::DeepSeek(m) }
2389}
2390
2391impl From<GeminiModel> for LlmModel {
2392 fn from(m: GeminiModel) -> Self { LlmModel::Gemini(m) }
2393}
2394
2395impl From<MoonshotModel> for LlmModel {
2396 fn from(m: MoonshotModel) -> Self { LlmModel::Moonshot(m) }
2397}
2398
2399impl From<OpenaiModel> for LlmModel {
2400 fn from(m: OpenaiModel) -> Self { LlmModel::Openai(m) }
2401}
2402
2403impl From<OpenRouterModel> for LlmModel {
2404 fn from(m: OpenRouterModel) -> Self { LlmModel::OpenRouter(m) }
2405}
2406
2407impl From<ZAiModel> for LlmModel {
2408 fn from(m: ZAiModel) -> Self { LlmModel::ZAi(m) }
2409}
2410
2411impl From<BedrockModel> for LlmModel {
2412 fn from(m: BedrockModel) -> Self { LlmModel::Bedrock(m) }
2413}
2414
2415impl LlmModel {
2416 pub fn model_id(&self) -> Cow<'static, str> {
2418 match self {
2419 Self::Anthropic(m) => Cow::Borrowed(m.model_id()),
2420 Self::Codex(m) => Cow::Borrowed(m.model_id()),
2421 Self::DeepSeek(m) => Cow::Borrowed(m.model_id()),
2422 Self::Gemini(m) => Cow::Borrowed(m.model_id()),
2423 Self::Moonshot(m) => Cow::Borrowed(m.model_id()),
2424 Self::Openai(m) => Cow::Borrowed(m.model_id()),
2425 Self::OpenRouter(m) => Cow::Borrowed(m.model_id()),
2426 Self::ZAi(m) => Cow::Borrowed(m.model_id()),
2427 Self::Bedrock(m) => Cow::Borrowed(m.model_id()),
2428 Self::Ollama(s) | Self::LlamaCpp(s) => Cow::Owned(s.clone()),
2429 }
2430 }
2431
2432 pub fn display_name(&self) -> Cow<'static, str> {
2434 match self {
2435 Self::Anthropic(m) => Cow::Borrowed(m.display_name()),
2436 Self::Codex(m) => Cow::Borrowed(m.display_name()),
2437 Self::DeepSeek(m) => Cow::Borrowed(m.display_name()),
2438 Self::Gemini(m) => Cow::Borrowed(m.display_name()),
2439 Self::Moonshot(m) => Cow::Borrowed(m.display_name()),
2440 Self::Openai(m) => Cow::Borrowed(m.display_name()),
2441 Self::OpenRouter(m) => Cow::Borrowed(m.display_name()),
2442 Self::ZAi(m) => Cow::Borrowed(m.display_name()),
2443 Self::Bedrock(m) => Cow::Borrowed(m.display_name()),
2444 Self::Ollama(s) => Cow::Owned(format!("Ollama {s}")),
2445 Self::LlamaCpp(s) => Cow::Owned(format!("LlamaCpp {s}")),
2446 }
2447 }
2448
2449 pub fn provider(&self) -> &'static str {
2451 match self {
2452 Self::Anthropic(_) => "anthropic",
2453 Self::Codex(_) => "codex",
2454 Self::DeepSeek(_) => "deepseek",
2455 Self::Gemini(_) => "gemini",
2456 Self::Moonshot(_) => "moonshot",
2457 Self::Openai(_) => "openai",
2458 Self::OpenRouter(_) => "openrouter",
2459 Self::ZAi(_) => "zai",
2460 Self::Bedrock(_) => "bedrock",
2461 Self::Ollama(_) => "ollama",
2462 Self::LlamaCpp(_) => "llamacpp",
2463 }
2464 }
2465
2466 pub fn provider_display_name(&self) -> &'static str {
2468 match self {
2469 Self::Anthropic(_) => "Anthropic",
2470 Self::Codex(_) => "Codex",
2471 Self::DeepSeek(_) => "DeepSeek",
2472 Self::Gemini(_) => "Gemini",
2473 Self::Moonshot(_) => "Moonshot",
2474 Self::Openai(_) => "OpenAI",
2475 Self::OpenRouter(_) => "OpenRouter",
2476 Self::ZAi(_) => "ZAI",
2477 Self::Bedrock(_) => "AWS Bedrock",
2478 Self::Ollama(_) => "Ollama",
2479 Self::LlamaCpp(_) => "LlamaCpp",
2480 }
2481 }
2482
2483 pub fn context_window(&self) -> Option<u32> {
2485 match self {
2486 Self::Anthropic(m) => Some(m.context_window()),
2487 Self::Codex(m) => Some(m.context_window()),
2488 Self::DeepSeek(m) => Some(m.context_window()),
2489 Self::Gemini(m) => Some(m.context_window()),
2490 Self::Moonshot(m) => Some(m.context_window()),
2491 Self::Openai(m) => Some(m.context_window()),
2492 Self::OpenRouter(m) => Some(m.context_window()),
2493 Self::ZAi(m) => Some(m.context_window()),
2494 Self::Bedrock(m) => Some(m.context_window()),
2495 Self::Ollama(_) | Self::LlamaCpp(_) => None,
2496 }
2497 }
2498
2499 pub fn required_env_var(&self) -> Option<&'static str> {
2501 match self {
2502 Self::Anthropic(_) => Some("ANTHROPIC_API_KEY"),
2503 Self::DeepSeek(_) => Some("DEEPSEEK_API_KEY"),
2504 Self::Gemini(_) => Some("GEMINI_API_KEY"),
2505 Self::Moonshot(_) => Some("MOONSHOT_API_KEY"),
2506 Self::Openai(_) => Some("OPENAI_API_KEY"),
2507 Self::OpenRouter(_) => Some("OPENROUTER_API_KEY"),
2508 Self::ZAi(_) => Some("ZAI_API_KEY"),
2509 Self::Codex(_) | Self::Bedrock(_) | Self::Ollama(_) | Self::LlamaCpp(_) => None,
2510 }
2511 }
2512
2513 pub const ALL_REQUIRED_ENV_VARS: &[&str] = &["ANTHROPIC_API_KEY", "DEEPSEEK_API_KEY", "GEMINI_API_KEY", "MOONSHOT_API_KEY", "OPENAI_API_KEY", "OPENROUTER_API_KEY", "ZAI_API_KEY"];
2515
2516 pub fn oauth_provider_id(&self) -> Option<&'static str> {
2518 match self {
2519 Self::Codex(_) => Some("codex"),
2520 Self::Anthropic(_) | Self::DeepSeek(_) | Self::Gemini(_) | Self::Moonshot(_) | Self::Openai(_) | Self::OpenRouter(_) | Self::ZAi(_) | Self::Bedrock(_) | Self::Ollama(_) | Self::LlamaCpp(_) => None,
2521 }
2522 }
2523
2524 pub fn reasoning_levels(&self) -> &'static [ReasoningEffort] {
2526 match self {
2527 Self::Anthropic(m) => m.reasoning_levels(),
2528 Self::Codex(m) => m.reasoning_levels(),
2529 Self::DeepSeek(m) => m.reasoning_levels(),
2530 Self::Gemini(m) => m.reasoning_levels(),
2531 Self::Moonshot(m) => m.reasoning_levels(),
2532 Self::Openai(m) => m.reasoning_levels(),
2533 Self::OpenRouter(m) => m.reasoning_levels(),
2534 Self::ZAi(m) => m.reasoning_levels(),
2535 Self::Bedrock(m) => m.reasoning_levels(),
2536 Self::Ollama(_) | Self::LlamaCpp(_) => &[],
2537 }
2538 }
2539
2540 pub fn supports_reasoning(&self) -> bool {
2542 !self.reasoning_levels().is_empty()
2543 }
2544
2545 pub fn supports_image(&self) -> bool {
2547 match self {
2548 Self::Anthropic(m) => m.supports_image(),
2549 Self::Codex(m) => m.supports_image(),
2550 Self::DeepSeek(m) => m.supports_image(),
2551 Self::Gemini(m) => m.supports_image(),
2552 Self::Moonshot(m) => m.supports_image(),
2553 Self::Openai(m) => m.supports_image(),
2554 Self::OpenRouter(m) => m.supports_image(),
2555 Self::ZAi(m) => m.supports_image(),
2556 Self::Bedrock(m) => m.supports_image(),
2557 Self::Ollama(_) | Self::LlamaCpp(_) => false,
2558 }
2559 }
2560
2561 pub fn supports_audio(&self) -> bool {
2563 match self {
2564 Self::Anthropic(m) => m.supports_audio(),
2565 Self::Codex(m) => m.supports_audio(),
2566 Self::DeepSeek(m) => m.supports_audio(),
2567 Self::Gemini(m) => m.supports_audio(),
2568 Self::Moonshot(m) => m.supports_audio(),
2569 Self::Openai(m) => m.supports_audio(),
2570 Self::OpenRouter(m) => m.supports_audio(),
2571 Self::ZAi(m) => m.supports_audio(),
2572 Self::Bedrock(m) => m.supports_audio(),
2573 Self::Ollama(_) | Self::LlamaCpp(_) => false,
2574 }
2575 }
2576
2577 pub fn all() -> &'static [LlmModel] {
2579 static ALL: LazyLock<Vec<LlmModel>> = LazyLock::new(|| {
2580 let mut v = Vec::new();
2581 v.extend(AnthropicModel::ALL.iter().copied().map(LlmModel::Anthropic));
2582 v.extend(CodexModel::ALL.iter().copied().map(LlmModel::Codex));
2583 v.extend(DeepSeekModel::ALL.iter().copied().map(LlmModel::DeepSeek));
2584 v.extend(GeminiModel::ALL.iter().copied().map(LlmModel::Gemini));
2585 v.extend(MoonshotModel::ALL.iter().copied().map(LlmModel::Moonshot));
2586 v.extend(OpenaiModel::ALL.iter().copied().map(LlmModel::Openai));
2587 v.extend(OpenRouterModel::ALL.iter().copied().map(LlmModel::OpenRouter));
2588 v.extend(ZAiModel::ALL.iter().copied().map(LlmModel::ZAi));
2589 v.extend(BedrockModel::ALL.iter().copied().map(LlmModel::Bedrock));
2590 v
2591 });
2592 &ALL
2593 }
2594}
2595
2596impl std::fmt::Display for LlmModel {
2597 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2598 write!(f, "{}:{}", self.provider(), self.model_id())
2599 }
2600}
2601
2602impl std::str::FromStr for LlmModel {
2603 type Err = String;
2604
2605 fn from_str(s: &str) -> Result<Self, Self::Err> {
2607 let (provider_str, model_str) = s.split_once(':').unwrap_or((s, ""));
2608 match provider_str {
2609 "anthropic" => model_str.parse::<AnthropicModel>().map(Self::Anthropic),
2610 "codex" => model_str.parse::<CodexModel>().map(Self::Codex),
2611 "deepseek" => model_str.parse::<DeepSeekModel>().map(Self::DeepSeek),
2612 "gemini" => model_str.parse::<GeminiModel>().map(Self::Gemini),
2613 "moonshot" => model_str.parse::<MoonshotModel>().map(Self::Moonshot),
2614 "openai" => model_str.parse::<OpenaiModel>().map(Self::Openai),
2615 "openrouter" => model_str.parse::<OpenRouterModel>().map(Self::OpenRouter),
2616 "zai" => model_str.parse::<ZAiModel>().map(Self::ZAi),
2617 "bedrock" => model_str.parse::<BedrockModel>().map(Self::Bedrock),
2618 "ollama" => Ok(Self::Ollama(model_str.to_string())),
2619 "llamacpp" => Ok(Self::LlamaCpp(model_str.to_string())),
2620 _ => Err(format!("Unknown provider: '{provider_str}'")),
2621 }
2622 }
2623}