vtcode_config/models/model_id/
capabilities.rs1use super::ModelId;
2
3impl ModelId {
4 pub fn non_reasoning_variant(&self) -> Option<Self> {
6 if let Some(meta) = self.openrouter_metadata() {
7 if !meta.reasoning {
8 return None;
9 }
10
11 let vendor = meta.vendor;
12 let mut candidates: Vec<Self> = Self::openrouter_vendor_groups()
13 .into_iter()
14 .find(|(candidate_vendor, _)| *candidate_vendor == vendor)
15 .map(|(_, models)| {
16 models
17 .iter()
18 .copied()
19 .filter(|candidate| candidate != self)
20 .filter(|candidate| {
21 candidate
22 .openrouter_metadata()
23 .map(|other| !other.reasoning)
24 .unwrap_or(false)
25 })
26 .collect()
27 })
28 .unwrap_or_default();
29
30 if candidates.is_empty() {
31 return None;
32 }
33
34 candidates.sort_by_key(|candidate| {
35 candidate
36 .openrouter_metadata()
37 .map(|data| (!data.efficient, data.display))
38 .unwrap_or((true, ""))
39 });
40
41 return candidates.into_iter().next();
42 }
43
44 let direct = match self {
45 ModelId::Gemini31ProPreview
46 | ModelId::Gemini31ProPreviewCustomTools
47 | ModelId::Gemini31FlashLitePreview => Some(ModelId::Gemini3FlashPreview),
48 ModelId::GPT | ModelId::GPT52 | ModelId::GPT54 | ModelId::GPT54Pro | ModelId::GPT5 => {
49 Some(ModelId::GPT5Mini)
50 }
51 ModelId::DeepSeekReasoner => Some(ModelId::DeepSeekChat),
52 ModelId::ZaiGlm5 => Some(ModelId::OllamaGlm5Cloud),
53 ModelId::ClaudeOpus46 | ModelId::ClaudeSonnet46 => Some(ModelId::ClaudeSonnet46),
54 ModelId::MinimaxM25 => None,
55 _ => None,
56 };
57
58 direct.and_then(|candidate| {
59 if candidate.supports_reasoning_effort() {
60 None
61 } else {
62 Some(candidate)
63 }
64 })
65 }
66
67 pub fn is_flash_variant(&self) -> bool {
69 matches!(
70 self,
71 ModelId::Gemini3FlashPreview
72 | ModelId::Gemini31FlashLitePreview
73 | ModelId::OpenRouterStepfunStep35FlashFree
74 | ModelId::OpenRouterNvidiaNemotron3Super120bA12bFree
75 | ModelId::OllamaGemini3FlashPreviewCloud
76 | ModelId::HuggingFaceStep35Flash
77 )
78 }
79
80 pub fn is_pro_variant(&self) -> bool {
82 matches!(
83 self,
84 ModelId::Gemini31ProPreview
85 | ModelId::Gemini31ProPreviewCustomTools
86 | ModelId::OpenRouterGoogleGemini31ProPreview
87 | ModelId::GPT
88 | ModelId::GPT5
89 | ModelId::GPT52
90 | ModelId::GPT54
91 | ModelId::GPT54Pro
92 | ModelId::GPT53Codex
93 | ModelId::ClaudeOpus46
94 | ModelId::ClaudeSonnet46
95 | ModelId::DeepSeekReasoner
96 | ModelId::ZaiGlm5
97 | ModelId::OpenRouterStepfunStep35FlashFree
98 | ModelId::OpenRouterNvidiaNemotron3Super120bA12bFree
99 | ModelId::MinimaxM25
100 | ModelId::OllamaGlm5Cloud
101 | ModelId::OllamaMinimaxM25Cloud
102 | ModelId::HuggingFaceQwen3CoderNextNovita
103 | ModelId::HuggingFaceQwen35397BA17BTogether
104 )
105 }
106
107 pub fn is_efficient_variant(&self) -> bool {
109 if let Some(meta) = self.openrouter_metadata() {
110 return meta.efficient;
111 }
112 matches!(
113 self,
114 ModelId::Gemini3FlashPreview
115 | ModelId::Gemini31FlashLitePreview
116 | ModelId::GPT5Mini
117 | ModelId::GPT5Nano
118 | ModelId::ClaudeHaiku45
119 | ModelId::DeepSeekChat
120 | ModelId::HuggingFaceStep35Flash
121 )
122 }
123
124 pub fn is_top_tier(&self) -> bool {
126 if let Some(meta) = self.openrouter_metadata() {
127 return meta.top_tier;
128 }
129 matches!(
130 self,
131 ModelId::Gemini31ProPreview
132 | ModelId::Gemini31ProPreviewCustomTools
133 | ModelId::OpenRouterGoogleGemini31ProPreview
134 | ModelId::Gemini3FlashPreview
135 | ModelId::Gemini31FlashLitePreview
136 | ModelId::GPT
137 | ModelId::GPT5
138 | ModelId::GPT52
139 | ModelId::GPT54
140 | ModelId::GPT54Pro
141 | ModelId::GPT53Codex
142 | ModelId::ClaudeOpus46
143 | ModelId::ClaudeSonnet46
144 | ModelId::DeepSeekReasoner
145 | ModelId::ZaiGlm5
146 | ModelId::OpenRouterStepfunStep35FlashFree
147 | ModelId::HuggingFaceQwen3CoderNextNovita
148 | ModelId::HuggingFaceQwen35397BA17BTogether
149 )
150 }
151
152 pub fn is_reasoning_variant(&self) -> bool {
154 if let Some(meta) = self.openrouter_metadata() {
155 return meta.reasoning;
156 }
157 self.provider().supports_reasoning_effort(self.as_str())
158 }
159
160 pub fn supports_tool_calls(&self) -> bool {
162 if let Some(meta) = self.openrouter_metadata() {
163 return meta.tool_call;
164 }
165 true
166 }
167
168 pub fn generation(&self) -> &'static str {
170 if let Some(meta) = self.openrouter_metadata() {
171 return meta.generation;
172 }
173 match self {
174 ModelId::Gemini31ProPreview | ModelId::Gemini31ProPreviewCustomTools => "3.1",
176 ModelId::Gemini31FlashLitePreview => "3.1-lite",
177 ModelId::Gemini3FlashPreview => "3",
178 ModelId::GPT => "5.4",
180 ModelId::GPT52 => "5.2",
181 ModelId::GPT54 | ModelId::GPT54Pro => "5.4",
182 ModelId::GPT53Codex => "5.3",
183 ModelId::GPT5
184 | ModelId::GPT5Mini
185 | ModelId::GPT5Nano
186 | ModelId::OpenAIGptOss20b
187 | ModelId::OpenAIGptOss120b => "5",
188 ModelId::ClaudeOpus46 | ModelId::ClaudeSonnet46 => "4.6",
190 ModelId::ClaudeHaiku45 => "4.5",
191 ModelId::DeepSeekChat | ModelId::DeepSeekReasoner => "V3.2-Exp",
193 ModelId::ZaiGlm5 => "5",
195 ModelId::OllamaGptOss20b => "oss",
196 ModelId::OllamaGptOss20bCloud => "oss-cloud",
197 ModelId::OllamaGptOss120bCloud => "oss-cloud",
198 ModelId::OllamaQwen317b => "oss",
199 ModelId::OllamaQwen3CoderNext => "qwen3-coder-next:cloud",
200 ModelId::OllamaDeepseekV32Cloud => "deepseek-v3.2",
201 ModelId::OllamaQwen3Next80bCloud => "qwen3-next",
202 ModelId::OllamaMinimaxM2Cloud => "minimax-m2",
203 ModelId::OllamaGlm5Cloud => "glm-5",
204 ModelId::OllamaMinimaxM25Cloud => "minimax-m2.5",
205 ModelId::OllamaGemini3FlashPreviewCloud => "gemini-3",
206 ModelId::MinimaxM25 => "M2.5",
208 ModelId::MoonshotKimiK25 => "k2.5",
210 ModelId::HuggingFaceDeepseekV32 => "V3.2-Exp",
212 ModelId::HuggingFaceOpenAIGptOss20b => "oss",
213 ModelId::HuggingFaceOpenAIGptOss120b => "oss",
214 ModelId::HuggingFaceMinimaxM25Novita => "m2.5",
215 ModelId::HuggingFaceDeepseekV32Novita => "v3.2",
216 ModelId::HuggingFaceXiaomiMimoV2FlashNovita => "v2-flash",
217 ModelId::HuggingFaceGlm5Novita => "5",
218 ModelId::HuggingFaceStep35Flash => "3.5",
219 ModelId::HuggingFaceQwen3CoderNextNovita | ModelId::OpenRouterQwen3CoderNext => {
220 "qwen3-coder-next"
221 }
222 _ => "unknown",
223 }
224 }
225
226 pub fn supports_shell_tool(&self) -> bool {
228 matches!(
229 self,
230 ModelId::GPT
231 | ModelId::GPT52
232 | ModelId::GPT54
233 | ModelId::GPT54Pro
234 | ModelId::GPT53Codex
235 )
236 }
237
238 pub fn supports_apply_patch_tool(&self) -> bool {
240 false }
242}