1use async_trait::async_trait;
4use serde_json::Value;
5
6use crate::error::{ToolError, codes};
7use crate::metadata::ToolMetadata;
8use crate::tool::DynTool;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12#[non_exhaustive]
13pub enum ApprovalDecision {
14 Allow,
16 Deny,
18}
19
20#[async_trait]
22pub trait ApprovalGate: Send + Sync {
23 async fn approve(
25 &self,
26 tool: &dyn DynTool,
27 metadata: &ToolMetadata,
28 arguments: &Value,
29 ) -> Result<ApprovalDecision, ToolError>;
30}
31
32#[derive(Debug, Default, Clone, Copy)]
34pub struct AutoApprove;
35
36#[async_trait]
37impl ApprovalGate for AutoApprove {
38 async fn approve(
39 &self,
40 _tool: &dyn DynTool,
41 _metadata: &ToolMetadata,
42 _arguments: &Value,
43 ) -> Result<ApprovalDecision, ToolError> {
44 Ok(ApprovalDecision::Allow)
45 }
46}
47
48#[derive(Debug, Default, Clone, Copy)]
50pub struct AlwaysDeny;
51
52#[async_trait]
53impl ApprovalGate for AlwaysDeny {
54 async fn approve(
55 &self,
56 tool: &dyn DynTool,
57 _metadata: &ToolMetadata,
58 _arguments: &Value,
59 ) -> Result<ApprovalDecision, ToolError> {
60 Err(codes::approval_denied(format!(
61 "approval denied for tool {}",
62 tool.name()
63 )))
64 }
65}
66
67#[must_use]
69pub fn denied_error(tool_name: &str) -> ToolError {
70 codes::approval_denied(format!("approval denied for tool {tool_name}"))
71}