use crate::config::models::ModelId;
use crate::ui::user_confirmation::{AgentMode, UserConfirmation};
use anyhow::Result;
use console::style;
pub struct SafetyValidator;
impl SafetyValidator {
pub fn validate_model_usage(
requested_model: &str,
task_description: Option<&str>,
skip_confirmations: bool,
) -> Result<String> {
use crate::config::constants::models;
let model_id = match requested_model {
s if s == models::GEMINI_2_5_PRO => Some(ModelId::Gemini25Pro),
s if s == models::GEMINI_2_5_FLASH_PREVIEW => Some(ModelId::Gemini25FlashPreview),
s if s == models::GEMINI_2_5_PRO => Some(ModelId::Gemini25Pro),
_ => None,
};
if let Some(ModelId::Gemini25Pro) = model_id {
let current_default = ModelId::default();
if skip_confirmations {
println!(
"{}",
style("Using Gemini 2.5 Pro model (confirmations skipped)").yellow()
);
return Ok(requested_model.to_string());
}
if let Some(task) = task_description {
println!("{}", style("Model Selection Review").cyan().bold());
println!("Task: {}", style(task).cyan());
println!();
}
let confirmed = UserConfirmation::confirm_pro_model_usage(current_default.as_str())?;
if !confirmed {
println!(
"Falling back to default model: {}",
current_default.display_name()
);
return Ok(current_default.as_str().to_string());
}
}
Ok(requested_model.to_string())
}
pub fn validate_agent_mode(
_task_description: &str,
_skip_confirmations: bool,
) -> Result<AgentMode> {
println!(
"{}",
style("Using single-agent mode with Decision Ledger").green()
);
Ok(AgentMode::SingleCoder)
}
pub fn is_model_switch_safe(from_model: &str, to_model: &str) -> bool {
use std::str::FromStr;
let from_id = ModelId::from_str(from_model).ok();
let to_id = ModelId::from_str(to_model).ok();
match (from_id, to_id) {
(Some(from), Some(to)) => {
!matches!(to, ModelId::Gemini25Pro) || matches!(from, ModelId::Gemini25Pro)
}
_ => true, }
}
pub fn display_safety_recommendations(
model: &str,
agent_mode: &AgentMode,
task_description: Option<&str>,
) {
println!("{}", style(" Safety Configuration Summary").cyan().bold());
println!("Model: {}", style(model).green());
println!("Agent Mode: {}", style(format!("{:?}", agent_mode)).green());
if let Some(task) = task_description {
println!("Task: {}", style(task).cyan());
}
println!();
use crate::config::constants::models;
match model {
s if s == models::GEMINI_2_5_FLASH_PREVIEW => {
println!("{}", style("[FAST] Using balanced model:").green());
println!("• Good quality responses");
println!("• Reasonable cost");
println!("• Fast response times");
}
s if s == models::GEMINI_2_5_PRO => {
println!("{}", style("Using most capable model:").yellow());
println!("• Highest quality responses");
println!("• Higher cost per token");
println!("• Slower response times");
}
_ => {}
}
match agent_mode {
AgentMode::SingleCoder => {
println!("{}", style("Single-Agent System:").blue());
println!("• Streamlined execution");
println!("• Decision Ledger tracking");
println!("• Lower API costs");
println!("• Faster task completion");
println!("• Best for most development tasks");
}
}
println!();
}
pub fn validate_resource_usage(
model: &str,
_agent_mode: &AgentMode,
estimated_tokens: Option<usize>,
) -> Result<bool> {
use crate::config::constants::models;
let mut warnings = Vec::new();
if model == models::GEMINI_2_5_PRO {
warnings.push("Using most expensive model (Gemini 2.5 Pro)");
}
if let Some(tokens) = estimated_tokens
&& tokens > 10000
{
warnings.push("High token usage estimated (>10k tokens)");
}
if !warnings.is_empty() {
println!("{}", style(" Resource Usage Warning").yellow().bold());
for warning in &warnings {
println!("• {}", warning);
}
println!();
let confirmed = UserConfirmation::confirm_action(
"Do you want to proceed with these resource usage implications?",
false,
)?;
return Ok(confirmed);
}
Ok(true)
}
}
impl ModelId {
pub fn parse_from_str(s: &str) -> Result<Self, &'static str> {
use std::str::FromStr;
<Self as FromStr>::from_str(s).map_err(|_| "Unknown model")
}
}