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, TerminalRequirementFailure};
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 TerminalRepairScheduled {
88 attempt: u32,
90 failure: TerminalRequirementFailure,
92 },
93}
94
95pub(crate) trait AgentObserver: Send + Sync {
96 fn emit(&self, event: AgentStreamEvent);
97
98 fn backpressured(&self) -> bool {
99 false
100 }
101}
102
103#[derive(Debug)]
104pub(crate) struct NoopObserver;
105
106impl AgentObserver for NoopObserver {
107 fn emit(&self, _event: AgentStreamEvent) {}
108}
109
110#[derive(Clone, Debug, Default)]
111pub(crate) struct BufferedObserver {
112 events: Arc<Mutex<VecDeque<AgentStreamEvent>>>,
113}
114
115impl BufferedObserver {
116 pub(crate) fn events(&self) -> Arc<Mutex<VecDeque<AgentStreamEvent>>> {
117 self.events.clone()
118 }
119}
120
121impl AgentObserver for BufferedObserver {
122 fn emit(&self, event: AgentStreamEvent) {
123 self.events
124 .lock()
125 .unwrap_or_else(std::sync::PoisonError::into_inner)
126 .push_back(event);
127 }
128
129 fn backpressured(&self) -> bool {
130 true
131 }
132}
133
134pub(crate) async fn emit_agent_event(observer: &dyn AgentObserver, event: AgentStreamEvent) {
135 observer.emit(event);
136 if observer.backpressured() {
137 YieldOnce::new().await;
138 }
139}
140
141struct YieldOnce {
142 yielded: bool,
143}
144
145impl YieldOnce {
146 const fn new() -> Self {
147 Self { yielded: false }
148 }
149}
150
151impl Future for YieldOnce {
152 type Output = ();
153
154 fn poll(mut self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Self::Output> {
155 if self.yielded {
156 Poll::Ready(())
157 } else {
158 self.yielded = true;
159 context.waker().wake_by_ref();
160 Poll::Pending
161 }
162 }
163}
164
165#[must_use = "streams do nothing unless polled"]
167pub struct AgentEventStream<'a> {
168 execution: Option<AgentFuture<'a, Result<AgentOutcome, AgentError>>>,
169 events: Arc<Mutex<VecDeque<AgentStreamEvent>>>,
170 failure: Option<AgentError>,
171 finished: bool,
172}
173
174impl<'a> AgentEventStream<'a> {
175 pub(crate) fn new(
176 execution: AgentFuture<'a, Result<AgentOutcome, AgentError>>,
177 events: Arc<Mutex<VecDeque<AgentStreamEvent>>>,
178 ) -> Self {
179 Self {
180 execution: Some(execution),
181 events,
182 failure: None,
183 finished: false,
184 }
185 }
186
187 fn events(&self) -> MutexGuard<'_, VecDeque<AgentStreamEvent>> {
188 self.events
189 .lock()
190 .unwrap_or_else(std::sync::PoisonError::into_inner)
191 }
192
193 fn pop_event(&self) -> Option<AgentStreamEvent> {
194 self.events().pop_front()
195 }
196}
197
198impl Stream for AgentEventStream<'_> {
199 type Item = Result<AgentStreamEvent, AgentError>;
200
201 fn poll_next(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Option<Self::Item>> {
202 let this = self.get_mut();
203 if let Some(event) = this.pop_event() {
204 return Poll::Ready(Some(Ok(event)));
205 }
206 if let Some(execution) = this.execution.as_mut() {
207 match execution.as_mut().poll(context) {
208 Poll::Pending => {
209 return this
210 .pop_event()
211 .map_or(Poll::Pending, |event| Poll::Ready(Some(Ok(event))));
212 }
213 Poll::Ready(Ok(_outcome)) => {
214 this.execution = None;
215 }
216 Poll::Ready(Err(error)) => {
217 this.execution = None;
218 this.failure = Some(error);
219 }
220 }
221 }
222 if let Some(event) = this.pop_event() {
223 return Poll::Ready(Some(Ok(event)));
224 }
225 if let Some(error) = this.failure.take() {
226 return Poll::Ready(Some(Err(error)));
227 }
228 if this.execution.is_none() {
229 this.finished = true;
230 }
231 if this.finished {
232 Poll::Ready(None)
233 } else {
234 Poll::Pending
235 }
236 }
237}
238
239impl std::fmt::Debug for AgentEventStream<'_> {
240 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
241 formatter
242 .debug_struct("AgentEventStream")
243 .field("queued_events", &self.events().len())
244 .field("has_execution", &self.execution.is_some())
245 .field("has_failure", &self.failure.is_some())
246 .field("finished", &self.finished)
247 .finish()
248 }
249}