Skip to main content

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