Skip to main content

agentkit_reporting/
channel.rs

1//! Channel-based reporter adapter.
2//!
3//! [`ChannelReporter`] forwards events to another thread or task via a
4//! [`std::sync::mpsc::Sender`]. This keeps the observer contract synchronous
5//! while allowing expensive event processing to happen off the driver's hot
6//! path.
7
8use std::sync::mpsc::{self, Receiver, Sender};
9
10use agentkit_loop::{AgentEvent, LoopObserver};
11
12use crate::ReportError;
13use crate::policy::FallibleObserver;
14
15/// Reporter adapter that forwards events over a channel.
16///
17/// Use this when you need expensive or async event processing without
18/// blocking the agent loop. The receiving end can live on a dedicated
19/// thread or async task.
20///
21/// # Example
22///
23/// ```rust
24/// use agentkit_reporting::ChannelReporter;
25///
26/// let (reporter, rx) = ChannelReporter::pair();
27///
28/// // Spawn a consumer on another thread.
29/// std::thread::spawn(move || {
30///     while let Ok(event) = rx.recv() {
31///         println!("{event:?}");
32///     }
33/// });
34///
35/// // `reporter` implements `LoopObserver` — hand it to the agent loop.
36/// ```
37pub struct ChannelReporter {
38    sender: Sender<AgentEvent>,
39}
40
41impl ChannelReporter {
42    /// Creates a `ChannelReporter` from an existing sender.
43    pub fn new(sender: Sender<AgentEvent>) -> Self {
44        Self { sender }
45    }
46
47    /// Creates a `ChannelReporter` together with the receiving end of the
48    /// channel.
49    ///
50    /// This is a convenience wrapper around [`std::sync::mpsc::channel`].
51    pub fn pair() -> (Self, Receiver<AgentEvent>) {
52        let (sender, receiver) = mpsc::channel();
53        (Self { sender }, receiver)
54    }
55}
56
57impl LoopObserver for ChannelReporter {
58    fn handle_event(&mut self, event: AgentEvent) {
59        // Silently drop if the receiver is gone — reporters are non-fatal.
60        let _ = self.sender.send(event);
61    }
62}
63
64impl FallibleObserver for ChannelReporter {
65    fn try_handle_event(&mut self, event: &AgentEvent) -> Result<(), ReportError> {
66        self.sender
67            .send(event.clone())
68            .map_err(|_| ReportError::ChannelSend)
69    }
70}