Skip to main content

agent_base/engine/
approval.rs

1use async_trait::async_trait;
2
3use crate::types::{AgentResult, ApprovalDecision, ApprovalRequest};
4
5/// Trait for handling tool approval requests.
6///
7/// # Cancellation Contract
8///
9/// Implementors MUST handle cancellation via the provided `cancel_token`.
10/// The token is cancelled when the user interrupts the agent (e.g., Ctrl+C).
11///
12/// - **Async handlers** (channels, timers): race against `cancel_token.cancelled()` using `tokio::select!`
13/// - **Blocking handlers** (stdin, file IO): use `tokio::task::spawn_blocking` + `tokio::select!` to avoid blocking the tokio runtime
14///
15/// # Timeout
16///
17/// The caller (`process_approval`) wraps this method with a 300-second timeout.
18/// If the handler does not return within 300s, the approval is denied automatically.
19///
20/// # Example (blocking stdin)
21///
22/// ```ignore
23/// async fn approve(&self, request: ApprovalRequest, cancel_token: CancellationToken) -> AgentResult<ApprovalDecision> {
24///     tokio::select! {
25///         _ = cancel_token.cancelled() => Err(AgentError::Cancelled),
26///         result = tokio::task::spawn_blocking(|| read_stdin()) => result?,
27///     }
28/// }
29/// ```
30#[async_trait]
31pub trait ApprovalHandler: Send + Sync {
32    async fn approve(
33        &self,
34        request: ApprovalRequest,
35        cancel_token: tokio_util::sync::CancellationToken,
36    ) -> AgentResult<ApprovalDecision>;
37}
38
39#[derive(Clone, Debug, Default)]
40pub struct DenyAllApprovalHandler;
41
42#[async_trait]
43impl ApprovalHandler for DenyAllApprovalHandler {
44    async fn approve(
45        &self,
46        _request: ApprovalRequest,
47        _cancel_token: tokio_util::sync::CancellationToken,
48    ) -> AgentResult<ApprovalDecision> {
49        Ok(ApprovalDecision::Deny)
50    }
51}
52
53#[derive(Clone, Debug, Default)]
54pub struct AllowAllApprovalHandler;
55
56#[async_trait]
57impl ApprovalHandler for AllowAllApprovalHandler {
58    async fn approve(
59        &self,
60        _request: ApprovalRequest,
61        _cancel_token: tokio_util::sync::CancellationToken,
62    ) -> AgentResult<ApprovalDecision> {
63        Ok(ApprovalDecision::AllowAlways)
64    }
65}