vtcode_config/models/model_id/
collection.rs1use std::collections::BTreeMap;
2use std::str::FromStr;
3
4use crate::core::{CustomProviderConfig, ProviderOverrideConfig};
5use crate::models::Provider;
6use hashbrown::HashSet;
7
8use super::ModelId;
9
10impl ModelId {
11 pub fn openrouter_vendor(&self) -> Option<&'static str> {
13 self.openrouter_metadata().map(|meta| meta.vendor)
14 }
15
16 pub fn all_models() -> Vec<ModelId> {
18 let mut models = vec![
19 ModelId::Gemini38Flash,
21 ModelId::Gemini4Argon,
22 ModelId::GPT6Astra,
24 ModelId::GPT6Sol,
25 ModelId::GPT61Sol,
26 ModelId::GPT61Terra,
27 ModelId::GPT6Luna,
28 ModelId::GPT56Sol,
29 ModelId::GPT56Terra,
30 ModelId::GPT56Luna,
31 ModelId::OpenAIGptOss20b,
32 ModelId::OpenAIGptOss120b,
33 ModelId::ClaudeSonnet5,
35 ModelId::ClaudeSonnet55,
36 ModelId::ClaudeHaiku55,
37 ModelId::ClaudeFable5,
38 ModelId::ClaudeFable51,
39 ModelId::ClaudeFable52,
40 ModelId::ClaudeOpus5,
41 ModelId::ClaudeOpus55,
42 ModelId::CopilotAuto,
43 ModelId::CopilotGPT52Codex,
44 ModelId::CopilotGPT51CodexMax,
45 ModelId::CopilotGPT54,
46 ModelId::CopilotGPT54Mini,
47 ModelId::DeepSeekFlash,
49 ModelId::MetaMuseSpark13,
51 ModelId::MetaMuseSpark13Contributor,
52 ModelId::MetaMuseWonder10,
53 ModelId::MetaMuseWonderFull10,
54 ModelId::MetaMuseEmber10,
55 ModelId::NvidiaNemotron3Ultra550bA55b,
57 ModelId::NvidiaNemotron3Super120bA12b,
58 ModelId::NvidiaNemotron3Nano30bA3b,
59 ModelId::MergeGatewayDefaultRouting,
61 ModelId::MergeGatewayAnthropicClaudeOpus5,
62 ModelId::MergeGatewayAnthropicClaudeOpus55,
63 ModelId::MergeGatewayAnthropicClaudeSonnet5,
64 ModelId::MergeGatewayAnthropicClaudeSonnet55,
65 ModelId::MergeGatewayXaiGrok46,
66 ModelId::MergeGatewayXaiGrok47,
67 ModelId::MergeGatewayMinimaxH3,
68 ModelId::MergeGatewayMinimaxM31Flash,
69 ModelId::MergeGatewayMoonshotKimiK3,
70 ModelId::MergeGatewayMoonshotKimiK31Pro,
71 ModelId::MergeGatewayThinkingMachinesInkling,
72 ModelId::MergeGatewayZaiGlm53Flash,
73 ModelId::MergeGatewayZaiGlm53Flashx,
74 ModelId::MergeGatewayOpenAIGpt56Luna,
75 ModelId::MergeGatewayOpenAIGpt56Sol,
76 ModelId::MergeGatewayOpenAIGpt56Terra,
77 ModelId::MergeGatewayGoogleGemini38Flash,
78 ModelId::MergeGatewayGoogleGemini4Argon,
79 ModelId::MergeGatewayAnthropicClaudeHaiku4520251001,
80 ModelId::MergeGatewayAnthropicClaudeHaiku55,
81 ModelId::MergeGatewayAnthropicClaudeFable51,
82 ModelId::MergeGatewayAnthropicClaudeFable52,
83 ModelId::MergeGatewayDeepseekFlash,
84 ModelId::MergeGatewayOpenAIGpt6Astra,
85 ModelId::MergeGatewayOpenAIGpt6Sol,
86 ModelId::MergeGatewayOpenAIGpt61Sol,
87 ModelId::MergeGatewayOpenAIGpt61Terra,
88 ModelId::MergeGatewayOpenAIGpt6Luna,
89 ModelId::MergeGatewayXiaomimimoMimoV26Pro,
90 ModelId::MergeGatewayXiaomimimoMimoV26Flash,
91 ModelId::MergeGatewayMistralLarge4,
92 ModelId::MergeGatewayMetaMuseSparkOpen,
93 ModelId::MistralLarge3,
95 ModelId::MistralLarge4,
96 ModelId::ZaiGlm53,
98 ModelId::ZaiGlm53Flash,
99 ModelId::ZaiGlm53Flashx,
100 ModelId::MiMoV26Pro,
102 ModelId::MiMoV26Flash,
103 ModelId::MiMoV26ProUltraspeed,
104 ModelId::MoonshotKimiK31Pro,
106 ModelId::MoonshotKimiK3,
107 ModelId::OpenCodeGoGlm53,
110 ModelId::OpenCodeGoGpt56Luna,
111 ModelId::OpenCodeGoKimiK3,
112 ModelId::OpenCodeGoMinimaxM3,
113 ModelId::OllamaGptOss20b,
115 ModelId::OllamaGptOss20bCloud,
116 ModelId::OllamaGptOss120bCloud,
117 ModelId::OllamaGlm53Cloud,
118 ModelId::OllamaGlm53FlashCloud,
119 ModelId::OllamaMinimaxM3Cloud,
120 ModelId::OllamaMinimaxM31FlashCloud,
121 ModelId::OllamaMistralLarge4Cloud,
122 ModelId::OllamaMuseSparkOpenCloud,
123 ModelId::OllamaDeepSeekV41FlashCloud,
124 ModelId::OllamaKimiK3Cloud,
125 ModelId::OllamaGemma4,
126 ModelId::LlamaCppGemma426bA4b,
128 ModelId::LlamaCppGemma4E4b,
129 ModelId::LlamaCppGptOss20b,
130 ModelId::MinimaxM3,
132 ModelId::MinimaxM31Flash,
133 ModelId::HuggingFaceOpenAIGptOss20b,
135 ModelId::HuggingFaceOpenAIGptOss120b,
136 ModelId::HuggingFaceGlm53FlashTogether,
137 ModelId::HuggingFaceGlm53Together,
138 ModelId::HuggingFaceKimiK3Together,
139 ModelId::HuggingFaceMinimaxM3Novita,
140 ModelId::HuggingFaceMuseSparkOpenBaseten,
141 ModelId::StepFun37Flash,
142 ModelId::StepFun5Preview,
143 ModelId::EvolinkGemini31Pro,
144 ModelId::EvolinkMinimaxM3,
145 ModelId::EvolinkClaudeHaiku45,
146 ModelId::OpenRouterMoonshotaiKimiK3,
147 ModelId::OpenRouterZaiGlm53Flash,
148 ModelId::OpenRouterZaiGlm53Flashx,
149 ModelId::XaiGrok46,
151 ModelId::XaiGrok47,
152 ModelId::VercelAnthropicClaudeSonnet5,
154 ModelId::VercelAnthropicClaudeOpus5,
155 ModelId::VercelAnthropicClaudeOpus55,
156 ModelId::VercelAnthropicClaudeHaiku45,
157 ModelId::VercelOpenAiGpt56Sol,
158 ModelId::VercelOpenAiGpt6Astra,
159 ModelId::VercelOpenAiGpt56Luna,
160 ModelId::VercelOpenAiGpt6Sol,
161 ModelId::VercelOpenAiGpt6Luna,
162 ModelId::VercelGoogleGemini38Flash,
163 ModelId::VercelDeepseekFlash,
164 ModelId::VercelMoonshotaiKimiK3,
165 ModelId::VercelMinimaxM3,
166 ModelId::VercelSpacexaiGrok47,
167 ];
168 models.extend(Self::openrouter_models());
169 let mut seen = HashSet::new();
170 models.retain(|model| seen.insert(model.clone()));
171 models
172 }
173
174 pub fn models_for_provider(provider: Provider) -> Vec<ModelId> {
176 Self::all_models()
177 .into_iter()
178 .filter(|model| model.provider() == provider)
179 .collect()
180 }
181
182 pub fn all_models_with_overrides(overrides: &BTreeMap<String, ProviderOverrideConfig>) -> Vec<ModelId> {
188 let mut models = Self::all_models();
189 for (provider_key, config) in overrides {
190 for model_name in &config.models {
191 let trimmed = model_name.trim().to_string();
192 if !trimmed.is_empty() {
193 models.push(ModelId::Custom(provider_key.clone(), trimmed));
194 }
195 }
196 }
197 models
198 }
199
200 pub fn models_for_provider_with_overrides(
202 provider: Provider,
203 overrides: &BTreeMap<String, ProviderOverrideConfig>,
204 ) -> Vec<ModelId> {
205 Self::all_models_with_overrides(overrides)
206 .into_iter()
207 .filter(|model| model.provider() == provider)
208 .collect()
209 }
210
211 pub fn from_config(
222 model: &str,
223 provider: &str,
224 provider_overrides: &BTreeMap<String, ProviderOverrideConfig>,
225 custom_providers: &[CustomProviderConfig],
226 ) -> Result<Self, crate::models::ModelParseError> {
227 let trimmed = model.trim();
228 if let Ok(parsed) = Self::from_str(trimmed) {
229 return Ok(parsed);
230 }
231 let hinted_provider = provider.trim().parse::<Provider>().ok();
232 for (provider_key, override_cfg) in provider_overrides {
233 let matches_hint = match hinted_provider {
234 Some(active) => provider_key.parse::<Provider>().ok() == Some(active),
235 None => provider_key.eq_ignore_ascii_case(provider.trim()),
236 };
237 if matches_hint && override_cfg.models.iter().any(|candidate| candidate.trim() == trimmed) {
238 return Ok(ModelId::Custom(provider_key.clone(), trimmed.to_owned()));
239 }
240 }
241 for custom in custom_providers {
242 if custom.name.eq_ignore_ascii_case(provider.trim())
243 && custom.effective_models().iter().any(|candidate| candidate == trimmed)
244 {
245 return Ok(ModelId::Custom(custom.name.to_lowercase(), trimmed.to_owned()));
246 }
247 }
248 Self::from_str(trimmed)
249 }
250}