Skip to main content

vtcode_core/models_manager/
model_presets.rs

1//! Model presets and built-in model configurations.
2//!
3//! This module provides pre-configured model presets for all supported providers,
4//! following the pattern from OpenAI Codex's models_manager.
5
6use serde::{Deserialize, Serialize};
7
8use crate::config::constants::models::copilot as copilot_models;
9use crate::config::constants::models::evolink as evolink_models;
10use crate::config::constants::models::llamacpp as llamacpp_models;
11use crate::config::constants::models::mimo as mimo_models;
12use crate::config::constants::models::poolside as poolside_models;
13use crate::config::constants::models::qwen as qwen_models;
14use crate::config::constants::models::stepfun as stepfun_models;
15use crate::config::models::Provider;
16use crate::config::types::ReasoningEffortLevel;
17
18/// Reasoning effort preset with description
19#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
20pub struct ReasoningEffortPreset {
21    /// The effort level
22    pub effort: ReasoningEffortLevel,
23    /// Human-readable description
24    pub description: String,
25}
26
27/// Model upgrade information
28#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
29pub struct ModelUpgrade {
30    /// Target model ID to upgrade to
31    pub id: String,
32    /// Optional reasoning effort mapping
33    #[serde(default, skip_serializing_if = "Option::is_none")]
34    pub reasoning_effort_mapping: Option<String>,
35    /// Configuration key for migration
36    pub migration_config_key: String,
37    /// Link to model documentation
38    #[serde(default, skip_serializing_if = "Option::is_none")]
39    pub model_link: Option<String>,
40    /// Upgrade notification copy
41    #[serde(default, skip_serializing_if = "Option::is_none")]
42    pub upgrade_copy: Option<String>,
43}
44
45/// Remote model information received from provider APIs
46#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
47pub struct ModelInfo {
48    /// Unique model identifier/slug
49    pub slug: String,
50    /// Display name for UI
51    pub display_name: String,
52    /// Model description
53    pub description: String,
54    /// Provider this model belongs to
55    pub provider: Provider,
56    /// Default reasoning level
57    #[serde(default)]
58    pub default_reasoning_level: ReasoningEffortLevel,
59    /// Supported reasoning levels
60    #[serde(default)]
61    pub supported_reasoning_levels: Vec<ReasoningEffortPreset>,
62    /// Context window size
63    #[serde(default)]
64    pub context_window: Option<i64>,
65    /// Whether this model supports tool use
66    #[serde(default = "default_true")]
67    pub supports_tool_use: bool,
68    /// Whether this model supports streaming
69    #[serde(default = "default_true")]
70    pub supports_streaming: bool,
71    /// Whether this model supports reasoning/thinking
72    #[serde(default)]
73    pub supports_reasoning: bool,
74    /// Priority for sorting (lower = higher priority)
75    #[serde(default)]
76    pub priority: i32,
77    /// Visibility in picker
78    #[serde(default = "default_visibility")]
79    pub visibility: String,
80    /// Whether supported in API mode
81    #[serde(default = "default_true")]
82    pub supported_in_api: bool,
83    /// Upgrade path if available
84    #[serde(default, skip_serializing_if = "Option::is_none")]
85    pub upgrade: Option<ModelUpgrade>,
86}
87
88fn default_true() -> bool {
89    true
90}
91
92fn default_visibility() -> String {
93    "list".to_string()
94}
95
96/// A preset configuration for a model shown in the picker
97#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
98pub struct ModelPreset {
99    /// Unique identifier for the preset
100    pub id: String,
101    /// Actual model slug to use in API calls
102    pub model: String,
103    /// Display name for UI
104    pub display_name: String,
105    /// Model description
106    pub description: String,
107    /// Provider
108    pub provider: Provider,
109    /// Default reasoning effort
110    pub default_reasoning_effort: ReasoningEffortLevel,
111    /// Supported reasoning efforts
112    pub supported_reasoning_efforts: Vec<ReasoningEffortPreset>,
113    /// Whether this is the default model
114    #[serde(default)]
115    pub is_default: bool,
116    /// Upgrade path
117    #[serde(default, skip_serializing_if = "Option::is_none")]
118    pub upgrade: Option<ModelUpgrade>,
119    /// Whether to show in picker
120    #[serde(default = "default_true")]
121    pub show_in_picker: bool,
122    /// Whether supported in API mode
123    #[serde(default = "default_true")]
124    pub supported_in_api: bool,
125    /// Context window size
126    #[serde(default)]
127    pub context_window: Option<i64>,
128}
129
130impl From<ModelInfo> for ModelPreset {
131    fn from(info: ModelInfo) -> Self {
132        Self {
133            id: info.slug.clone(),
134            model: info.slug,
135            display_name: info.display_name,
136            description: info.description,
137            provider: info.provider,
138            default_reasoning_effort: info.default_reasoning_level,
139            supported_reasoning_efforts: info.supported_reasoning_levels,
140            is_default: false,
141            upgrade: info.upgrade,
142            show_in_picker: info.visibility == "list",
143            supported_in_api: info.supported_in_api,
144            context_window: info.context_window,
145        }
146    }
147}
148
149/// Get built-in model presets for the given provider
150pub fn builtin_model_presets() -> Vec<ModelPreset> {
151    let mut presets = Vec::new();
152
153    // Gemini presets
154    presets.extend(gemini_presets());
155
156    // OpenAI presets
157    presets.extend(openai_presets());
158
159    // Anthropic presets
160    presets.extend(anthropic_presets());
161
162    // Copilot presets
163    presets.extend(copilot_presets());
164
165    // DeepSeek presets
166    presets.extend(deepseek_presets());
167
168    // Z.AI presets
169    presets.extend(zai_presets());
170
171    // LM Studio presets
172    presets.extend(lmstudio_presets());
173
174    // llama.cpp presets
175    presets.extend(llamacpp_presets());
176
177    // MiniMax presets
178    presets.extend(minimax_presets());
179
180    // OpenCode Zen presets
181    presets.extend(opencode_zen_presets());
182
183    // OpenCode Go presets
184    presets.extend(opencode_go_presets());
185
186    // Poolside presets
187    presets.extend(poolside_presets());
188
189    // StepFun presets
190    presets.extend(stepfun_presets());
191
192    // Evolink presets
193    presets.extend(evolink_presets());
194
195    presets
196}
197
198/// Get presets for a specific provider
199pub fn presets_for_provider(provider: Provider) -> Vec<ModelPreset> {
200    match provider {
201        Provider::Gemini => gemini_presets(),
202        Provider::OpenAI => openai_presets(),
203        Provider::Anthropic => anthropic_presets(),
204        Provider::Copilot => copilot_presets(),
205        Provider::DeepSeek => deepseek_presets(),
206        Provider::ZAI => zai_presets(),
207        Provider::Minimax => minimax_presets(),
208        Provider::OpenRouter => openrouter_presets(),
209        Provider::Ollama => ollama_presets(),
210        Provider::LmStudio => lmstudio_presets(),
211        Provider::LlamaCpp => llamacpp_presets(),
212        Provider::Moonshot => moonshot_presets(),
213        Provider::Mistral => mistral_presets(),
214        Provider::HuggingFace => huggingface_presets(),
215        Provider::OpenCodeZen => opencode_zen_presets(),
216        Provider::OpenCodeGo => opencode_go_presets(),
217        Provider::MiMo => mimo_presets(),
218        Provider::Qwen => qwen_presets(),
219        Provider::StepFun => stepfun_presets(),
220        Provider::Evolink => evolink_presets(),
221        Provider::Poolside => poolside_presets(),
222    }
223}
224
225fn copilot_presets() -> Vec<ModelPreset> {
226    vec![ModelPreset {
227        id: copilot_models::AUTO.to_string(),
228        model: copilot_models::AUTO.to_string(),
229        display_name: "GitHub Copilot Auto".to_string(),
230        description:
231            "Official GitHub Copilot preview provider via the Copilot CLI with automatic model selection."
232                .to_string(),
233        provider: Provider::Copilot,
234        default_reasoning_effort: ReasoningEffortLevel::Medium,
235        supported_reasoning_efforts: Vec::new(),
236        is_default: true,
237        upgrade: None,
238        show_in_picker: true,
239        supported_in_api: true,
240        context_window: Some(400_000),
241    }]
242}
243
244fn gemini_presets() -> Vec<ModelPreset> {
245    vec![ModelPreset {
246        id: "gemini-3-flash-preview".to_string(),
247        model: "gemini-3-flash-preview".to_string(),
248        display_name: "Gemini 3 Flash Preview".to_string(),
249        description: "Most intelligent model built for speed with superior search and grounding"
250            .to_string(),
251        provider: Provider::Gemini,
252        default_reasoning_effort: ReasoningEffortLevel::Medium,
253        supported_reasoning_efforts: vec![
254            ReasoningEffortPreset {
255                effort: ReasoningEffortLevel::Low,
256                description: "Fast responses".to_string(),
257            },
258            ReasoningEffortPreset {
259                effort: ReasoningEffortLevel::Medium,
260                description: "Balanced reasoning".to_string(),
261            },
262            ReasoningEffortPreset {
263                effort: ReasoningEffortLevel::High,
264                description: "Deep reasoning".to_string(),
265            },
266        ],
267        is_default: true,
268        upgrade: None,
269        show_in_picker: true,
270        supported_in_api: true,
271        context_window: Some(1_048_576),
272    }]
273}
274
275fn reasoning_preset(
276    effort: ReasoningEffortLevel,
277    description: &'static str,
278) -> ReasoningEffortPreset {
279    ReasoningEffortPreset {
280        effort,
281        description: description.to_string(),
282    }
283}
284
285fn openai_reasoning_efforts(include_none: bool, include_xhigh: bool) -> Vec<ReasoningEffortPreset> {
286    let mut efforts = Vec::new();
287    if include_none {
288        efforts.push(reasoning_preset(
289            ReasoningEffortLevel::None,
290            "Lowest latency",
291        ));
292    }
293    efforts.push(reasoning_preset(ReasoningEffortLevel::Low, "Fast"));
294    efforts.push(reasoning_preset(ReasoningEffortLevel::Medium, "Balanced"));
295    efforts.push(reasoning_preset(ReasoningEffortLevel::High, "Deep"));
296    if include_xhigh {
297        efforts.push(reasoning_preset(
298            ReasoningEffortLevel::XHigh,
299            "Maximum reasoning",
300        ));
301    }
302    efforts
303}
304
305fn openai_presets() -> Vec<ModelPreset> {
306    vec![
307        ModelPreset {
308            id: "gpt-5.4".to_string(),
309            model: "gpt-5.4".to_string(),
310            display_name: "GPT-5.4".to_string(),
311            description: "Frontier model for complex professional work".to_string(),
312            provider: Provider::OpenAI,
313            default_reasoning_effort: ReasoningEffortLevel::None,
314            supported_reasoning_efforts: openai_reasoning_efforts(true, true),
315            is_default: true,
316            upgrade: None,
317            show_in_picker: true,
318            supported_in_api: true,
319            context_window: Some(1_050_000),
320        },
321        ModelPreset {
322            id: "gpt-5.4-pro".to_string(),
323            model: "gpt-5.4-pro".to_string(),
324            display_name: "GPT-5.4 Pro".to_string(),
325            description: "Higher-compute GPT-5.4 variant for tougher problems".to_string(),
326            provider: Provider::OpenAI,
327            default_reasoning_effort: ReasoningEffortLevel::Medium,
328            supported_reasoning_efforts: vec![
329                reasoning_preset(ReasoningEffortLevel::Medium, "Balanced"),
330                reasoning_preset(ReasoningEffortLevel::High, "Deep"),
331                reasoning_preset(ReasoningEffortLevel::XHigh, "Maximum reasoning"),
332            ],
333            is_default: false,
334            upgrade: None,
335            show_in_picker: true,
336            supported_in_api: true,
337            context_window: Some(1_050_000),
338        },
339        ModelPreset {
340            id: "gpt-5.3-codex".to_string(),
341            model: "gpt-5.3-codex".to_string(),
342            display_name: "GPT-5.3 Codex".to_string(),
343            description: "GPT-5.3 variant optimized for agentic coding with xhigh reasoning"
344                .to_string(),
345            provider: Provider::OpenAI,
346            default_reasoning_effort: ReasoningEffortLevel::High,
347            supported_reasoning_efforts: openai_reasoning_efforts(true, true),
348            is_default: false,
349            upgrade: None,
350            show_in_picker: true,
351            supported_in_api: true,
352            context_window: Some(272_000),
353        },
354        ModelPreset {
355            id: "gpt-5.2-codex".to_string(),
356            model: "gpt-5.2-codex".to_string(),
357            display_name: "GPT-5.2 Codex".to_string(),
358            description: "GPT-5.2 variant optimized for agentic coding with xhigh reasoning"
359                .to_string(),
360            provider: Provider::OpenAI,
361            default_reasoning_effort: ReasoningEffortLevel::High,
362            supported_reasoning_efforts: openai_reasoning_efforts(true, true),
363            is_default: false,
364            upgrade: None,
365            show_in_picker: true,
366            supported_in_api: true,
367            context_window: Some(272_000),
368        },
369        ModelPreset {
370            id: "gpt-5.1-codex".to_string(),
371            model: "gpt-5.1-codex".to_string(),
372            display_name: "GPT-5.1 Codex".to_string(),
373            description: "GPT-5.1 variant optimized for agentic coding".to_string(),
374            provider: Provider::OpenAI,
375            default_reasoning_effort: ReasoningEffortLevel::High,
376            supported_reasoning_efforts: openai_reasoning_efforts(false, false),
377            is_default: false,
378            upgrade: None,
379            show_in_picker: true,
380            supported_in_api: true,
381            context_window: Some(272_000),
382        },
383        ModelPreset {
384            id: "gpt-5.1-codex-max".to_string(),
385            model: "gpt-5.1-codex-max".to_string(),
386            display_name: "GPT-5.1 Codex Max".to_string(),
387            description:
388                "Higher-compute GPT-5.1 Codex variant for longer-running engineering tasks"
389                    .to_string(),
390            provider: Provider::OpenAI,
391            default_reasoning_effort: ReasoningEffortLevel::High,
392            supported_reasoning_efforts: openai_reasoning_efforts(false, false),
393            is_default: false,
394            upgrade: None,
395            show_in_picker: true,
396            supported_in_api: true,
397            context_window: Some(272_000),
398        },
399        ModelPreset {
400            id: "gpt-5-codex".to_string(),
401            model: "gpt-5-codex".to_string(),
402            display_name: "GPT-5 Codex".to_string(),
403            description: "GPT-5 variant optimized for agentic coding".to_string(),
404            provider: Provider::OpenAI,
405            default_reasoning_effort: ReasoningEffortLevel::High,
406            supported_reasoning_efforts: openai_reasoning_efforts(false, false),
407            is_default: false,
408            upgrade: None,
409            show_in_picker: true,
410            supported_in_api: true,
411            context_window: Some(272_000),
412        },
413        ModelPreset {
414            id: "gpt-5.2".to_string(),
415            model: "gpt-5.2".to_string(),
416            display_name: "GPT-5.2".to_string(),
417            description: "Latest frontier model with improved reasoning and coding".to_string(),
418            provider: Provider::OpenAI,
419            default_reasoning_effort: ReasoningEffortLevel::None,
420            supported_reasoning_efforts: openai_reasoning_efforts(true, true),
421            is_default: false,
422            upgrade: None,
423            show_in_picker: true,
424            supported_in_api: true,
425            context_window: Some(272_000),
426        },
427        ModelPreset {
428            id: "gpt-5".to_string(),
429            model: "gpt-5".to_string(),
430            display_name: "GPT-5".to_string(),
431            description: "Latest most capable OpenAI model".to_string(),
432            provider: Provider::OpenAI,
433            default_reasoning_effort: ReasoningEffortLevel::Medium,
434            supported_reasoning_efforts: vec![
435                ReasoningEffortPreset {
436                    effort: ReasoningEffortLevel::Low,
437                    description: "Fast".to_string(),
438                },
439                ReasoningEffortPreset {
440                    effort: ReasoningEffortLevel::Medium,
441                    description: "Balanced".to_string(),
442                },
443                ReasoningEffortPreset {
444                    effort: ReasoningEffortLevel::High,
445                    description: "Deep".to_string(),
446                },
447            ],
448            is_default: false,
449            upgrade: None,
450            show_in_picker: true,
451            supported_in_api: true,
452            context_window: Some(200_000),
453        },
454        ModelPreset {
455            id: "gpt-5-mini".to_string(),
456            model: "gpt-5-mini".to_string(),
457            display_name: "GPT-5 Mini".to_string(),
458            description: "Efficient GPT-5 variant".to_string(),
459            provider: Provider::OpenAI,
460            default_reasoning_effort: ReasoningEffortLevel::Medium,
461            supported_reasoning_efforts: vec![ReasoningEffortPreset {
462                effort: ReasoningEffortLevel::Medium,
463                description: "Balanced".to_string(),
464            }],
465            is_default: false,
466            upgrade: None,
467            show_in_picker: true,
468            supported_in_api: true,
469            context_window: Some(128_000),
470        },
471        ModelPreset {
472            id: "gpt-5-nano".to_string(),
473            model: "gpt-5-nano".to_string(),
474            display_name: "GPT-5 Nano".to_string(),
475            description: "Most cost-effective GPT-5 variant for high-volume tasks".to_string(),
476            provider: Provider::OpenAI,
477            default_reasoning_effort: ReasoningEffortLevel::Medium,
478            supported_reasoning_efforts: vec![ReasoningEffortPreset {
479                effort: ReasoningEffortLevel::Medium,
480                description: "Balanced".to_string(),
481            }],
482            is_default: false,
483            upgrade: None,
484            show_in_picker: true,
485            supported_in_api: true,
486            context_window: Some(200_000),
487        },
488        ModelPreset {
489            id: "o3".to_string(),
490            model: "o3".to_string(),
491            display_name: "o3".to_string(),
492            description: "OpenAI reasoning model for harder multi-step work".to_string(),
493            provider: Provider::OpenAI,
494            default_reasoning_effort: ReasoningEffortLevel::Medium,
495            supported_reasoning_efforts: openai_reasoning_efforts(false, false),
496            is_default: false,
497            upgrade: None,
498            show_in_picker: true,
499            supported_in_api: true,
500            context_window: None,
501        },
502        ModelPreset {
503            id: "o4-mini".to_string(),
504            model: "o4-mini".to_string(),
505            display_name: "o4-mini".to_string(),
506            description: "Smaller OpenAI reasoning model with strong tool use".to_string(),
507            provider: Provider::OpenAI,
508            default_reasoning_effort: ReasoningEffortLevel::Medium,
509            supported_reasoning_efforts: openai_reasoning_efforts(false, false),
510            is_default: false,
511            upgrade: None,
512            show_in_picker: true,
513            supported_in_api: true,
514            context_window: None,
515        },
516        ModelPreset {
517            id: "gpt-oss-20b".to_string(),
518            model: "gpt-oss-20b".to_string(),
519            display_name: "GPT-OSS 20B".to_string(),
520            description: "OpenAI's open-source 20B parameter model".to_string(),
521            provider: Provider::OpenAI,
522            default_reasoning_effort: ReasoningEffortLevel::Medium,
523            supported_reasoning_efforts: vec![
524                ReasoningEffortPreset {
525                    effort: ReasoningEffortLevel::Low,
526                    description: "Fast".to_string(),
527                },
528                ReasoningEffortPreset {
529                    effort: ReasoningEffortLevel::Medium,
530                    description: "Balanced".to_string(),
531                },
532                ReasoningEffortPreset {
533                    effort: ReasoningEffortLevel::High,
534                    description: "Deep".to_string(),
535                },
536            ],
537            is_default: false,
538            upgrade: None,
539            show_in_picker: true,
540            supported_in_api: true,
541            context_window: Some(131_072),
542        },
543        ModelPreset {
544            id: "gpt-oss-120b".to_string(),
545            model: "gpt-oss-120b".to_string(),
546            display_name: "GPT-OSS 120B".to_string(),
547            description: "OpenAI's open-source 120B parameter model with advanced reasoning"
548                .to_string(),
549            provider: Provider::OpenAI,
550            default_reasoning_effort: ReasoningEffortLevel::Medium,
551            supported_reasoning_efforts: vec![
552                ReasoningEffortPreset {
553                    effort: ReasoningEffortLevel::Low,
554                    description: "Fast".to_string(),
555                },
556                ReasoningEffortPreset {
557                    effort: ReasoningEffortLevel::Medium,
558                    description: "Balanced".to_string(),
559                },
560                ReasoningEffortPreset {
561                    effort: ReasoningEffortLevel::High,
562                    description: "Deep".to_string(),
563                },
564            ],
565            is_default: false,
566            upgrade: None,
567            show_in_picker: true,
568            supported_in_api: true,
569            context_window: Some(131_072),
570        },
571    ]
572}
573
574fn anthropic_presets() -> Vec<ModelPreset> {
575    vec![
576        ModelPreset {
577            id: "claude-opus-4-8".to_string(),
578            model: "claude-opus-4-8".to_string(),
579            display_name: "Claude Opus 4.8".to_string(),
580            description:
581                "Anthropic's most capable model for complex reasoning, long-horizon agentic coding, and high-autonomy work"
582                    .to_string(),
583            provider: Provider::Anthropic,
584            default_reasoning_effort: ReasoningEffortLevel::XHigh,
585            supported_reasoning_efforts: vec![
586                ReasoningEffortPreset {
587                    effort: ReasoningEffortLevel::Low,
588                    description: "Fast adaptive effort".to_string(),
589                },
590                ReasoningEffortPreset {
591                    effort: ReasoningEffortLevel::Medium,
592                    description: "Balanced adaptive effort".to_string(),
593                },
594                ReasoningEffortPreset {
595                    effort: ReasoningEffortLevel::High,
596                    description: "Deep adaptive effort".to_string(),
597                },
598                ReasoningEffortPreset {
599                    effort: ReasoningEffortLevel::XHigh,
600                    description: "Recommended Opus 4.8 effort for coding and agentic work".to_string(),
601                },
602                ReasoningEffortPreset {
603                    effort: ReasoningEffortLevel::Max,
604                    description: "Maximum adaptive effort for intelligence-demanding tasks"
605                        .to_string(),
606                },
607            ],
608            is_default: false,
609            upgrade: None,
610            show_in_picker: true,
611            supported_in_api: true,
612            context_window: Some(1_000_000),
613        },
614        ModelPreset {
615            id: "claude-sonnet-4-6".to_string(),
616            model: "claude-sonnet-4-6".to_string(),
617            display_name: "Claude Sonnet 4.6".to_string(),
618            description:
619                "The best combination of speed and intelligence. Supports extended thinking and adaptive thinking with 1M context."
620                    .to_string(),
621            provider: Provider::Anthropic,
622            default_reasoning_effort: ReasoningEffortLevel::High,
623            supported_reasoning_efforts: vec![
624                ReasoningEffortPreset {
625                    effort: ReasoningEffortLevel::Low,
626                    description: "Fast adaptive effort".to_string(),
627                },
628                ReasoningEffortPreset {
629                    effort: ReasoningEffortLevel::Medium,
630                    description: "Balanced adaptive effort".to_string(),
631                },
632                ReasoningEffortPreset {
633                    effort: ReasoningEffortLevel::High,
634                    description: "Default adaptive effort".to_string(),
635                },
636                ReasoningEffortPreset {
637                    effort: ReasoningEffortLevel::Max,
638                    description: "Maximum adaptive effort".to_string(),
639                },
640            ],
641            is_default: false,
642            upgrade: None,
643            show_in_picker: true,
644            supported_in_api: true,
645            context_window: Some(1_000_000),
646        },
647        ModelPreset {
648            id: "claude-haiku-4-5".to_string(),
649            model: "claude-haiku-4-5".to_string(),
650            display_name: "Claude Haiku 4.5".to_string(),
651            description: "The fastest model with near-frontier intelligence. Supports extended thinking with manual budget."
652                .to_string(),
653            provider: Provider::Anthropic,
654            default_reasoning_effort: ReasoningEffortLevel::Medium,
655            supported_reasoning_efforts: Vec::new(),
656            is_default: false,
657            upgrade: None,
658            show_in_picker: true,
659            supported_in_api: true,
660            context_window: Some(200_000),
661        },
662    ]
663}
664
665fn deepseek_presets() -> Vec<ModelPreset> {
666    vec![
667        ModelPreset {
668            id: "deepseek-v4-pro".to_string(),
669            model: "deepseek-v4-pro".to_string(),
670            display_name: "DeepSeek V4 Pro".to_string(),
671            description: "High-performance reasoning model with advanced thinking capabilities"
672                .to_string(),
673            provider: Provider::DeepSeek,
674            default_reasoning_effort: ReasoningEffortLevel::High,
675            supported_reasoning_efforts: vec![
676                ReasoningEffortPreset {
677                    effort: ReasoningEffortLevel::High,
678                    description: "Balanced".to_string(),
679                },
680                ReasoningEffortPreset {
681                    effort: ReasoningEffortLevel::Max,
682                    description: "Maximum thinking".to_string(),
683                },
684            ],
685            is_default: true,
686            upgrade: None,
687            show_in_picker: true,
688            supported_in_api: true,
689            context_window: Some(1_000_000),
690        },
691        ModelPreset {
692            id: "deepseek-v4-flash".to_string(),
693            model: "deepseek-v4-flash".to_string(),
694            display_name: "DeepSeek V4 Flash".to_string(),
695            description: "Fast inference model for cost-effective reasoning tasks".to_string(),
696            provider: Provider::DeepSeek,
697            default_reasoning_effort: ReasoningEffortLevel::High,
698            supported_reasoning_efforts: vec![
699                ReasoningEffortPreset {
700                    effort: ReasoningEffortLevel::High,
701                    description: "Balanced".to_string(),
702                },
703                ReasoningEffortPreset {
704                    effort: ReasoningEffortLevel::Max,
705                    description: "Maximum thinking".to_string(),
706                },
707            ],
708            is_default: false,
709            upgrade: None,
710            show_in_picker: true,
711            supported_in_api: true,
712            context_window: Some(1_000_000),
713        },
714    ]
715}
716
717fn zai_presets() -> Vec<ModelPreset> {
718    vec![ModelPreset {
719        id: "glm-5.1".to_string(),
720        model: "glm-5.1".to_string(),
721        display_name: "GLM-5.1".to_string(),
722        description:
723            "Z.ai's next-gen foundation model with improved reasoning and agent capabilities"
724                .to_string(),
725        provider: Provider::ZAI,
726        default_reasoning_effort: ReasoningEffortLevel::Medium,
727        supported_reasoning_efforts: vec![
728            ReasoningEffortPreset {
729                effort: ReasoningEffortLevel::Medium,
730                description: "Balanced".to_string(),
731            },
732            ReasoningEffortPreset {
733                effort: ReasoningEffortLevel::High,
734                description: "Deep thinking".to_string(),
735            },
736        ],
737        is_default: true,
738        upgrade: None,
739        show_in_picker: true,
740        supported_in_api: true,
741        context_window: Some(200_000),
742    }]
743}
744
745fn mistral_presets() -> Vec<ModelPreset> {
746    vec![
747        ModelPreset {
748            id: "mistral-large-2512".to_string(),
749            model: "mistral-large-2512".to_string(),
750            display_name: "Mistral Large 3".to_string(),
751            description:
752                "State-of-the-art open-weight general-purpose multimodal model (41B active, 675B total)".to_string(),
753            provider: Provider::Mistral,
754            default_reasoning_effort: ReasoningEffortLevel::Medium,
755            supported_reasoning_efforts: vec![
756                ReasoningEffortPreset {
757                    effort: ReasoningEffortLevel::Medium,
758                    description: "Balanced".to_string(),
759                },
760                ReasoningEffortPreset {
761                    effort: ReasoningEffortLevel::High,
762                    description: "Deep".to_string(),
763                },
764            ],
765            is_default: true,
766            upgrade: None,
767            show_in_picker: true,
768            supported_in_api: true,
769            context_window: Some(256_000),
770        },
771        ModelPreset {
772            id: "mistral-medium-3-5".to_string(),
773            model: "mistral-medium-3-5".to_string(),
774            display_name: "Mistral Medium 3.5".to_string(),
775            description:
776                "Frontier-class multimodal model optimized for agentic and coding use cases (256k context)"
777                    .to_string(),
778            provider: Provider::Mistral,
779            default_reasoning_effort: ReasoningEffortLevel::Medium,
780            supported_reasoning_efforts: vec![
781                ReasoningEffortPreset {
782                    effort: ReasoningEffortLevel::Medium,
783                    description: "Balanced".to_string(),
784                },
785                ReasoningEffortPreset {
786                    effort: ReasoningEffortLevel::High,
787                    description: "Deep".to_string(),
788                },
789            ],
790            is_default: false,
791            upgrade: None,
792            show_in_picker: true,
793            supported_in_api: true,
794            context_window: Some(256_000),
795        },
796        ModelPreset {
797            id: "mistral-small-2603".to_string(),
798            model: "mistral-small-2603".to_string(),
799            display_name: "Mistral Small 4".to_string(),
800            description:
801                "Hybrid model unifying instruct, reasoning, and coding (119B params, 6.5B active)"
802                    .to_string(),
803            provider: Provider::Mistral,
804            default_reasoning_effort: ReasoningEffortLevel::Medium,
805            supported_reasoning_efforts: vec![
806                ReasoningEffortPreset {
807                    effort: ReasoningEffortLevel::Medium,
808                    description: "Balanced".to_string(),
809                },
810                ReasoningEffortPreset {
811                    effort: ReasoningEffortLevel::High,
812                    description: "Deep".to_string(),
813                },
814            ],
815            is_default: false,
816            upgrade: None,
817            show_in_picker: true,
818            supported_in_api: true,
819            context_window: Some(256_000),
820        },
821        ModelPreset {
822            id: "mistral-medium-2508".to_string(),
823            model: "mistral-medium-2508".to_string(),
824            display_name: "Mistral Medium 3.1".to_string(),
825            description: "Frontier-class multimodal model with 256k context".to_string(),
826            provider: Provider::Mistral,
827            default_reasoning_effort: ReasoningEffortLevel::Medium,
828            supported_reasoning_efforts: vec![ReasoningEffortPreset {
829                effort: ReasoningEffortLevel::Medium,
830                description: "Balanced".to_string(),
831            }],
832            is_default: false,
833            upgrade: None,
834            show_in_picker: true,
835            supported_in_api: true,
836            context_window: Some(256_000),
837        },
838        ModelPreset {
839            id: "codestral-2508".to_string(),
840            model: "codestral-2508".to_string(),
841            display_name: "Codestral".to_string(),
842            description: "Cutting-edge language model for code completion".to_string(),
843            provider: Provider::Mistral,
844            default_reasoning_effort: ReasoningEffortLevel::Medium,
845            supported_reasoning_efforts: Vec::new(),
846            is_default: false,
847            upgrade: None,
848            show_in_picker: true,
849            supported_in_api: true,
850            context_window: Some(256_000),
851        },
852    ]
853}
854
855fn minimax_presets() -> Vec<ModelPreset> {
856    vec![ModelPreset {
857        id: "minimax-m3".to_string(),
858        model: "MiniMax-M3".to_string(),
859        display_name: "MiniMax M3".to_string(),
860        description: "Frontier multimodal coding model with 1M context".to_string(),
861        provider: Provider::Minimax,
862        default_reasoning_effort: ReasoningEffortLevel::Medium,
863        supported_reasoning_efforts: vec![
864            ReasoningEffortPreset {
865                effort: ReasoningEffortLevel::Medium,
866                description: "Balanced".to_string(),
867            },
868            ReasoningEffortPreset {
869                effort: ReasoningEffortLevel::High,
870                description: "Deep".to_string(),
871            },
872        ],
873        is_default: true,
874        upgrade: None,
875        show_in_picker: true,
876        supported_in_api: true,
877        context_window: Some(1_000_000),
878    }]
879}
880
881fn openrouter_presets() -> Vec<ModelPreset> {
882    vec![
883        ModelPreset {
884            id: "openrouter/deepseek/deepseek-chat".to_string(),
885            model: "deepseek/deepseek-chat".to_string(),
886            display_name: "DeepSeek V3.2 (OpenRouter)".to_string(),
887            description: "DeepSeek via OpenRouter".to_string(),
888            provider: Provider::OpenRouter,
889            default_reasoning_effort: ReasoningEffortLevel::Medium,
890            supported_reasoning_efforts: vec![ReasoningEffortPreset {
891                effort: ReasoningEffortLevel::Medium,
892                description: "Balanced".to_string(),
893            }],
894            is_default: false,
895            upgrade: None,
896            show_in_picker: true,
897            supported_in_api: true,
898            context_window: Some(128_000),
899        },
900        ModelPreset {
901            id: "openrouter/moonshotai/kimi-k2.6".to_string(),
902            model: "moonshotai/kimi-k2.6".to_string(),
903            display_name: "Kimi K2.6 (OpenRouter)".to_string(),
904            description: "Kimi K2.6 multimodal agentic model via OpenRouter".to_string(),
905            provider: Provider::OpenRouter,
906            default_reasoning_effort: ReasoningEffortLevel::Medium,
907            supported_reasoning_efforts: vec![ReasoningEffortPreset {
908                effort: ReasoningEffortLevel::Medium,
909                description: "Balanced".to_string(),
910            }],
911            is_default: false,
912            upgrade: None,
913            show_in_picker: true,
914            supported_in_api: true,
915            context_window: Some(262_144),
916        },
917        ModelPreset {
918            id: "openrouter/moonshotai/kimi-k2.7-code".to_string(),
919            model: "moonshotai/kimi-k2.7-code".to_string(),
920            display_name: "Kimi K2.7 Code (OpenRouter)".to_string(),
921            description: "Kimi K2.7 Code most capable coding model with long-horizon coding breakthrough via OpenRouter".to_string(),
922            provider: Provider::OpenRouter,
923            default_reasoning_effort: ReasoningEffortLevel::Medium,
924            supported_reasoning_efforts: vec![ReasoningEffortPreset {
925                effort: ReasoningEffortLevel::Medium,
926                description: "Balanced".to_string(),
927            }],
928            is_default: false,
929            upgrade: None,
930            show_in_picker: true,
931            supported_in_api: true,
932            context_window: Some(262_144),
933        },
934        ModelPreset {
935            id: "openrouter/qwen/qwen3.7-max".to_string(),
936            model: "qwen/qwen3.7-max".to_string(),
937            display_name: "Qwen3.7 Max (OpenRouter)".to_string(),
938            description: "Qwen3.7 Max flagship model for coding and agentic workloads via OpenRouter".to_string(),
939            provider: Provider::OpenRouter,
940            default_reasoning_effort: ReasoningEffortLevel::Medium,
941            supported_reasoning_efforts: vec![ReasoningEffortPreset {
942                effort: ReasoningEffortLevel::Medium,
943                description: "Balanced".to_string(),
944            }],
945            is_default: false,
946            upgrade: None,
947            show_in_picker: true,
948            supported_in_api: true,
949            context_window: Some(1_000_000),
950        },
951        ModelPreset {
952            id: "openrouter/tencent/hy3-preview".to_string(),
953            model: "tencent/hy3-preview".to_string(),
954            display_name: "Hy3 Preview (OpenRouter)".to_string(),
955            description: "Tencent Hy3 high-efficiency MoE model with configurable reasoning via OpenRouter".to_string(),
956            provider: Provider::OpenRouter,
957            default_reasoning_effort: ReasoningEffortLevel::Medium,
958            supported_reasoning_efforts: vec![
959                ReasoningEffortPreset {
960                    effort: ReasoningEffortLevel::Low,
961                    description: "Fast".to_string(),
962                },
963                ReasoningEffortPreset {
964                    effort: ReasoningEffortLevel::Medium,
965                    description: "Balanced".to_string(),
966                },
967                ReasoningEffortPreset {
968                    effort: ReasoningEffortLevel::High,
969                    description: "Deep".to_string(),
970                },
971            ],
972            is_default: false,
973            upgrade: None,
974            show_in_picker: true,
975            supported_in_api: true,
976            context_window: Some(262_144),
977        },
978        ModelPreset {
979            id: "openrouter/x-ai/grok-build-0.1".to_string(),
980            model: "x-ai/grok-build-0.1".to_string(),
981            display_name: "Grok Build 0.1 (OpenRouter)".to_string(),
982            description: "xAI Grok Build 0.1 coding model for agentic software engineering via OpenRouter".to_string(),
983            provider: Provider::OpenRouter,
984            default_reasoning_effort: ReasoningEffortLevel::Medium,
985            supported_reasoning_efforts: vec![ReasoningEffortPreset {
986                effort: ReasoningEffortLevel::Medium,
987                description: "Balanced".to_string(),
988            }],
989            is_default: false,
990            upgrade: None,
991            show_in_picker: true,
992            supported_in_api: true,
993            context_window: Some(256_000),
994        },
995        ModelPreset {
996            id: "openrouter/xiaomi/mimo-v2.5".to_string(),
997            model: "xiaomi/mimo-v2.5".to_string(),
998            display_name: "MiMo-V2.5 (OpenRouter)".to_string(),
999            description: "Xiaomi MiMo-V2.5 omnimodal agentic model for complex software engineering via OpenRouter".to_string(),
1000            provider: Provider::OpenRouter,
1001            default_reasoning_effort: ReasoningEffortLevel::Medium,
1002            supported_reasoning_efforts: vec![ReasoningEffortPreset {
1003                effort: ReasoningEffortLevel::Medium,
1004                description: "Balanced".to_string(),
1005            }],
1006            is_default: false,
1007            upgrade: None,
1008            show_in_picker: true,
1009            supported_in_api: true,
1010            context_window: Some(1_000_000),
1011        },
1012        ModelPreset {
1013            id: "openrouter/xiaomi/mimo-v2.5-pro".to_string(),
1014            model: "xiaomi/mimo-v2.5-pro".to_string(),
1015            display_name: "MiMo-V2.5-Pro (OpenRouter)".to_string(),
1016            description: "Xiaomi MiMo-V2.5-Pro flagship agentic model for complex software engineering via OpenRouter".to_string(),
1017            provider: Provider::OpenRouter,
1018            default_reasoning_effort: ReasoningEffortLevel::Medium,
1019            supported_reasoning_efforts: vec![ReasoningEffortPreset {
1020                effort: ReasoningEffortLevel::Medium,
1021                description: "Balanced".to_string(),
1022            }],
1023            is_default: true,
1024            upgrade: None,
1025            show_in_picker: true,
1026            supported_in_api: true,
1027            context_window: Some(1_000_000),
1028        },
1029        ModelPreset {
1030            id: "openrouter/poolside/laguna-m.1:free".to_string(),
1031            model: "poolside/laguna-m.1:free".to_string(),
1032            display_name: "Laguna M.1 free (OpenRouter)".to_string(),
1033            description: "Poolside Laguna M.1 flagship free coding agent model via OpenRouter".to_string(),
1034            provider: Provider::OpenRouter,
1035            default_reasoning_effort: ReasoningEffortLevel::Medium,
1036            supported_reasoning_efforts: vec![ReasoningEffortPreset {
1037                effort: ReasoningEffortLevel::Medium,
1038                description: "Balanced".to_string(),
1039            }],
1040            is_default: false,
1041            upgrade: None,
1042            show_in_picker: true,
1043            supported_in_api: true,
1044            context_window: Some(262_144),
1045        },
1046    ]
1047}
1048
1049fn ollama_presets() -> Vec<ModelPreset> {
1050    vec![
1051        ModelPreset {
1052            id: "ollama/gpt-oss:20b".to_string(),
1053            model: "gpt-oss:20b".to_string(),
1054            display_name: "GPT-OSS 20B (Ollama)".to_string(),
1055            description: "Open-weight GPT-OSS served locally".to_string(),
1056            provider: Provider::Ollama,
1057            default_reasoning_effort: ReasoningEffortLevel::Medium,
1058            supported_reasoning_efforts: vec![ReasoningEffortPreset {
1059                effort: ReasoningEffortLevel::Medium,
1060                description: "Balanced".to_string(),
1061            }],
1062            is_default: true,
1063            upgrade: None,
1064            show_in_picker: true,
1065            supported_in_api: true,
1066            context_window: Some(96_000),
1067        },
1068        ModelPreset {
1069            id: "ollama/deepseek-v4-flash:cloud".to_string(),
1070            model: "deepseek-v4-flash:cloud".to_string(),
1071            display_name: "DeepSeek V4 Flash (Ollama)".to_string(),
1072            description: "Fast inference DeepSeek V4 Flash model via Ollama Cloud".to_string(),
1073            provider: Provider::Ollama,
1074            default_reasoning_effort: ReasoningEffortLevel::Medium,
1075            supported_reasoning_efforts: vec![ReasoningEffortPreset {
1076                effort: ReasoningEffortLevel::Medium,
1077                description: "Balanced".to_string(),
1078            }],
1079            is_default: false,
1080            upgrade: None,
1081            show_in_picker: true,
1082            supported_in_api: true,
1083            context_window: Some(128_000),
1084        },
1085        ModelPreset {
1086            id: "ollama/deepseek-v4-pro:cloud".to_string(),
1087            model: "deepseek-v4-pro:cloud".to_string(),
1088            display_name: "DeepSeek V4 Pro (Ollama)".to_string(),
1089            description: "High-performance DeepSeek V4 Pro model via Ollama Cloud".to_string(),
1090            provider: Provider::Ollama,
1091            default_reasoning_effort: ReasoningEffortLevel::Medium,
1092            supported_reasoning_efforts: vec![ReasoningEffortPreset {
1093                effort: ReasoningEffortLevel::Medium,
1094                description: "Balanced".to_string(),
1095            }],
1096            is_default: false,
1097            upgrade: None,
1098            show_in_picker: true,
1099            supported_in_api: true,
1100            context_window: Some(128_000),
1101        },
1102        ModelPreset {
1103            id: "ollama/nemotron-3-ultra:cloud".to_string(),
1104            model: "nemotron-3-ultra:cloud".to_string(),
1105            display_name: "Nemotron 3 Ultra (Ollama)".to_string(),
1106            description: "NVIDIA Nemotron 3 Ultra 550B for high-throughput reasoning and long-running agent workflows via Ollama Cloud".to_string(),
1107            provider: Provider::Ollama,
1108            default_reasoning_effort: ReasoningEffortLevel::Medium,
1109            supported_reasoning_efforts: vec![
1110                ReasoningEffortPreset {
1111                    effort: ReasoningEffortLevel::Medium,
1112                    description: "Balanced".to_string(),
1113                },
1114                ReasoningEffortPreset {
1115                    effort: ReasoningEffortLevel::High,
1116                    description: "Deep".to_string(),
1117                },
1118            ],
1119            is_default: false,
1120            upgrade: None,
1121            show_in_picker: true,
1122            supported_in_api: true,
1123            context_window: Some(256_000),
1124        },
1125        ModelPreset {
1126            id: "ollama/gemma4".to_string(),
1127            model: "gemma4".to_string(),
1128            display_name: "Gemma 4 (Ollama)".to_string(),
1129            description: "Google Gemma 4 for reasoning, agentic workflows, coding, and multimodal understanding".to_string(),
1130            provider: Provider::Ollama,
1131            default_reasoning_effort: ReasoningEffortLevel::Medium,
1132            supported_reasoning_efforts: vec![ReasoningEffortPreset {
1133                effort: ReasoningEffortLevel::Medium,
1134                description: "Balanced".to_string(),
1135            }],
1136            is_default: false,
1137            upgrade: None,
1138            show_in_picker: true,
1139            supported_in_api: true,
1140            context_window: Some(128_000),
1141        },
1142        ModelPreset {
1143            id: "ollama/minimax-m3:cloud".to_string(),
1144            model: "minimax-m3:cloud".to_string(),
1145            display_name: "MiniMax-M3 (Ollama)".to_string(),
1146            description: "Cloud-hosted MiniMax-M3 model via Ollama Cloud".to_string(),
1147            provider: Provider::Ollama,
1148            default_reasoning_effort: ReasoningEffortLevel::Medium,
1149            supported_reasoning_efforts: vec![ReasoningEffortPreset {
1150                effort: ReasoningEffortLevel::Medium,
1151                description: "Balanced".to_string(),
1152            }],
1153            is_default: false,
1154            upgrade: None,
1155            show_in_picker: true,
1156            supported_in_api: true,
1157            context_window: Some(131_072),
1158        },
1159    ]
1160}
1161
1162fn lmstudio_presets() -> Vec<ModelPreset> {
1163    use crate::config::constants::models::lmstudio as lmstudio_models;
1164    vec![
1165        ModelPreset {
1166            id: format!("lmstudio/{}", lmstudio_models::OPENAI_GPT_OSS_20B),
1167            model: lmstudio_models::OPENAI_GPT_OSS_20B.to_string(),
1168            display_name: "GPT-OSS 20B (LM Studio)".to_string(),
1169            description: "OpenAI's open-weight GPT-OSS 20B model served locally via LM Studio"
1170                .to_string(),
1171            provider: Provider::LmStudio,
1172            default_reasoning_effort: ReasoningEffortLevel::Medium,
1173            supported_reasoning_efforts: vec![ReasoningEffortPreset {
1174                effort: ReasoningEffortLevel::Medium,
1175                description: "Balanced".to_string(),
1176            }],
1177            is_default: false,
1178            upgrade: None,
1179            show_in_picker: true,
1180            supported_in_api: true,
1181            context_window: Some(131_072),
1182        },
1183        ModelPreset {
1184            id: format!("lmstudio/{}", lmstudio_models::META_LLAMA_31_8B_INSTRUCT),
1185            model: lmstudio_models::META_LLAMA_31_8B_INSTRUCT.to_string(),
1186            display_name: "Llama 3.1 8B (LM Studio)".to_string(),
1187            description: "Meta Llama 3.1 8B Instruct for general-purpose local inference"
1188                .to_string(),
1189            provider: Provider::LmStudio,
1190            default_reasoning_effort: ReasoningEffortLevel::Medium,
1191            supported_reasoning_efforts: vec![ReasoningEffortPreset {
1192                effort: ReasoningEffortLevel::Medium,
1193                description: "Balanced".to_string(),
1194            }],
1195            is_default: false,
1196            upgrade: None,
1197            show_in_picker: true,
1198            supported_in_api: true,
1199            context_window: Some(131_072),
1200        },
1201        ModelPreset {
1202            id: format!("lmstudio/{}", lmstudio_models::GEMMA_3_12B_IT),
1203            model: lmstudio_models::GEMMA_3_12B_IT.to_string(),
1204            display_name: "Gemma 3 12B (LM Studio)".to_string(),
1205            description: "Google Gemma 3 12B IT for local inference".to_string(),
1206            provider: Provider::LmStudio,
1207            default_reasoning_effort: ReasoningEffortLevel::Medium,
1208            supported_reasoning_efforts: vec![ReasoningEffortPreset {
1209                effort: ReasoningEffortLevel::Medium,
1210                description: "Balanced".to_string(),
1211            }],
1212            is_default: false,
1213            upgrade: None,
1214            show_in_picker: true,
1215            supported_in_api: true,
1216            context_window: Some(32_768),
1217        },
1218    ]
1219}
1220
1221fn llamacpp_presets() -> Vec<ModelPreset> {
1222    vec![
1223        ModelPreset {
1224            id: format!("llamacpp/{}", llamacpp_models::GPT_OSS_20B),
1225            model: llamacpp_models::GPT_OSS_20B.to_string(),
1226            display_name: "GPT-OSS 20B (llama.cpp)".to_string(),
1227            description: "OpenAI's open-weight GPT-OSS 20B model served locally through llama.cpp"
1228                .to_string(),
1229            provider: Provider::LlamaCpp,
1230            default_reasoning_effort: ReasoningEffortLevel::Medium,
1231            supported_reasoning_efforts: vec![ReasoningEffortPreset {
1232                effort: ReasoningEffortLevel::Medium,
1233                description: "Balanced".to_string(),
1234            }],
1235            is_default: true,
1236            upgrade: None,
1237            show_in_picker: true,
1238            supported_in_api: true,
1239            context_window: Some(131_072),
1240        },
1241        ModelPreset {
1242            id: format!("llamacpp/{}", llamacpp_models::GEMMA_4_26B_A4B),
1243            model: llamacpp_models::GEMMA_4_26B_A4B.to_string(),
1244            display_name: "Gemma 4 26B A4B (llama.cpp)".to_string(),
1245            description: "Gemma 4 desktop MoE model served through llama.cpp".to_string(),
1246            provider: Provider::LlamaCpp,
1247            default_reasoning_effort: ReasoningEffortLevel::Medium,
1248            supported_reasoning_efforts: vec![ReasoningEffortPreset {
1249                effort: ReasoningEffortLevel::Medium,
1250                description: "Balanced".to_string(),
1251            }],
1252            is_default: false,
1253            upgrade: None,
1254            show_in_picker: true,
1255            supported_in_api: true,
1256            context_window: Some(262_144),
1257        },
1258        ModelPreset {
1259            id: format!("llamacpp/{}", llamacpp_models::GEMMA_4_E4B),
1260            model: llamacpp_models::GEMMA_4_E4B.to_string(),
1261            display_name: "Gemma 4 E4B (llama.cpp)".to_string(),
1262            description: "Tiny-footprint Gemma 4 model served through llama.cpp".to_string(),
1263            provider: Provider::LlamaCpp,
1264            default_reasoning_effort: ReasoningEffortLevel::Low,
1265            supported_reasoning_efforts: vec![ReasoningEffortPreset {
1266                effort: ReasoningEffortLevel::Low,
1267                description: "Fast".to_string(),
1268            }],
1269            is_default: false,
1270            upgrade: None,
1271            show_in_picker: true,
1272            supported_in_api: true,
1273            context_window: Some(131_072),
1274        },
1275        ModelPreset {
1276            id: format!("llamacpp/{}", llamacpp_models::STEP_3_5_FLASH),
1277            model: llamacpp_models::STEP_3_5_FLASH.to_string(),
1278            display_name: "Step 3.5 Flash (llama.cpp)".to_string(),
1279            description: "StepFun's efficient reasoning model served through llama.cpp".to_string(),
1280            provider: Provider::LlamaCpp,
1281            default_reasoning_effort: ReasoningEffortLevel::Medium,
1282            supported_reasoning_efforts: vec![ReasoningEffortPreset {
1283                effort: ReasoningEffortLevel::Medium,
1284                description: "Balanced".to_string(),
1285            }],
1286            is_default: false,
1287            upgrade: None,
1288            show_in_picker: true,
1289            supported_in_api: true,
1290            context_window: Some(262_144),
1291        },
1292    ]
1293}
1294
1295fn opencode_zen_presets() -> Vec<ModelPreset> {
1296    vec![ModelPreset {
1297        id: "opencode/gpt-5.4".to_string(),
1298        model: "gpt-5.4".to_string(),
1299        display_name: "GPT-5.4 (OpenCode Zen)".to_string(),
1300        description: "OpenCode Zen gateway — curated, benchmarked models at cost".to_string(),
1301        provider: Provider::OpenCodeZen,
1302        default_reasoning_effort: ReasoningEffortLevel::Medium,
1303        supported_reasoning_efforts: vec![ReasoningEffortPreset {
1304            effort: ReasoningEffortLevel::Medium,
1305            description: "Balanced".to_string(),
1306        }],
1307        is_default: true,
1308        upgrade: None,
1309        show_in_picker: true,
1310        supported_in_api: true,
1311        context_window: Some(1_050_000),
1312    }]
1313}
1314
1315fn opencode_go_presets() -> Vec<ModelPreset> {
1316    vec![ModelPreset {
1317        id: "opencode-go/glm-5.1".to_string(),
1318        model: "glm-5.1".to_string(),
1319        display_name: "GLM-5.1 (OpenCode Go)".to_string(),
1320        description: "OpenCode Go — affordable subscription for open coding models".to_string(),
1321        provider: Provider::OpenCodeGo,
1322        default_reasoning_effort: ReasoningEffortLevel::Medium,
1323        supported_reasoning_efforts: vec![ReasoningEffortPreset {
1324            effort: ReasoningEffortLevel::Medium,
1325            description: "Balanced".to_string(),
1326        }],
1327        is_default: true,
1328        upgrade: None,
1329        show_in_picker: true,
1330        supported_in_api: true,
1331        context_window: Some(256_000),
1332    }]
1333}
1334
1335fn poolside_presets() -> Vec<ModelPreset> {
1336    vec![
1337        ModelPreset {
1338            id: poolside_models::LAGUNA_M1.to_string(),
1339            model: poolside_models::LAGUNA_M1.to_string(),
1340            display_name: "Laguna M.1".to_string(),
1341            description:
1342                "Poolside's flagship MoE coding agent model optimized for multi-step agentic tasks, tool use, and validation (128K context)"
1343                    .to_string(),
1344            provider: Provider::Poolside,
1345            default_reasoning_effort: ReasoningEffortLevel::Medium,
1346            supported_reasoning_efforts: Vec::new(),
1347            is_default: true,
1348            upgrade: None,
1349            show_in_picker: true,
1350            supported_in_api: true,
1351            context_window: Some(131_072),
1352        },
1353        ModelPreset {
1354            id: poolside_models::LAGUNA_XS2.to_string(),
1355            model: poolside_models::LAGUNA_XS2.to_string(),
1356            display_name: "Laguna XS.2".to_string(),
1357            description:
1358                "Poolside's efficient MoE coding agent model optimized for fast agentic coding (128K context)"
1359                    .to_string(),
1360            provider: Provider::Poolside,
1361            default_reasoning_effort: ReasoningEffortLevel::Medium,
1362            supported_reasoning_efforts: Vec::new(),
1363            is_default: false,
1364            upgrade: None,
1365            show_in_picker: true,
1366            supported_in_api: true,
1367            context_window: Some(131_072),
1368        },
1369    ]
1370}
1371
1372fn mimo_presets() -> Vec<ModelPreset> {
1373    vec![
1374        ModelPreset {
1375            id: mimo_models::MIMO_V2_5_PRO.to_string(),
1376            model: mimo_models::MIMO_V2_5_PRO.to_string(),
1377            display_name: "MiMo V2.5 Pro".to_string(),
1378            description:
1379                "Xiaomi's flagship reasoning model with advanced capabilities (1M context)"
1380                    .to_string(),
1381            provider: Provider::MiMo,
1382            default_reasoning_effort: ReasoningEffortLevel::Medium,
1383            supported_reasoning_efforts: vec![ReasoningEffortPreset {
1384                effort: ReasoningEffortLevel::Medium,
1385                description: "Balanced".to_string(),
1386            }],
1387            is_default: true,
1388            upgrade: None,
1389            show_in_picker: true,
1390            supported_in_api: true,
1391            context_window: Some(1_048_576),
1392        },
1393        ModelPreset {
1394            id: mimo_models::MIMO_V2_5.to_string(),
1395            model: mimo_models::MIMO_V2_5.to_string(),
1396            display_name: "MiMo V2.5".to_string(),
1397            description: "Xiaomi's general-purpose model with strong reasoning (1M context)"
1398                .to_string(),
1399            provider: Provider::MiMo,
1400            default_reasoning_effort: ReasoningEffortLevel::Medium,
1401            supported_reasoning_efforts: vec![ReasoningEffortPreset {
1402                effort: ReasoningEffortLevel::Medium,
1403                description: "Balanced".to_string(),
1404            }],
1405            is_default: false,
1406            upgrade: None,
1407            show_in_picker: true,
1408            supported_in_api: true,
1409            context_window: Some(1_048_576),
1410        },
1411    ]
1412}
1413
1414fn qwen_presets() -> Vec<ModelPreset> {
1415    vec![
1416        ModelPreset {
1417            id: qwen_models::DEEPSEEK_V4_FLASH.to_string(),
1418            model: qwen_models::DEEPSEEK_V4_FLASH.to_string(),
1419            display_name: "DeepSeek V4 Flash (Qwen)".to_string(),
1420            description:
1421                "DeepSeek V4 Flash fast inference model served through Qwen Cloud API (1M context)"
1422                    .to_string(),
1423            provider: Provider::Qwen,
1424            default_reasoning_effort: ReasoningEffortLevel::Low,
1425            supported_reasoning_efforts: vec![ReasoningEffortPreset {
1426                effort: ReasoningEffortLevel::Low,
1427                description: "Fast".to_string(),
1428            }],
1429            is_default: false,
1430            upgrade: None,
1431            show_in_picker: true,
1432            supported_in_api: true,
1433            context_window: Some(1_048_576),
1434        },
1435        ModelPreset {
1436            id: qwen_models::DEEPSEEK_V4_PRO.to_string(),
1437            model: qwen_models::DEEPSEEK_V4_PRO.to_string(),
1438            display_name: "DeepSeek V4 Pro (Qwen)".to_string(),
1439            description:
1440                "DeepSeek V4 Pro high-performance reasoning model served through Qwen Cloud API (1M context)"
1441                    .to_string(),
1442            provider: Provider::Qwen,
1443            default_reasoning_effort: ReasoningEffortLevel::Medium,
1444            supported_reasoning_efforts: vec![ReasoningEffortPreset {
1445                effort: ReasoningEffortLevel::Medium,
1446                description: "Balanced".to_string(),
1447            }],
1448            is_default: false,
1449            upgrade: None,
1450            show_in_picker: true,
1451            supported_in_api: true,
1452            context_window: Some(1_048_576),
1453        },
1454        ModelPreset {
1455            id: qwen_models::GLM_5_1.to_string(),
1456            model: qwen_models::GLM_5_1.to_string(),
1457            display_name: "GLM-5.1 (Qwen)".to_string(),
1458            description:
1459                "Z.AI GLM-5.1 next-gen foundation model served through Qwen Cloud API"
1460                    .to_string(),
1461            provider: Provider::Qwen,
1462            default_reasoning_effort: ReasoningEffortLevel::Medium,
1463            supported_reasoning_efforts: vec![ReasoningEffortPreset {
1464                effort: ReasoningEffortLevel::Medium,
1465                description: "Balanced".to_string(),
1466            }],
1467            is_default: false,
1468            upgrade: None,
1469            show_in_picker: true,
1470            supported_in_api: true,
1471            context_window: Some(131_072),
1472        },
1473    ]
1474}
1475
1476fn stepfun_presets() -> Vec<ModelPreset> {
1477    vec![ModelPreset {
1478        id: stepfun_models::STEP_3_7_FLASH.to_string(),
1479        model: stepfun_models::STEP_3_7_FLASH.to_string(),
1480        display_name: "Step 3.7 Flash".to_string(),
1481        description:
1482            "StepFun's flagship multimodal reasoning model with 256K context and tool calling."
1483                .to_string(),
1484        provider: Provider::StepFun,
1485        default_reasoning_effort: ReasoningEffortLevel::Medium,
1486        supported_reasoning_efforts: vec![
1487            reasoning_preset(ReasoningEffortLevel::Low, "Fast"),
1488            reasoning_preset(ReasoningEffortLevel::Medium, "Balanced"),
1489            reasoning_preset(ReasoningEffortLevel::High, "Deep"),
1490        ],
1491        is_default: true,
1492        upgrade: None,
1493        show_in_picker: true,
1494        supported_in_api: true,
1495        context_window: Some(262_144),
1496    }]
1497}
1498
1499fn evolink_presets() -> Vec<ModelPreset> {
1500    vec![
1501        ModelPreset {
1502            id: "evolink/gpt-5.2".to_string(),
1503            model: evolink_models::GPT_5_2.to_string(),
1504            display_name: "GPT-5.2 (Evolink)".to_string(),
1505            description: "GPT-5.2 served through the Evolink OpenAI-compatible gateway."
1506                .to_string(),
1507            provider: Provider::Evolink,
1508            default_reasoning_effort: ReasoningEffortLevel::Medium,
1509            supported_reasoning_efforts: vec![reasoning_preset(
1510                ReasoningEffortLevel::Medium,
1511                "Balanced",
1512            )],
1513            is_default: true,
1514            upgrade: None,
1515            show_in_picker: true,
1516            supported_in_api: true,
1517            context_window: Some(400_000),
1518        },
1519        ModelPreset {
1520            id: "evolink/gpt-5.5".to_string(),
1521            model: evolink_models::GPT_5_5.to_string(),
1522            display_name: "GPT-5.5 (Evolink)".to_string(),
1523            description: "GPT-5.5 flagship model served through the Evolink gateway.".to_string(),
1524            provider: Provider::Evolink,
1525            default_reasoning_effort: ReasoningEffortLevel::Medium,
1526            supported_reasoning_efforts: vec![reasoning_preset(
1527                ReasoningEffortLevel::Medium,
1528                "Balanced",
1529            )],
1530            is_default: false,
1531            upgrade: None,
1532            show_in_picker: true,
1533            supported_in_api: true,
1534            context_window: Some(400_000),
1535        },
1536        ModelPreset {
1537            id: "evolink/deepseek-v4-pro".to_string(),
1538            model: evolink_models::DEEPSEEK_V4_PRO.to_string(),
1539            display_name: "DeepSeek V4 Pro (Evolink)".to_string(),
1540            description: "DeepSeek V4 Pro reasoning model served through the Evolink gateway."
1541                .to_string(),
1542            provider: Provider::Evolink,
1543            default_reasoning_effort: ReasoningEffortLevel::Medium,
1544            supported_reasoning_efforts: vec![
1545                reasoning_preset(ReasoningEffortLevel::Low, "Fast"),
1546                reasoning_preset(ReasoningEffortLevel::Medium, "Balanced"),
1547                reasoning_preset(ReasoningEffortLevel::High, "Deep"),
1548            ],
1549            is_default: false,
1550            upgrade: None,
1551            show_in_picker: true,
1552            supported_in_api: true,
1553            context_window: Some(163_840),
1554        },
1555        ModelPreset {
1556            id: "evolink/deepseek-v4-flash".to_string(),
1557            model: evolink_models::DEEPSEEK_V4_FLASH.to_string(),
1558            display_name: "DeepSeek V4 Flash (Evolink)".to_string(),
1559            description:
1560                "DeepSeek V4 Flash fast inference model served through the Evolink gateway."
1561                    .to_string(),
1562            provider: Provider::Evolink,
1563            default_reasoning_effort: ReasoningEffortLevel::Medium,
1564            supported_reasoning_efforts: vec![
1565                reasoning_preset(ReasoningEffortLevel::Low, "Fast"),
1566                reasoning_preset(ReasoningEffortLevel::Medium, "Balanced"),
1567                reasoning_preset(ReasoningEffortLevel::High, "Deep"),
1568            ],
1569            is_default: false,
1570            upgrade: None,
1571            show_in_picker: true,
1572            supported_in_api: true,
1573            context_window: Some(1_000_000),
1574        },
1575        ModelPreset {
1576            id: "evolink/doubao-seed-2.0-pro".to_string(),
1577            model: evolink_models::DOUBAO_SEED_2_0_PRO.to_string(),
1578            display_name: "Doubao Seed 2.0 Pro (Evolink)".to_string(),
1579            description: "Doubao Seed 2.0 Pro served through the Evolink gateway.".to_string(),
1580            provider: Provider::Evolink,
1581            default_reasoning_effort: ReasoningEffortLevel::Medium,
1582            supported_reasoning_efforts: vec![
1583                reasoning_preset(ReasoningEffortLevel::Low, "Fast"),
1584                reasoning_preset(ReasoningEffortLevel::Medium, "Balanced"),
1585                reasoning_preset(ReasoningEffortLevel::High, "Deep"),
1586            ],
1587            is_default: false,
1588            upgrade: None,
1589            show_in_picker: true,
1590            supported_in_api: true,
1591            context_window: Some(262_144),
1592        },
1593        ModelPreset {
1594            id: "evolink/gemini-3.1-pro-preview".to_string(),
1595            model: evolink_models::GEMINI_3_1_PRO.to_string(),
1596            display_name: "Gemini 3.1 Pro (Evolink)".to_string(),
1597            description: "Gemini 3.1 Pro served through the Evolink gateway via OpenAI SDK format."
1598                .to_string(),
1599            provider: Provider::Evolink,
1600            default_reasoning_effort: ReasoningEffortLevel::Medium,
1601            supported_reasoning_efforts: vec![reasoning_preset(
1602                ReasoningEffortLevel::Medium,
1603                "Balanced",
1604            )],
1605            is_default: false,
1606            upgrade: None,
1607            show_in_picker: true,
1608            supported_in_api: true,
1609            context_window: Some(1_000_000),
1610        },
1611        ModelPreset {
1612            id: "evolink/gemini-3.5-flash".to_string(),
1613            model: evolink_models::GEMINI_3_5_FLASH.to_string(),
1614            display_name: "Gemini 3.5 Flash (Evolink)".to_string(),
1615            description:
1616                "Gemini 3.5 Flash served through the Evolink gateway via OpenAI SDK format."
1617                    .to_string(),
1618            provider: Provider::Evolink,
1619            default_reasoning_effort: ReasoningEffortLevel::Medium,
1620            supported_reasoning_efforts: vec![reasoning_preset(
1621                ReasoningEffortLevel::Medium,
1622                "Balanced",
1623            )],
1624            is_default: false,
1625            upgrade: None,
1626            show_in_picker: true,
1627            supported_in_api: true,
1628            context_window: Some(1_000_000),
1629        },
1630        ModelPreset {
1631            id: "evolink/MiniMax-M3".to_string(),
1632            model: evolink_models::MINIMAX_M3.to_string(),
1633            display_name: "MiniMax-M3 (Evolink)".to_string(),
1634            description: "MiniMax-M3 frontier multimodal model served through the Evolink gateway."
1635                .to_string(),
1636            provider: Provider::Evolink,
1637            default_reasoning_effort: ReasoningEffortLevel::Medium,
1638            supported_reasoning_efforts: vec![reasoning_preset(
1639                ReasoningEffortLevel::Medium,
1640                "Balanced",
1641            )],
1642            is_default: false,
1643            upgrade: None,
1644            show_in_picker: true,
1645            supported_in_api: true,
1646            context_window: Some(1_000_000),
1647        },
1648        ModelPreset {
1649            id: "evolink/claude-sonnet-4-6".to_string(),
1650            model: evolink_models::CLAUDE_SONNET_4_6.to_string(),
1651            display_name: "Claude Sonnet 4.6 (Evolink)".to_string(),
1652            description: "Claude Sonnet 4.6 served through Evolink via Anthropic Messages API."
1653                .to_string(),
1654            provider: Provider::Evolink,
1655            default_reasoning_effort: ReasoningEffortLevel::Medium,
1656            supported_reasoning_efforts: vec![reasoning_preset(
1657                ReasoningEffortLevel::Medium,
1658                "Balanced",
1659            )],
1660            is_default: false,
1661            upgrade: None,
1662            show_in_picker: true,
1663            supported_in_api: true,
1664            context_window: Some(200_000),
1665        },
1666        ModelPreset {
1667            id: "evolink/claude-opus-4-8".to_string(),
1668            model: evolink_models::CLAUDE_OPUS_4_8.to_string(),
1669            display_name: "Claude Opus 4.8 (Evolink)".to_string(),
1670            description: "Claude Opus 4.8 served through Evolink via Anthropic Messages API."
1671                .to_string(),
1672            provider: Provider::Evolink,
1673            default_reasoning_effort: ReasoningEffortLevel::High,
1674            supported_reasoning_efforts: vec![
1675                reasoning_preset(ReasoningEffortLevel::Medium, "Balanced"),
1676                reasoning_preset(ReasoningEffortLevel::High, "Deep"),
1677            ],
1678            is_default: false,
1679            upgrade: None,
1680            show_in_picker: true,
1681            supported_in_api: true,
1682            context_window: Some(200_000),
1683        },
1684        ModelPreset {
1685            id: "evolink/claude-haiku-4-5-20251001".to_string(),
1686            model: evolink_models::CLAUDE_HAIKU_4_5.to_string(),
1687            display_name: "Claude Haiku 4.5 (Evolink)".to_string(),
1688            description:
1689                "Claude Haiku 4.5 fast model served through Evolink via Anthropic Messages API."
1690                    .to_string(),
1691            provider: Provider::Evolink,
1692            default_reasoning_effort: ReasoningEffortLevel::Low,
1693            supported_reasoning_efforts: vec![
1694                reasoning_preset(ReasoningEffortLevel::Low, "Fast"),
1695                reasoning_preset(ReasoningEffortLevel::Medium, "Balanced"),
1696            ],
1697            is_default: false,
1698            upgrade: None,
1699            show_in_picker: true,
1700            supported_in_api: true,
1701            context_window: Some(200_000),
1702        },
1703    ]
1704}
1705
1706fn moonshot_presets() -> Vec<ModelPreset> {
1707    vec![
1708        ModelPreset {
1709            id: "kimi-k2.7-code".to_string(),
1710            model: "kimi-k2.7-code".to_string(),
1711            display_name: "Kimi K2.7 Code (Moonshot)".to_string(),
1712            description:
1713                "Moonshot's most capable coding model with long-horizon coding breakthrough."
1714                    .to_string(),
1715            provider: Provider::Moonshot,
1716            default_reasoning_effort: ReasoningEffortLevel::Medium,
1717            supported_reasoning_efforts: vec![reasoning_preset(
1718                ReasoningEffortLevel::Medium,
1719                "Balanced",
1720            )],
1721            is_default: true,
1722            upgrade: None,
1723            show_in_picker: true,
1724            supported_in_api: true,
1725            context_window: Some(256_000),
1726        },
1727        ModelPreset {
1728            id: "kimi-k2.6".to_string(),
1729            model: "kimi-k2.6".to_string(),
1730            display_name: "Kimi K2.6 (Moonshot)".to_string(),
1731            description: "Moonshot's previous flagship coding and agent model.".to_string(),
1732            provider: Provider::Moonshot,
1733            default_reasoning_effort: ReasoningEffortLevel::Medium,
1734            supported_reasoning_efforts: vec![reasoning_preset(
1735                ReasoningEffortLevel::Medium,
1736                "Balanced",
1737            )],
1738            is_default: false,
1739            upgrade: None,
1740            show_in_picker: true,
1741            supported_in_api: true,
1742            context_window: Some(256_000),
1743        },
1744    ]
1745}
1746
1747fn huggingface_presets() -> Vec<ModelPreset> {
1748    vec![
1749        ModelPreset {
1750            id: "huggingface/deepseek-v4-flash".to_string(),
1751            model: "deepseek-ai/DeepSeek-V4-Flash:novita".to_string(),
1752            display_name: "DeepSeek V4 Flash (HF/Novita)".to_string(),
1753            description:
1754                "Fast inference model for cost-effective reasoning (1M context, 158B params)"
1755                    .to_string(),
1756            provider: Provider::HuggingFace,
1757            default_reasoning_effort: ReasoningEffortLevel::High,
1758            supported_reasoning_efforts: vec![
1759                ReasoningEffortPreset {
1760                    effort: ReasoningEffortLevel::High,
1761                    description: "Balanced".to_string(),
1762                },
1763                ReasoningEffortPreset {
1764                    effort: ReasoningEffortLevel::Max,
1765                    description: "Maximum thinking".to_string(),
1766                },
1767            ],
1768            is_default: false,
1769            upgrade: None,
1770            show_in_picker: true,
1771            supported_in_api: true,
1772            context_window: Some(1_000_000),
1773        },
1774        ModelPreset {
1775            id: "huggingface/deepseek-v4-pro".to_string(),
1776            model: "deepseek-ai/DeepSeek-V4-Pro:together".to_string(),
1777            display_name: "DeepSeek V4 Pro (HF/Together)".to_string(),
1778            description:
1779                "High-performance reasoning model with advanced thinking capabilities (1M context, 1.6T params)"
1780                    .to_string(),
1781            provider: Provider::HuggingFace,
1782            default_reasoning_effort: ReasoningEffortLevel::High,
1783            supported_reasoning_efforts: vec![
1784                ReasoningEffortPreset {
1785                    effort: ReasoningEffortLevel::High,
1786                    description: "Balanced".to_string(),
1787                },
1788                ReasoningEffortPreset {
1789                    effort: ReasoningEffortLevel::Max,
1790                    description: "Maximum thinking".to_string(),
1791                },
1792            ],
1793            is_default: false,
1794            upgrade: None,
1795            show_in_picker: true,
1796            supported_in_api: true,
1797            context_window: Some(1_000_000),
1798        },
1799        ModelPreset {
1800            id: "huggingface/nvidia-nemotron-3-ultra".to_string(),
1801            model: "nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B-NVFP4:together".to_string(),
1802            display_name: "NVIDIA-Nemotron-3-Ultra-550B (HF/Together)".to_string(),
1803            description:
1804                "NVIDIA Nemotron 3 Ultra 550B-A55B-NVFP4 via Together inference provider"
1805                    .to_string(),
1806            provider: Provider::HuggingFace,
1807            default_reasoning_effort: ReasoningEffortLevel::High,
1808            supported_reasoning_efforts: vec![
1809                ReasoningEffortPreset {
1810                    effort: ReasoningEffortLevel::High,
1811                    description: "Balanced".to_string(),
1812                },
1813                ReasoningEffortPreset {
1814                    effort: ReasoningEffortLevel::Max,
1815                    description: "Maximum thinking".to_string(),
1816                },
1817            ],
1818            is_default: false,
1819            upgrade: None,
1820            show_in_picker: true,
1821            supported_in_api: true,
1822            context_window: Some(128_000),
1823        },
1824        ModelPreset {
1825            id: "huggingface/minimax-m3".to_string(),
1826            model: "MiniMaxAI/MiniMax-M3:novita".to_string(),
1827            display_name: "MiniMax-M3 (HF/Novita)".to_string(),
1828            description:
1829                "Frontier multimodal coding model with 1M context window via Novita inference provider"
1830                    .to_string(),
1831            provider: Provider::HuggingFace,
1832            default_reasoning_effort: ReasoningEffortLevel::High,
1833            supported_reasoning_efforts: vec![
1834                ReasoningEffortPreset {
1835                    effort: ReasoningEffortLevel::High,
1836                    description: "Balanced".to_string(),
1837                },
1838                ReasoningEffortPreset {
1839                    effort: ReasoningEffortLevel::Max,
1840                    description: "Maximum thinking".to_string(),
1841                },
1842            ],
1843            is_default: false,
1844            upgrade: None,
1845            show_in_picker: true,
1846            supported_in_api: true,
1847            context_window: Some(1_000_000),
1848        },
1849    ]
1850}
1851
1852/// Get all model presets (for testing)
1853#[cfg(test)]
1854pub fn all_model_presets() -> Vec<ModelPreset> {
1855    builtin_model_presets()
1856}
1857
1858#[cfg(test)]
1859mod tests {
1860    use super::*;
1861
1862    #[test]
1863    fn only_one_default_per_provider() {
1864        let presets = builtin_model_presets();
1865        let providers: Vec<Provider> = Provider::all_providers();
1866
1867        for provider in providers {
1868            let default_count = presets
1869                .iter()
1870                .filter(|p| p.provider == provider && p.is_default)
1871                .count();
1872            assert!(
1873                default_count <= 1,
1874                "Provider {:?} has {} defaults, expected 0 or 1",
1875                provider,
1876                default_count
1877            );
1878        }
1879    }
1880
1881    #[test]
1882    fn gemini_presets_exist() {
1883        let presets = gemini_presets();
1884        assert!(!presets.is_empty());
1885        assert!(presets.iter().any(|p| p.id.contains("gemini")));
1886    }
1887
1888    #[test]
1889    fn model_info_converts_to_preset() {
1890        let info = ModelInfo {
1891            slug: "test-model".to_string(),
1892            display_name: "Test Model".to_string(),
1893            description: "A test model".to_string(),
1894            provider: Provider::Gemini,
1895            default_reasoning_level: ReasoningEffortLevel::Medium,
1896            supported_reasoning_levels: vec![],
1897            context_window: Some(128_000),
1898            supports_tool_use: true,
1899            supports_streaming: true,
1900            supports_reasoning: false,
1901            priority: 0,
1902            visibility: "list".to_string(),
1903            supported_in_api: true,
1904            upgrade: None,
1905        };
1906
1907        let preset: ModelPreset = info.into();
1908        assert_eq!(preset.id, "test-model");
1909        assert_eq!(preset.model, "test-model");
1910        assert!(preset.show_in_picker);
1911    }
1912
1913    #[test]
1914    fn openai_codex_presets_default_to_high_reasoning() {
1915        let codex = openai_presets()
1916            .into_iter()
1917            .find(|preset| preset.id == "gpt-5.3-codex")
1918            .expect("gpt-5.3-codex preset");
1919
1920        assert_eq!(codex.default_reasoning_effort, ReasoningEffortLevel::High);
1921    }
1922
1923    #[test]
1924    fn moonshot_presets_exist_and_default_to_kimi_k26() {
1925        let presets = moonshot_presets();
1926        assert_eq!(presets.len(), 2);
1927
1928        let default = presets
1929            .iter()
1930            .find(|preset| preset.is_default)
1931            .expect("moonshot default preset");
1932        assert_eq!(default.id, "kimi-k2.6");
1933        assert_eq!(default.provider, Provider::Moonshot);
1934    }
1935}