use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct AsyncApprovalConfig {
#[serde(default = "default_async_approval_enabled")]
enabled: bool,
#[serde(default = "default_async_approval_timeout_secs")]
timeout_secs: u64,
#[serde(default)]
notify_command: Option<String>,
#[serde(default = "default_async_approval_auto_approve_below")]
auto_approve_below_usd: f64,
#[serde(default)]
auto_approve_timeout_secs: Option<u64>,
}
impl Default for AsyncApprovalConfig {
fn default() -> Self {
Self {
enabled: default_async_approval_enabled(),
timeout_secs: default_async_approval_timeout_secs(),
notify_command: None,
auto_approve_below_usd: default_async_approval_auto_approve_below(),
auto_approve_timeout_secs: None,
}
}
}
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct SkepticPanelConfig {
#[serde(default = "default_skeptic_panel_enabled")]
pub enabled: bool,
#[serde(default)]
pub models: Vec<String>,
}
impl Default for SkepticPanelConfig {
fn default() -> Self {
Self {
enabled: default_skeptic_panel_enabled(),
models: Vec::new(),
}
}
}
const fn default_skeptic_panel_enabled() -> bool {
false
}
const fn default_async_approval_enabled() -> bool {
false
}
const fn default_async_approval_timeout_secs() -> u64 {
3600
}
const fn default_async_approval_auto_approve_below() -> f64 {
0.10
}
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ConfidenceEscalationConfig {
#[serde(default = "default_escalation_enabled")]
pub enabled: bool,
#[serde(default = "default_escalation_confidence_threshold")]
pub confidence_threshold: f64,
#[serde(default = "default_escalation_always_escalate_tools")]
pub always_escalate_tools: Vec<String>,
#[serde(default = "default_escalation_cost_threshold")]
pub cost_threshold_usd: f64,
#[serde(default = "default_escalation_llm_confidence")]
pub use_llm_confidence: bool,
#[serde(default)]
pub plan_mode_only: bool,
#[serde(default = "default_escalation_max_replan")]
pub max_replan_attempts: u32,
#[serde(default = "default_escalation_max_total")]
pub max_total_escalations: u32,
#[serde(default = "default_escalation_prompt_user")]
pub prompt_user_on_exhaust: bool,
}
impl ConfidenceEscalationConfig {
pub fn would_escalate(&self, tool_name: &str, estimated_cost_usd: Option<f64>) -> bool {
if self.always_escalate_tools.iter().any(|t| t == tool_name) {
return true;
}
if let Some(cost) = estimated_cost_usd
&& cost > self.cost_threshold_usd
{
return true;
}
false
}
}
impl Default for ConfidenceEscalationConfig {
fn default() -> Self {
Self {
enabled: default_escalation_enabled(),
confidence_threshold: default_escalation_confidence_threshold(),
always_escalate_tools: default_escalation_always_escalate_tools(),
cost_threshold_usd: default_escalation_cost_threshold(),
use_llm_confidence: default_escalation_llm_confidence(),
plan_mode_only: false,
max_replan_attempts: default_escalation_max_replan(),
max_total_escalations: default_escalation_max_total(),
prompt_user_on_exhaust: default_escalation_prompt_user(),
}
}
}
const fn default_escalation_enabled() -> bool {
false
}
const fn default_escalation_confidence_threshold() -> f64 {
0.7
}
fn default_escalation_always_escalate_tools() -> Vec<String> {
vec!["delete_file".to_string(), "remove".to_string(), "rm".to_string()]
}
const fn default_escalation_cost_threshold() -> f64 {
0.05
}
const fn default_escalation_llm_confidence() -> bool {
false
}
const fn default_escalation_max_replan() -> u32 {
3
}
const fn default_escalation_max_total() -> u32 {
5
}
const fn default_escalation_prompt_user() -> bool {
true
}