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