strands_agents/handlers/
mod.rs1use std::sync::Arc;
4
5#[derive(Debug, Clone, Default)]
7pub struct CallbackEvent {
8 pub reasoning_text: Option<String>,
9 pub data: Option<String>,
10 pub complete: bool,
11 pub current_tool_use: Option<CurrentToolUse>,
12}
13
14#[derive(Debug, Clone, PartialEq)]
16pub struct CurrentToolUse {
17 pub name: String,
18 pub tool_use_id: Option<String>,
19 pub input: Option<serde_json::Value>,
20}
21
22pub trait CallbackHandler: Send + Sync {
24 fn call(&mut self, event: &CallbackEvent);
26}
27
28pub struct PrintingCallbackHandler {
30 tool_count: u32,
31 previous_tool_use: Option<CurrentToolUse>,
32 verbose_tool_use: bool,
33}
34
35impl PrintingCallbackHandler {
36 pub fn new(verbose_tool_use: bool) -> Self {
38 Self {
39 tool_count: 0,
40 previous_tool_use: None,
41 verbose_tool_use,
42 }
43 }
44}
45
46impl Default for PrintingCallbackHandler {
47 fn default() -> Self {
48 Self::new(true)
49 }
50}
51
52impl CallbackHandler for PrintingCallbackHandler {
53 fn call(&mut self, event: &CallbackEvent) {
54 if let Some(ref reasoning_text) = event.reasoning_text {
55 print!("{}", reasoning_text);
56 }
57
58 if let Some(ref data) = event.data {
59 if event.complete {
60 println!("{}", data);
61 } else {
62 print!("{}", data);
63 }
64 }
65
66 if let Some(ref current_tool_use) = event.current_tool_use {
67 if self.previous_tool_use.as_ref() != Some(current_tool_use) {
68 self.previous_tool_use = Some(current_tool_use.clone());
69 self.tool_count += 1;
70 if self.verbose_tool_use {
71 println!("\nTool #{}: {}", self.tool_count, current_tool_use.name);
72 }
73 }
74 }
75
76 if event.complete && event.data.is_some() {
77 println!();
78 }
79 }
80}
81
82pub struct CompositeCallbackHandler {
84 handlers: Vec<Arc<std::sync::Mutex<dyn CallbackHandler>>>,
85}
86
87impl CompositeCallbackHandler {
88 pub fn new() -> Self {
90 Self {
91 handlers: Vec::new(),
92 }
93 }
94
95 pub fn add_handler(&mut self, handler: impl CallbackHandler + 'static) {
97 self.handlers.push(Arc::new(std::sync::Mutex::new(handler)));
98 }
99}
100
101impl Default for CompositeCallbackHandler {
102 fn default() -> Self {
103 Self::new()
104 }
105}
106
107impl CallbackHandler for CompositeCallbackHandler {
108 fn call(&mut self, event: &CallbackEvent) {
109 for handler in &self.handlers {
110 if let Ok(mut h) = handler.lock() {
111 h.call(event);
112 }
113 }
114 }
115}
116
117pub struct NullCallbackHandler;
119
120impl CallbackHandler for NullCallbackHandler {
121 fn call(&mut self, _event: &CallbackEvent) {
122 }
123}
124
125pub fn null_callback_handler() -> NullCallbackHandler {
127 NullCallbackHandler
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133
134 #[test]
135 fn test_printing_callback_handler() {
136 let mut handler = PrintingCallbackHandler::new(true);
137
138 let event = CallbackEvent {
139 data: Some("Hello".to_string()),
140 complete: false,
141 ..Default::default()
142 };
143
144 handler.call(&event);
145 }
146
147 #[test]
148 fn test_null_callback_handler() {
149 let mut handler = null_callback_handler();
150
151 let event = CallbackEvent {
152 data: Some("Should be ignored".to_string()),
153 ..Default::default()
154 };
155
156 handler.call(&event);
157 }
158
159 #[test]
160 fn test_composite_callback_handler() {
161 let mut composite = CompositeCallbackHandler::new();
162 composite.add_handler(NullCallbackHandler);
163
164 let event = CallbackEvent::default();
165 composite.call(&event);
166 }
167}
168