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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
//! Observation channels: the Agent publishes process events internally, and the environment / UI side subscribes.
//!
//! Division of labor in the channel family: conversation channels
//! [`MessageChannel`](crate::message_channel::MessageChannel) carry request-response and notifications
//! between humans and Agents (`ask` / `notify`); observation channels carry the process events produced by the
//! Agent runtime (`publish` / `subscribe`) for the environment / UI / observability side to subscribe to,
//! with no reply expected.
//!
//! Two implementations, chosen by the number of subscribers:
//! - [`BroadcastEventChannel`] — multiple subscribers share the event stream; slow subscribers drop the oldest,
//! and events published before subscribing are never received;
//! - [`MpscEventChannel`] — a single subscriber; strictly ordered and lossless within capacity,
//! dropping new events when full.
//!
//! # Publishing is always non-blocking
//!
//! The Agent loop must not be held up by slow observers: when nobody is subscribed or the buffer is full,
//! events are **silently dropped** — events are process snapshots, missed is missed; no replay, no
//! backpressure, and publish calls return synchronously.
//!
//! The payload is uniformly `Arc<dyn AgentEvent>`: each Agent defines its own event type (e.g.
//! [`ReActEvent`](crate::agent::ReActEvent)) and plugs in by implementing [`AgentEvent`] with it;
//! consumers downcast via `as_any` to a known type for precise handling, and fall back to
//! [`name`](AgentEvent::name) to display unknown types.
//!
//! # Choosing an implementation
//!
//! - multiple subscribers (UI + logs + metrics from one source) → [`BroadcastEventChannel`];
//! - a single subscriber (one consumer with exclusive access) → [`MpscEventChannel`].
//!
//! Both can drop events (broadcast drops the oldest, a single queue drops new ones when full) — that is a
//! deliberate trade-off of observation semantics; interactions that need reliable delivery (approval,
//! confirmation) go through [`MessageChannel`](crate::message_channel::MessageChannel) and must not be
//! carried by event channels.
pub use BroadcastEventChannel;
pub use MpscEventChannel;
use crateAgentEvent;
use BoxFuture;
use Arc;
/// The unified receive-end interface: the environment side takes subscribed events out one by one.
///
/// [`recv`](EventReceiver::recv) returning `None` means the channel is closed (all senders dropped) and the
/// event stream has ended; further calls keep returning `None`. Each implementation's drop semantics
/// (broadcast drops the oldest / a single queue drops new ones when full) are handled transparently behind
/// the interface: `recv` never errors, it only yields the events that remain. Dropping the receive end stops
/// consumption — other subscribers of a broadcast channel are unaffected; unconsumed events of a single-queue
/// channel are dropped along with the receive end.
///
/// The interface expresses asynchrony explicitly with `BoxFuture`: `async fn` cannot be a trait-object
/// method, and this type circulates exactly as a trait object (see [`EventChannel::subscribe`]).
///
/// # Example
///
/// After all senders are dropped, `recv` returns `None` and the event stream ends:
///
/// ```rust
/// # #[tokio::main]
/// # async fn main() {
/// use molo::event_channel::{EventChannel, MpscEventChannel};
///
/// let mut rx = {
/// let channel = MpscEventChannel::new(8);
/// channel.subscribe()
/// };
///
/// // The channel goes out of scope here (its only sender disappears) → the stream ends.
/// assert!(rx.recv().await.is_none());
/// # }
/// ```
/// The observation channel abstraction: the Agent publishes events internally, and the environment side subscribes.
///
/// Both implementations behave the same on the publish side (non-blocking, silent drop); the difference is on
/// the subscribe side, see the docs of [`BroadcastEventChannel`] and [`MpscEventChannel`] respectively. For
/// the Agent-side wiring, see [`ReActAgent::with_event_channel`](crate::agent::ReActAgent::with_event_channel):
/// one mount, events of many runs go to the same channel, and each run ends with a `RunEnded` event.
///
/// # Example
///
/// Publish and subscribe through trait objects (the agent side holds `Arc<dyn EventChannel>`, the
/// environment side holds `Box<dyn EventReceiver>`):
///
/// ```rust
/// # #[tokio::main]
/// # async fn main() {
/// use molo::agent::ReActEvent;
/// use molo::event_channel::{BroadcastEventChannel, EventChannel};
/// use std::sync::Arc;
///
/// // Environment side: create the channel, subscribe, then hand the channel to the Agent side.
/// let channel: Arc<dyn EventChannel> = Arc::new(BroadcastEventChannel::new(64));
/// let mut rx = channel.subscribe();
///
/// // Publish from the Agent side; never blocks, silently drops when full or without subscribers.
/// channel.publish(Arc::new(ReActEvent::RunStarted {
/// run_id: "r1".into(),
/// input: "hello".into(),
/// }));
///
/// // The environment side consumes one by one; typed handling via AgentEvent::as_any.
/// let event = rx.recv().await.unwrap();
/// assert_eq!(event.name(), "run.started");
/// # }
/// ```