use anyhow::Result;
use indexmap::{IndexMap, IndexSet};
use serde::{Deserialize, Serialize};
use super::{McpPolicyStore, ToolPolicy};
#[derive(Debug, Clone, PartialEq)]
pub enum ToolExecutionDecision {
Allowed,
Denied,
DeniedWithFeedback(String),
}
impl ToolExecutionDecision {
pub fn is_allowed(&self) -> bool {
matches!(self, Self::Allowed)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolPolicyConfig {
pub version: u32,
pub available_tools: Vec<String>,
pub policies: IndexMap<String, ToolPolicy>,
#[serde(default)]
pub constraints: IndexMap<String, ToolConstraints>,
#[serde(default)]
pub mcp: McpPolicyStore,
#[serde(default)]
pub approval_cache: ApprovalCacheConfig,
}
impl Default for ToolPolicyConfig {
fn default() -> Self {
Self {
version: 1,
available_tools: Vec::new(),
policies: IndexMap::new(),
constraints: IndexMap::new(),
mcp: McpPolicyStore::default(),
approval_cache: ApprovalCacheConfig::default(),
}
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct ApprovalCacheConfig {
#[serde(default)]
pub allowed: IndexSet<String>,
#[serde(default)]
pub prefixes: IndexSet<String>,
#[serde(default)]
pub regexes: IndexSet<String>,
}
pub const APPROVAL_CACHE_MAX_ENTRIES: usize = 256;
impl ApprovalCacheConfig {
pub fn trim_to_budget(&mut self) -> bool {
let mut trimmed = false;
for collection in [&mut self.allowed, &mut self.prefixes, &mut self.regexes] {
while collection.len() > APPROVAL_CACHE_MAX_ENTRIES {
let _ = collection.shift_remove_index(0);
trimmed = true;
}
}
trimmed
}
}
pub trait PermissionPromptHandler: Send + Sync {
fn prompt_tool_permission(&mut self, tool_name: &str) -> Result<ToolExecutionDecision>;
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ToolConstraints {
#[serde(default)]
pub allowed_modes: Option<Vec<String>>,
#[serde(default)]
pub max_results_per_call: Option<usize>,
#[serde(default)]
pub max_items_per_call: Option<usize>,
#[serde(default)]
pub default_response_format: Option<String>,
#[serde(default)]
pub max_bytes_per_read: Option<usize>,
#[serde(default)]
pub max_response_bytes: Option<usize>,
#[serde(default)]
pub allowed_url_schemes: Option<Vec<String>>,
#[serde(default)]
pub denied_url_hosts: Option<Vec<String>>,
}