1use std::io::{self, Write};
37
38use tracing::{debug, error, trace};
39
40pub trait EventHandler: Send {
48 fn on_text(&mut self, text: &str) {
54 let _ = text;
55 }
56
57 fn on_tool_use(&mut self, tool: &str, input: &serde_json::Value) {
64 let _ = (tool, input);
65 }
66
67 fn on_tool_result(&mut self, result: &str) {
73 let _ = result;
74 }
75
76 fn on_error(&mut self, error: &str) {
82 let _ = error;
83 }
84
85 fn on_complete(&mut self) {}
87}
88
89#[derive(Debug, Default)]
104#[non_exhaustive]
105pub struct PrintEventHandler {
106 show_tools: bool,
108 auto_flush: bool,
110}
111
112impl PrintEventHandler {
113 #[must_use]
115 pub fn new() -> Self {
116 Self::default()
117 }
118
119 #[must_use]
121 pub fn with_tools(mut self) -> Self {
122 self.show_tools = true;
123 self
124 }
125
126 #[must_use]
131 pub fn with_auto_flush(mut self) -> Self {
132 self.auto_flush = true;
133 self
134 }
135}
136
137impl EventHandler for PrintEventHandler {
138 fn on_text(&mut self, text: &str) {
139 print!("{text}");
140 if self.auto_flush {
141 let _ = io::stdout().flush();
142 }
143 trace!(text_len = text.len(), "received text");
144 }
145
146 fn on_tool_use(&mut self, tool: &str, input: &serde_json::Value) {
147 if self.show_tools {
148 println!("\n[Tool: {tool}]");
149 if let Ok(formatted) = serde_json::to_string_pretty(input) {
150 println!("Input: {formatted}");
151 }
152 }
153 debug!(tool = tool, "tool use started");
154 }
155
156 fn on_tool_result(&mut self, result: &str) {
157 if self.show_tools {
158 let preview = if result.len() > 200 {
159 format!("{}...", &result[..200])
160 } else {
161 result.to_string()
162 };
163 println!("[Result: {preview}]");
164 }
165 trace!(result_len = result.len(), "tool result received");
166 }
167
168 fn on_error(&mut self, error_msg: &str) {
169 eprintln!("\nError: {error_msg}");
170 error!(error = error_msg, "streaming error");
171 }
172
173 fn on_complete(&mut self) {
174 println!();
175 debug!("response complete");
176 }
177}
178
179#[derive(Debug, Default)]
194#[non_exhaustive]
195pub struct CollectingEventHandler {
196 text: String,
197 tools_used: Vec<String>,
198 has_error: bool,
199}
200
201impl CollectingEventHandler {
202 #[must_use]
204 pub fn new() -> Self {
205 Self::default()
206 }
207
208 #[must_use]
210 pub fn text(&self) -> &str {
211 &self.text
212 }
213
214 #[must_use]
216 pub fn into_text(self) -> String {
217 self.text
218 }
219
220 #[must_use]
222 pub fn tools_used(&self) -> &[String] {
223 &self.tools_used
224 }
225
226 #[must_use]
228 pub fn has_error(&self) -> bool {
229 self.has_error
230 }
231
232 pub fn clear(&mut self) {
234 self.text.clear();
235 self.tools_used.clear();
236 self.has_error = false;
237 }
238}
239
240impl EventHandler for CollectingEventHandler {
241 fn on_text(&mut self, text: &str) {
242 self.text.push_str(text);
243 }
244
245 fn on_tool_use(&mut self, tool: &str, _input: &serde_json::Value) {
246 self.tools_used.push(tool.to_string());
247 }
248
249 fn on_tool_result(&mut self, _result: &str) {
250 }
252
253 fn on_error(&mut self, _error: &str) {
254 self.has_error = true;
255 }
256
257 fn on_complete(&mut self) {
258 }
260}
261
262#[cfg(test)]
263mod tests {
264 use super::*;
265 use serde_json::json;
266
267 #[test]
268 fn test_should_create_print_handler_with_options() {
269 let handler = PrintEventHandler::new().with_tools().with_auto_flush();
270
271 assert!(handler.show_tools);
272 assert!(handler.auto_flush);
273 }
274
275 #[test]
276 fn test_should_collect_text() {
277 let mut handler = CollectingEventHandler::new();
278
279 handler.on_text("Hello ");
280 handler.on_text("World!");
281
282 assert_eq!(handler.text(), "Hello World!");
283 }
284
285 #[test]
286 fn test_should_track_tools_used() {
287 let mut handler = CollectingEventHandler::new();
288
289 handler.on_tool_use("Read", &json!({"path": "/test"}));
290 handler.on_tool_use("Write", &json!({"path": "/out"}));
291
292 assert_eq!(handler.tools_used(), &["Read", "Write"]);
293 }
294
295 #[test]
296 fn test_should_track_errors() {
297 let mut handler = CollectingEventHandler::new();
298
299 assert!(!handler.has_error());
300
301 handler.on_error("test error");
302
303 assert!(handler.has_error());
304 }
305
306 #[test]
307 fn test_should_clear_collected_state() {
308 let mut handler = CollectingEventHandler::new();
309
310 handler.on_text("test");
311 handler.on_tool_use("Read", &json!({}));
312 handler.on_error("error");
313
314 handler.clear();
315
316 assert!(handler.text().is_empty());
317 assert!(handler.tools_used().is_empty());
318 assert!(!handler.has_error());
319 }
320
321 #[test]
322 fn test_should_take_ownership_of_text() {
323 let mut handler = CollectingEventHandler::new();
324 handler.on_text("owned text");
325
326 let text = handler.into_text();
327
328 assert_eq!(text, "owned text");
329 }
330
331 struct NoOpHandler;
333
334 impl EventHandler for NoOpHandler {}
335
336 #[test]
337 fn test_should_allow_no_op_handler() {
338 let mut handler = NoOpHandler;
339
340 handler.on_text("test");
342 handler.on_tool_use("tool", &json!({}));
343 handler.on_tool_result("result");
344 handler.on_error("error");
345 handler.on_complete();
346 }
347}