1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//! Approval types for human-in-the-loop (HITL) gates.
//!
//! These pure data types live in `wesichain-core` so that `wesichain-agent`
//! can reference them without depending on `wesichain-graph`, which would
//! create a circular dependency.
//!
//! `wesichain-graph` re-exports all of these from `wesichain_graph::hitl`.
use tokio::sync::{mpsc, oneshot};
/// A human's response to an approval request.
#[derive(Debug, Clone)]
pub enum ApprovalDecision {
/// The human approved the action.
Approved { comment: Option<String> },
/// The human denied the action.
Denied { reason: String },
/// The human modified the agent's intended action.
Modified { new_input: String },
}
/// Default action when no human responds within the timeout.
#[derive(Debug, Clone, Copy, Default)]
pub enum ApprovalDefault {
#[default]
Deny,
Approve,
}
/// Sent to the host application when an approval gate fires.
pub struct ApprovalRequest {
/// Unique identifier for this execution run.
pub run_id: String,
/// Opaque checkpoint identifier the host can use to resume.
pub checkpoint_id: String,
/// Human-readable prompt describing what the agent wants to do.
pub prompt: String,
/// Send your [`ApprovalDecision`] here to unblock the gate.
pub respond: oneshot::Sender<ApprovalDecision>,
}
/// Receiving end — your application listens on this for approval requests.
pub struct ApprovalChannel {
rx: mpsc::Receiver<ApprovalRequest>,
}
impl ApprovalChannel {
pub fn new(rx: mpsc::Receiver<ApprovalRequest>) -> Self {
Self { rx }
}
/// Receive the next approval request, or `None` if the sender was dropped.
pub async fn recv(&mut self) -> Option<ApprovalRequest> {
self.rx.recv().await
}
}