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