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