1use std::{
2 collections::VecDeque,
3 future::Future,
4 pin::Pin,
5 sync::{Arc, Mutex, MutexGuard},
6 task::{Context, Poll},
7};
8
9use futures_core::Stream;
10use runifold_core::Usage;
11use runifold_model::{ModelStreamEvent, ToolCall};
12use serde::{Deserialize, Serialize};
13
14use crate::{AgentError, AgentFuture, AgentOutcome};
15
16#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
18#[non_exhaustive]
19pub enum CallableKind {
20 Tool,
22 Agent,
24}
25
26#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
28#[non_exhaustive]
29pub enum AgentStreamEvent {
30 Started {
32 agent: String,
34 },
35 TurnStarted {
37 turn: u32,
39 },
40 Model {
42 turn: u32,
44 event: ModelStreamEvent,
46 },
47 ContextRetrieved {
49 source: String,
51 documents: usize,
53 },
54 CallableStarted {
56 turn: u32,
58 kind: CallableKind,
60 call: ToolCall,
62 },
63 CallableCompleted {
65 turn: u32,
67 kind: CallableKind,
69 call_id: String,
71 name: String,
73 success: bool,
75 },
76 UsageUpdated {
78 usage: Usage,
80 },
81 Completed {
83 outcome: AgentOutcome,
85 },
86}
87
88pub(crate) trait AgentObserver: Send + Sync {
89 fn emit(&self, event: AgentStreamEvent);
90
91 fn backpressured(&self) -> bool {
92 false
93 }
94}
95
96#[derive(Debug)]
97pub(crate) struct NoopObserver;
98
99impl AgentObserver for NoopObserver {
100 fn emit(&self, _event: AgentStreamEvent) {}
101}
102
103#[derive(Clone, Debug, Default)]
104pub(crate) struct BufferedObserver {
105 events: Arc<Mutex<VecDeque<AgentStreamEvent>>>,
106}
107
108impl BufferedObserver {
109 pub(crate) fn events(&self) -> Arc<Mutex<VecDeque<AgentStreamEvent>>> {
110 self.events.clone()
111 }
112}
113
114impl AgentObserver for BufferedObserver {
115 fn emit(&self, event: AgentStreamEvent) {
116 self.events
117 .lock()
118 .unwrap_or_else(std::sync::PoisonError::into_inner)
119 .push_back(event);
120 }
121
122 fn backpressured(&self) -> bool {
123 true
124 }
125}
126
127pub(crate) async fn emit_agent_event(observer: &dyn AgentObserver, event: AgentStreamEvent) {
128 observer.emit(event);
129 if observer.backpressured() {
130 YieldOnce::new().await;
131 }
132}
133
134struct YieldOnce {
135 yielded: bool,
136}
137
138impl YieldOnce {
139 const fn new() -> Self {
140 Self { yielded: false }
141 }
142}
143
144impl Future for YieldOnce {
145 type Output = ();
146
147 fn poll(mut self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Self::Output> {
148 if self.yielded {
149 Poll::Ready(())
150 } else {
151 self.yielded = true;
152 context.waker().wake_by_ref();
153 Poll::Pending
154 }
155 }
156}
157
158#[must_use = "streams do nothing unless polled"]
160pub struct AgentEventStream<'a> {
161 execution: Option<AgentFuture<'a, Result<AgentOutcome, AgentError>>>,
162 events: Arc<Mutex<VecDeque<AgentStreamEvent>>>,
163 failure: Option<AgentError>,
164 finished: bool,
165}
166
167impl<'a> AgentEventStream<'a> {
168 pub(crate) fn new(
169 execution: AgentFuture<'a, Result<AgentOutcome, AgentError>>,
170 events: Arc<Mutex<VecDeque<AgentStreamEvent>>>,
171 ) -> Self {
172 Self {
173 execution: Some(execution),
174 events,
175 failure: None,
176 finished: false,
177 }
178 }
179
180 fn events(&self) -> MutexGuard<'_, VecDeque<AgentStreamEvent>> {
181 self.events
182 .lock()
183 .unwrap_or_else(std::sync::PoisonError::into_inner)
184 }
185
186 fn pop_event(&self) -> Option<AgentStreamEvent> {
187 self.events().pop_front()
188 }
189}
190
191impl Stream for AgentEventStream<'_> {
192 type Item = Result<AgentStreamEvent, AgentError>;
193
194 fn poll_next(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Option<Self::Item>> {
195 let this = self.get_mut();
196 if let Some(event) = this.pop_event() {
197 return Poll::Ready(Some(Ok(event)));
198 }
199 if let Some(execution) = this.execution.as_mut() {
200 match execution.as_mut().poll(context) {
201 Poll::Pending => {
202 return this
203 .pop_event()
204 .map_or(Poll::Pending, |event| Poll::Ready(Some(Ok(event))));
205 }
206 Poll::Ready(Ok(_outcome)) => {
207 this.execution = None;
208 }
209 Poll::Ready(Err(error)) => {
210 this.execution = None;
211 this.failure = Some(error);
212 }
213 }
214 }
215 if let Some(event) = this.pop_event() {
216 return Poll::Ready(Some(Ok(event)));
217 }
218 if let Some(error) = this.failure.take() {
219 return Poll::Ready(Some(Err(error)));
220 }
221 if this.execution.is_none() {
222 this.finished = true;
223 }
224 if this.finished {
225 Poll::Ready(None)
226 } else {
227 Poll::Pending
228 }
229 }
230}
231
232impl std::fmt::Debug for AgentEventStream<'_> {
233 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
234 formatter
235 .debug_struct("AgentEventStream")
236 .field("queued_events", &self.events().len())
237 .field("has_execution", &self.execution.is_some())
238 .field("has_failure", &self.failure.is_some())
239 .field("finished", &self.finished)
240 .finish()
241 }
242}