vtcode_config/models/
provider.rs1pub use vtcode_commons::provider::Provider;
8
9use super::{ModelId, model_catalog_entry};
10use crate::core::OpenAIServiceTier;
11use std::str::FromStr;
12
13const GENERIC_REASONING_EFFORTS: &[&str] = &["low", "medium", "high"];
14
15pub trait ProviderModelSupport: AsRef<str> {
20 fn supports_reasoning(&self, model: &str) -> bool {
26 model_catalog_entry(self.as_ref(), model)
27 .map(|entry| entry.reasoning)
28 .unwrap_or_else(|| self.supports_reasoning_effort(model))
29 }
30
31 fn supports_reasoning_effort(&self, model: &str) -> bool;
33
34 fn supported_reasoning_efforts(&self, model: &str) -> &'static [&'static str] {
36 if let Some(entry) = model_catalog_entry(self.as_ref(), model) {
37 return entry.reasoning_efforts;
38 }
39 if self.supports_reasoning_effort(model) {
40 GENERIC_REASONING_EFFORTS
41 } else {
42 &[]
43 }
44 }
45
46 fn supports_service_tier(&self, model: &str) -> bool;
48
49 fn supports_service_tier_value(&self, model: &str, tier: OpenAIServiceTier) -> bool {
54 match tier {
55 OpenAIServiceTier::Ultrafast => {
56 self.as_ref() == Provider::OpenAI.as_ref() && self.supports_service_tier(model)
57 }
58 _ => self.supports_service_tier(model),
59 }
60 }
61}
62
63impl ProviderModelSupport for Provider {
64 fn supports_reasoning_effort(&self, model: &str) -> bool {
65 if let Some(entry) = model_catalog_entry(self.as_ref(), model) {
66 return !entry.reasoning_efforts.is_empty();
71 }
72
73 use crate::constants::models;
74
75 match self {
76 Provider::Gemini => models::google::REASONING_MODELS.contains(&model),
77 Provider::OpenAI => models::openai::REASONING_MODELS.contains(&model),
78 Provider::Anthropic => models::anthropic::REASONING_MODELS.contains(&model),
79 Provider::Copilot => false,
80 Provider::DeepSeek => model == models::deepseek::DEEPSEEK_FLASH || model == "deepseek-reasoner",
81 Provider::Meta => models::meta::REASONING_MODELS.contains(&model),
82 Provider::OpenRouter => {
83 if let Ok(model_id) = ModelId::from_str(model) {
84 if let Some(meta) = crate::models::openrouter_generated::metadata_for(model_id) {
85 return meta.reasoning;
86 }
87 return false;
88 }
89 models::openrouter::REASONING_MODELS.contains(&model)
90 }
91 Provider::Ollama => models::ollama::REASONING_LEVEL_MODELS.contains(&model),
92 Provider::OllamaCloud => models::ollama::REASONING_LEVEL_MODELS.contains(&model),
93 Provider::LmStudio => models::lmstudio::REASONING_MODELS.contains(&model),
94 Provider::LlamaCpp => models::llamacpp::REASONING_MODELS.contains(&model),
95 Provider::Moonshot => models::moonshot::REASONING_MODELS.contains(&model),
96 Provider::ZAI => models::zai::REASONING_MODELS.contains(&model),
97 Provider::Minimax => models::minimax::SUPPORTED_MODELS.contains(&model),
98 Provider::MiMo => models::mimo::SUPPORTED_MODELS.contains(&model),
99 Provider::Mistral => models::mistral::SUPPORTED_MODELS.contains(&model),
100 Provider::HuggingFace => models::huggingface::REASONING_MODELS.contains(&model),
101 Provider::OpenCodeZen => {
102 if models::opencode_zen::OPENAI_MODELS.contains(&model) {
103 Provider::OpenAI.supports_reasoning_effort(model)
104 } else if models::opencode_zen::ANTHROPIC_MODELS.contains(&model) {
105 Provider::Anthropic.supports_reasoning_effort(model)
106 } else {
107 false
108 }
109 }
110 Provider::OpenCodeGo => false,
111 Provider::Qwen => models::qwen::REASONING_MODELS.contains(&model),
112 Provider::StepFun => models::stepfun::REASONING_MODELS.contains(&model),
113 Provider::Evolink => models::evolink::REASONING_MODELS.contains(&model),
114 Provider::Poolside => false,
115 Provider::Vercel => !models::vercel::NON_REASONING_MODELS.contains(&model),
116 Provider::XAI => models::xai::REASONING_MODELS.contains(&model),
117 Provider::NVIDIA => models::nvidia::REASONING_MODELS.contains(&model),
118 Provider::MergeGateway => models::merge_gateway::route_supports_reasoning(model),
119 }
120 }
121
122 fn supports_service_tier(&self, model: &str) -> bool {
123 use crate::constants::models;
124
125 match self {
126 Provider::OpenAI => models::openai::SERVICE_TIER_MODELS.contains(&model),
127 Provider::MergeGateway => model.trim().starts_with("openai/"),
128 Provider::DeepSeek
131 | Provider::Meta
132 | Provider::OpenRouter
133 | Provider::Ollama
134 | Provider::OllamaCloud
135 | Provider::LmStudio
136 | Provider::LlamaCpp
137 | Provider::Moonshot
138 | Provider::ZAI
139 | Provider::Minimax
140 | Provider::MiMo
141 | Provider::Mistral
142 | Provider::HuggingFace
143 | Provider::OpenCodeZen
144 | Provider::OpenCodeGo
145 | Provider::Qwen
146 | Provider::StepFun
147 | Provider::Evolink
148 | Provider::Poolside
149 | Provider::XAI
150 | Provider::NVIDIA
151 | Provider::Vercel => true,
152 Provider::Gemini | Provider::Anthropic | Provider::Copilot => false,
153 }
154 }
155}