Skip to main content

llm/opt/rustwide/target/x86_64-unknown-linux-gnu/debug/build/aether-llm-5099cac690816167/out/
generated.rs

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