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