phi_agent/cli/
approval.rs1use agent_base::{AgentResult, ApprovalDecision, ApprovalHandler, ApprovalRequest};
8use async_trait::async_trait;
9
10#[derive(Clone, Debug)]
12pub enum ApprovalMode {
13 Auto,
15 DenyAll,
17}
18
19pub struct AutoApprovalHandler {
24 mode: ApprovalMode,
25}
26
27impl AutoApprovalHandler {
28 pub fn new(mode: ApprovalMode) -> Self {
30 Self { mode }
31 }
32}
33
34#[async_trait]
35impl ApprovalHandler for AutoApprovalHandler {
36 async fn approve(
37 &self,
38 request: ApprovalRequest,
39 _cancel_token: tokio_util::sync::CancellationToken,
40 ) -> AgentResult<ApprovalDecision> {
41 match &self.mode {
42 ApprovalMode::Auto => {
43 tracing::info!(decision = "AllowAlways", tool = %request.title, "auto-approved");
44 Ok(ApprovalDecision::AllowAlways)
45 },
46 ApprovalMode::DenyAll => {
47 tracing::info!(decision = "Deny", tool = %request.title, "auto-denied");
48 Ok(ApprovalDecision::Deny)
49 },
50 }
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57 use agent_base::{ApprovalRequest, RiskLevel};
58
59 #[tokio::test]
60 async fn test_auto_mode_approves_all() {
61 let handler = AutoApprovalHandler::new(ApprovalMode::Auto);
62 let request = ApprovalRequest {
63 title: "Delete file".into(),
64 message: "This will delete /tmp/important.txt".into(),
65 action_key: None,
66 risk_level: RiskLevel::Destructive,
67 raw: None,
68 };
69 let cancel = tokio_util::sync::CancellationToken::new();
70 let decision = handler.approve(request, cancel).await.unwrap();
71 assert_eq!(decision, ApprovalDecision::AllowAlways);
72 }
73
74 #[tokio::test]
75 async fn test_deny_all_mode_denies() {
76 let handler = AutoApprovalHandler::new(ApprovalMode::DenyAll);
77 let request = ApprovalRequest {
78 title: "Read file".into(),
79 message: "Read /tmp/safe.txt".into(),
80 action_key: None,
81 risk_level: RiskLevel::Safe,
82 raw: None,
83 };
84 let cancel = tokio_util::sync::CancellationToken::new();
85 let decision = handler.approve(request, cancel).await.unwrap();
86 assert_eq!(decision, ApprovalDecision::Deny);
87 }
88
89 #[tokio::test]
90 async fn test_deny_all_denies_even_safe_operations() {
91 let handler = AutoApprovalHandler::new(ApprovalMode::DenyAll);
92 let request = ApprovalRequest {
93 title: "Safe thing".into(),
94 message: "Perfectly safe".into(),
95 action_key: None,
96 risk_level: RiskLevel::Safe,
97 raw: None,
98 };
99 let cancel = tokio_util::sync::CancellationToken::new();
100 let decision = handler.approve(request, cancel).await.unwrap();
101 assert_eq!(decision, ApprovalDecision::Deny);
102 }
103}