vtcode_core/utils/
safety.rs1use crate::config::models::ModelId;
7use crate::ui::user_confirmation::{AgentMode, ProModelConfirmationResult, UserConfirmation};
8use crate::utils::colors::style;
9use anyhow::Result;
10use std::sync::atomic::{AtomicBool, Ordering};
11
12static PRO_MODEL_AUTO_ACCEPT: AtomicBool = AtomicBool::new(false);
13
14pub struct SafetyValidator;
16
17impl SafetyValidator {
18 pub fn validate_model_usage(
21 requested_model: &str,
22 task_description: Option<&str>,
23 skip_confirmations: bool,
24 ) -> Result<String> {
25 use crate::config::constants::models;
26 let model_id = match requested_model {
28 s if s == models::google::GEMINI_3_1_PRO_PREVIEW => Some(ModelId::Gemini31ProPreview),
29 s if s == models::GEMINI_3_5_FLASH => Some(ModelId::Gemini35Flash),
30 _ => None,
31 };
32
33 if let Some(ModelId::Gemini31ProPreview) = model_id {
35 let current_default = ModelId::default();
36
37 if skip_confirmations {
38 println!(
39 "{}",
40 style("Using Gemini 3.1 Pro model (confirmations skipped)").cyan()
41 );
42 return Ok(requested_model.to_string());
43 }
44
45 if PRO_MODEL_AUTO_ACCEPT.load(Ordering::Relaxed) {
46 println!(
47 "{}",
48 style("Using Gemini 3.1 Pro model (auto-accept enabled)").cyan()
49 );
50 return Ok(requested_model.to_string());
51 }
52
53 if let Some(task) = task_description {
54 println!("{}", style("Model Selection Review").cyan().bold());
55 println!("Task: {}", style(task).cyan());
56 println!();
57 }
58
59 match UserConfirmation::confirm_pro_model_usage(current_default.as_str())? {
61 ProModelConfirmationResult::Yes => {}
62 ProModelConfirmationResult::YesAutoAccept => {
63 PRO_MODEL_AUTO_ACCEPT.store(true, Ordering::Relaxed);
64 }
65 ProModelConfirmationResult::No => {
66 println!(
67 "Falling back to default model: {}",
68 current_default.display_name()
69 );
70 return Ok(current_default.to_string());
71 }
72 }
73 }
74
75 Ok(requested_model.to_string())
76 }
77
78 pub fn validate_agent_mode(
81 _task_description: &str,
82 _skip_confirmations: bool,
83 ) -> Result<AgentMode> {
84 println!(
86 "{}",
87 style("Using single-agent mode with Decision Ledger").green()
88 );
89 Ok(AgentMode::SingleCoder)
90 }
91
92 pub fn is_model_switch_safe(from_model: &str, to_model: &str) -> bool {
94 use std::str::FromStr;
95 let from_id = ModelId::from_str(from_model).ok();
96 let to_id = ModelId::from_str(to_model).ok();
97
98 match (from_id, to_id) {
99 (Some(from), Some(to)) => {
100 !matches!(to, ModelId::Gemini31ProPreview)
102 || matches!(from, ModelId::Gemini31ProPreview)
103 }
104 _ => true, }
106 }
107
108 pub fn display_safety_recommendations(
110 model: &str,
111 agent_mode: &AgentMode,
112 task_description: Option<&str>,
113 ) {
114 println!("{}", style(" Safety Configuration Summary").cyan().bold());
115 println!("Model: {}", style(model).green());
116 println!("Agent Mode: {}", style(format!("{:?}", agent_mode)).green());
117
118 if let Some(task) = task_description {
119 println!("Task: {}", style(task).cyan());
120 }
121
122 println!();
123
124 use crate::config::constants::models;
126 match model {
127 s if s == models::google::GEMINI_3_FLASH_PREVIEW => {
128 println!("{}", style("[FAST] Using balanced model:").green());
129 println!("• Good quality responses");
130 println!("• Reasonable cost");
131 println!("• Fast response times");
132 }
133 s if s == models::google::GEMINI_3_1_PRO_PREVIEW => {
134 println!("{}", style("Using most capable model:").cyan());
135 println!("• Highest quality responses");
136 println!("• Higher cost per token");
137 println!("• Slower response times");
138 }
139 _ => {}
140 }
141
142 match agent_mode {
144 AgentMode::SingleCoder => {
145 println!("{}", style("Single-Agent System:").cyan());
146 println!("• Streamlined execution");
147 println!("• Decision Ledger tracking");
148 println!("• Lower API costs");
149 println!("• Faster task completion");
150 println!("• Best for most development tasks");
151 }
152 }
153
154 println!();
155 }
156
157 pub fn validate_resource_usage(
159 model: &str,
160 _agent_mode: &AgentMode,
161 estimated_tokens: Option<usize>,
162 ) -> Result<bool> {
163 use crate::config::constants::models;
164 let mut warnings = Vec::new();
165
166 if model == models::google::GEMINI_3_1_PRO_PREVIEW {
168 warnings.push("Using most expensive model (Gemini 3 Pro)");
169 }
170
171 if let Some(tokens) = estimated_tokens
175 && tokens > 10000
176 {
177 warnings.push("High token usage estimated (>10k tokens)");
178 }
179
180 if !warnings.is_empty() {
181 println!("{}", style(" Resource Usage Warning").red().bold());
182 for warning in &warnings {
183 println!("• {}", warning);
184 }
185 println!();
186
187 let confirmed = UserConfirmation::confirm_action(
188 "Do you want to proceed with these resource usage implications?",
189 false,
190 )?;
191
192 return Ok(confirmed);
193 }
194
195 Ok(true)
196 }
197}