Skip to main content

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