vtcode_config/models/model_id/
parse.rs1use std::str::FromStr;
2
3use crate::models::ModelParseError;
4
5use super::ModelId;
6
7impl FromStr for ModelId {
8 type Err = ModelParseError;
9
10 fn from_str(s: &str) -> Result<Self, Self::Err> {
11 use crate::constants::models;
12 let trimmed = s.trim();
13
14 if trimmed == models::zai::GLM_5 || trimmed == models::zai::GLM_5_LEGACY {
16 return Ok(ModelId::ZaiGlm5);
17 }
18 if trimmed == models::zai::GLM_5_1 {
19 return Ok(ModelId::ZaiGlm51);
20 }
21
22 if let Some(opencode_model) = trimmed
23 .strip_prefix("opencode/")
24 .or_else(|| trimmed.strip_prefix("opencode-zen/"))
25 {
26 return match opencode_model {
27 m if m == models::opencode_zen::GPT_5_4 => Ok(ModelId::OpenCodeZenGPT54),
28 m if m == models::opencode_zen::GPT_5_4_MINI => Ok(ModelId::OpenCodeZenGPT54Mini),
29 m if m == models::opencode_zen::CLAUDE_SONNET_4_6 => {
30 Ok(ModelId::OpenCodeZenClaudeSonnet46)
31 }
32 m if m == models::opencode_zen::GLM_5_1 => Ok(ModelId::OpenCodeZenGlm51),
33 _ => Err(ModelParseError::InvalidModel(trimmed.to_string())),
34 };
35 }
36
37 if let Some(opencode_model) = trimmed.strip_prefix("opencode-go/") {
38 return match opencode_model {
39 m if m == models::opencode_go::GLM_5_1 => Ok(ModelId::OpenCodeGoGlm51),
40 m if m == models::opencode_go::MINIMAX_M2_5 => Ok(ModelId::OpenCodeGoMinimaxM25),
41 m if m == models::opencode_go::MINIMAX_M2_7 => Ok(ModelId::OpenCodeGoMinimaxM27),
42 _ => Err(ModelParseError::InvalidModel(trimmed.to_string())),
43 };
44 }
45
46 if let Some(model) = Self::parse_openrouter_model(trimmed) {
47 return Ok(model);
48 }
49
50 match trimmed {
51 s if s == models::GEMINI_3_1_PRO_PREVIEW => Ok(ModelId::Gemini31ProPreview),
53 s if s == models::GEMINI_3_1_PRO_PREVIEW_CUSTOMTOOLS => {
54 Ok(ModelId::Gemini31ProPreviewCustomTools)
55 }
56 s if s == models::GEMINI_3_1_FLASH_LITE_PREVIEW => {
57 Ok(ModelId::Gemini31FlashLitePreview)
58 }
59 s if s == models::GEMINI_3_5_FLASH || s == models::GEMINI_3_FLASH_PREVIEW => {
60 Ok(ModelId::Gemini35Flash)
61 }
62 s if s == models::GPT => Ok(ModelId::GPT54),
64 s if s == models::openai::GPT_5_5 || s == models::openai::GPT_5_5_DATED => {
65 Ok(ModelId::GPT55)
66 }
67 s if s == models::GPT_5_4 => Ok(ModelId::GPT54),
68 s if s == models::GPT_5_4_PRO => Ok(ModelId::GPT54Pro),
69 s if s == models::openai::GPT_5_4_NANO => Ok(ModelId::GPT54Nano),
70 s if s == models::openai::GPT_5_4_MINI => Ok(ModelId::GPT54Mini),
71 s if s == models::openai::GPT_5_3_CODEX => Ok(ModelId::GPT53Codex),
72 s if s == models::openai::GPT_OSS_20B => Ok(ModelId::OpenAIGptOss20b),
73 s if s == models::openai::GPT_OSS_120B => Ok(ModelId::OpenAIGptOss120b),
74 s if s == models::CLAUDE_OPUS_4_8 => Ok(ModelId::ClaudeOpus48),
76 s if s == models::CLAUDE_SONNET_4_6 => Ok(ModelId::ClaudeSonnet46),
77 s if s == models::CLAUDE_HAIKU_4_5 => Ok(ModelId::ClaudeHaiku45),
78 s if s == models::CLAUDE_HAIKU_4_5_20251001 => Ok(ModelId::ClaudeHaiku45),
79 s if s == models::CLAUDE_MYTHOS_PREVIEW => Ok(ModelId::ClaudeMythosPreview),
80 s if s == models::copilot::AUTO => Ok(ModelId::CopilotAuto),
81 s if s == models::copilot::GPT_5_2_CODEX => Ok(ModelId::CopilotGPT52Codex),
82 s if s == models::copilot::GPT_5_1_CODEX_MAX => Ok(ModelId::CopilotGPT51CodexMax),
83 s if s == models::copilot::GPT_5_4 => Ok(ModelId::CopilotGPT54),
84 s if s == models::copilot::GPT_5_4_MINI => Ok(ModelId::CopilotGPT54Mini),
85 s if s == models::copilot::CLAUDE_SONNET_4_6 => Ok(ModelId::CopilotClaudeSonnet46),
86 s if s == models::deepseek::DEEPSEEK_V4_PRO => Ok(ModelId::DeepSeekV4Pro),
88 s if s == models::deepseek::DEEPSEEK_V4_FLASH => Ok(ModelId::DeepSeekV4Flash),
89 s if s == models::mistral::MISTRAL_LARGE_3 => Ok(ModelId::MistralLarge3),
91 s if s == models::mimo::MIMO_V2_5_PRO => Ok(ModelId::MiMoV25Pro),
93 s if s == models::mimo::MIMO_V2_5 => Ok(ModelId::MiMoV25),
94 s if s == models::qwen::QWEN3_7_MAX => Ok(ModelId::Qwen37Max),
96 s if s == models::qwen::QWEN3_6_FLASH => Ok(ModelId::Qwen36Flash),
97 s if s == models::qwen::QWEN3_6_PLUS => Ok(ModelId::Qwen36Plus),
98 s if s == models::zai::GLM_5 || s == models::zai::GLM_5_LEGACY => Ok(ModelId::ZaiGlm5),
103 s if s == models::zai::GLM_5_1 => Ok(ModelId::ZaiGlm51),
104 s if s == models::moonshot::KIMI_K2_6 => Ok(ModelId::MoonshotKimiK26),
106 s if s == models::ollama::GPT_OSS_20B => Ok(ModelId::OllamaGptOss20b),
107 s if s == models::ollama::GPT_OSS_20B_CLOUD => Ok(ModelId::OllamaGptOss20bCloud),
108 s if s == models::ollama::GPT_OSS_120B_CLOUD => Ok(ModelId::OllamaGptOss120bCloud),
109 s if s == models::ollama::QWEN3_1_7B => Ok(ModelId::OllamaQwen317b),
110 s if s == models::ollama::QWEN3_CODER_NEXT => Ok(ModelId::OllamaQwen3CoderNext),
111 "qwen3-coder-next" => Ok(ModelId::OllamaQwen3CoderNext),
112 s if s == models::ollama::DEEPSEEK_V4_FLASH_CLOUD => {
113 Ok(ModelId::OllamaDeepseekV4FlashCloud)
114 }
115 s if s == models::ollama::DEEPSEEK_V4_PRO_CLOUD => {
116 Ok(ModelId::OllamaDeepseekV4ProCloud)
117 }
118 s if s == models::ollama::QWEN3_NEXT_80B_CLOUD => Ok(ModelId::OllamaQwen3Next80bCloud),
119 s if s == models::ollama::GLM_5_CLOUD => Ok(ModelId::OllamaGlm5Cloud),
120 s if s == models::ollama::GLM_5_1_CLOUD => Ok(ModelId::OllamaGlm51Cloud),
121 s if s == models::ollama::GEMINI_3_FLASH_PREVIEW_CLOUD => {
122 Ok(ModelId::OllamaGemini3FlashPreviewCloud)
123 }
124 s if s == models::ollama::MINIMAX_M2_CLOUD => Ok(ModelId::OllamaMinimaxM2Cloud),
125 s if s == models::ollama::MINIMAX_M27_CLOUD => Ok(ModelId::OllamaMinimaxM27Cloud),
126 s if s == models::ollama::MINIMAX_M25_CLOUD => Ok(ModelId::OllamaMinimaxM25Cloud),
127 s if s == models::ollama::KIMI_K2_6_CLOUD => Ok(ModelId::OllamaKimiK26Cloud),
128 s if s == models::ollama::NEMOTRON_3_SUPER_CLOUD => {
129 Ok(ModelId::OllamaNemotron3SuperCloud)
130 }
131 s if s == models::ollama::LAGUNA_XS_2 => Ok(ModelId::OllamaLagunaXs2),
132 s if s == models::llamacpp::QWEN36_27B => Ok(ModelId::LlamaCppQwen3627b),
133 s if s == models::llamacpp::QWEN36_35B_A3B => Ok(ModelId::LlamaCppQwen3635bA3b),
134 s if s == models::llamacpp::GEMMA_4_26B_A4B => Ok(ModelId::LlamaCppGemma426bA4b),
135 s if s == models::llamacpp::GEMMA_4_E4B => Ok(ModelId::LlamaCppGemma4E4b),
136 s if s == models::llamacpp::GPT_OSS_20B => Ok(ModelId::LlamaCppGptOss20b),
137 s if s == models::llamacpp::STEP_3_5_FLASH => Ok(ModelId::LlamaCppStep35Flash),
138 s if s == models::poolside::LAGUNA_M1 => Ok(ModelId::PoolsideLagunaM1),
140 s if s == models::poolside::LAGUNA_XS2 => Ok(ModelId::PoolsideLagunaXs2),
141 s if s == models::minimax::MINIMAX_M2_7 => Ok(ModelId::MinimaxM27),
142 s if s == models::minimax::MINIMAX_M2_5 => Ok(ModelId::MinimaxM25),
143 s if s == models::huggingface::OPENAI_GPT_OSS_20B => {
145 Ok(ModelId::HuggingFaceOpenAIGptOss20b)
146 }
147 s if s == models::huggingface::OPENAI_GPT_OSS_120B => {
148 Ok(ModelId::HuggingFaceOpenAIGptOss120b)
149 }
150 s if s == models::huggingface::MINIMAX_M2_5_NOVITA => {
151 Ok(ModelId::HuggingFaceMinimaxM25Novita)
152 }
153 s if s == models::huggingface::ZAI_GLM_5_NOVITA => Ok(ModelId::HuggingFaceGlm5Novita),
154 s if s == models::huggingface::ZAI_GLM_5_1_ZAI_ORG => {
155 Ok(ModelId::HuggingFaceGlm51ZaiOrg)
156 }
157 s if s == models::huggingface::QWEN3_CODER_NEXT_NOVITA => {
158 Ok(ModelId::HuggingFaceQwen3CoderNextNovita)
159 }
160 s if s == models::huggingface::QWEN3_5_397B_A17B_TOGETHER => {
161 Ok(ModelId::HuggingFaceQwen35397BA17BTogether)
162 }
163 s if s == models::huggingface::KIMI_K2_6_NOVITA => {
164 Ok(ModelId::HuggingFaceKimiK26Novita)
165 }
166 s if s == models::huggingface::DEEPSEEK_V4_FLASH_NOVITA => {
167 Ok(ModelId::HuggingFaceDeepseekV4FlashNovita)
168 }
169 s if s == models::huggingface::DEEPSEEK_V4_PRO_TOGETHER => {
170 Ok(ModelId::HuggingFaceDeepseekV4ProTogether)
171 }
172 s if s == models::huggingface::STEP_3_5_FLASH
173 || s == models::huggingface::STEP_3_5_FLASH_BASE
174 || s == models::huggingface::STEP_3_5_FLASH_LEGACY_FASTEST =>
175 {
176 Ok(ModelId::HuggingFaceStep35Flash)
177 }
178 s if s == models::huggingface::ZAI_GLM_5_1_DEEPINFRA => {
179 Ok(ModelId::HuggingFaceGlm51Deepinfra)
180 }
181 s if s == models::huggingface::MINIMAX_M2_7_NOVITA => {
182 Ok(ModelId::HuggingFaceMinimaxM27Novita)
183 }
184 s if s == models::huggingface::DEEPSEEK_V4_PRO_NOVITA => {
185 Ok(ModelId::HuggingFaceDeepseekV4ProNovita)
186 }
187 s if s == models::stepfun::STEP_3_7_FLASH => Ok(ModelId::StepFun37Flash),
188 "minimax/minimax-m2.5" => Ok(ModelId::OpenRouterMinimaxM25),
189 "qwen/qwen3-coder-next" => Ok(ModelId::OpenRouterQwen3CoderNext),
190 "moonshotai/kimi-k2.6" => Ok(ModelId::OpenRouterMoonshotaiKimiK26),
191 "z-ai/glm-5.1" => Ok(ModelId::OpenRouterZaiGlm51),
192 _ => {
193 if let Some(model) = Self::parse_openrouter_model(s) {
194 Ok(model)
195 } else {
196 Err(ModelParseError::InvalidModel(s.to_string()))
197 }
198 }
199 }
200 }
201}