Skip to main content

lc_callbacks/
base.rs

1// lc-callbacks/src/base.rs
2//! Base callback handler trait
3
4use async_trait::async_trait;
5use std::sync::Arc;
6
7use super::run_tree::RunTree;
8use lc_schema::Message;
9
10/// Callback handler trait for tracing and monitoring
11///
12/// Implement this trait to receive callbacks during execution.
13/// Can be used for logging, tracing, monitoring, etc.
14#[async_trait]
15pub trait CallbackHandler: Send + Sync {
16    // ============ Lifecycle callbacks ============
17
18    /// Called when any run starts
19    async fn on_run_start(&self, run: &RunTree);
20
21    /// Called when a run ends successfully
22    async fn on_run_end(&self, run: &RunTree);
23
24    /// Called when a run fails
25    async fn on_run_error(&self, run: &RunTree, error: &str);
26
27    // ============ LLM callbacks ============
28
29    /// Called when an LLM starts
30    async fn on_llm_start(&self, run: &RunTree, _messages: &[Message]) {
31        self.on_run_start(run).await;
32    }
33
34    /// Called when an LLM ends
35    async fn on_llm_end(&self, run: &RunTree, _response: &str) {
36        self.on_run_end(run).await;
37    }
38
39    /// Called for each new token during streaming
40    async fn on_llm_new_token(&self, _run: &RunTree, _token: &str) {
41        // Default: do nothing
42    }
43
44    /// Called for each thinking token during streaming (extended thinking).
45    ///
46    /// Anthropic's extended thinking feature emits thinking content blocks
47    /// before the final text response. This callback fires for each chunk
48    /// of thinking content, allowing consumers to observe the model's
49    /// reasoning process in real time.
50    async fn on_llm_thinking(&self, _run: &RunTree, _thinking: &str) {
51        // Default: do nothing
52    }
53
54    /// Called when an LLM errors
55    async fn on_llm_error(&self, run: &RunTree, error: &str) {
56        self.on_run_error(run, error).await;
57    }
58
59    // ============ Chain callbacks ============
60
61    /// Called when a chain starts
62    async fn on_chain_start(&self, run: &RunTree, _inputs: &serde_json::Value) {
63        self.on_run_start(run).await;
64    }
65
66    /// Called when a chain ends
67    async fn on_chain_end(&self, run: &RunTree, _outputs: &serde_json::Value) {
68        self.on_run_end(run).await;
69    }
70
71    /// Called when a chain errors
72    async fn on_chain_error(&self, run: &RunTree, error: &str) {
73        self.on_run_error(run, error).await;
74    }
75
76    // ============ Tool callbacks ============
77
78    /// Called when a tool starts
79    async fn on_tool_start(&self, run: &RunTree, _tool_name: &str, _input: &str) {
80        self.on_run_start(run).await;
81    }
82
83    /// Called when a tool ends
84    async fn on_tool_end(&self, run: &RunTree, _output: &str) {
85        self.on_run_end(run).await;
86    }
87
88    /// Called when a tool errors
89    async fn on_tool_error(&self, run: &RunTree, error: &str) {
90        self.on_run_error(run, error).await;
91    }
92
93    // ============ Retriever callbacks ============
94
95    /// Called when a retriever starts
96    async fn on_retriever_start(&self, run: &RunTree, _query: &str) {
97        self.on_run_start(run).await;
98    }
99
100    /// Called when a retriever ends
101    async fn on_retriever_end(&self, run: &RunTree, _documents: &[serde_json::Value]) {
102        self.on_run_end(run).await;
103    }
104
105    /// Called when a retriever errors
106    async fn on_retriever_error(&self, run: &RunTree, error: &str) {
107        self.on_run_error(run, error).await;
108    }
109}
110
111/// Callback manager that handles multiple handlers
112pub struct CallbackManager {
113    inner: Arc<CallbackManagerInner>,
114}
115
116struct CallbackManagerInner {
117    handlers: Vec<Arc<dyn CallbackHandler>>,
118}
119
120impl std::fmt::Debug for CallbackManager {
121    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122        f.debug_struct("CallbackManager")
123            .field("handlers_count", &self.inner.handlers.len())
124            .finish()
125    }
126}
127
128impl CallbackManager {
129    /// Create a new callback manager
130    pub fn new() -> Self {
131        Self {
132            inner: Arc::new(CallbackManagerInner {
133                handlers: Vec::new(),
134            }),
135        }
136    }
137
138    /// Add a callback handler
139    pub fn add_handler(self, handler: Arc<dyn CallbackHandler>) -> Self {
140        let mut handlers = self.inner.handlers.clone();
141        handlers.push(handler);
142        Self {
143            inner: Arc::new(CallbackManagerInner { handlers }),
144        }
145    }
146
147    /// Get all handlers
148    pub fn handlers(&self) -> &[Arc<dyn CallbackHandler>] {
149        &self.inner.handlers
150    }
151
152    /// Check if there are any handlers
153    pub fn is_empty(&self) -> bool {
154        self.inner.handlers.is_empty()
155    }
156}
157
158impl Default for CallbackManager {
159    fn default() -> Self {
160        Self::new()
161    }
162}
163
164impl Clone for CallbackManager {
165    fn clone(&self) -> Self {
166        Self {
167            inner: Arc::clone(&self.inner),
168        }
169    }
170}
171
172// ============ Helper methods for dispatching callbacks ============
173
174impl CallbackManager {
175    /// Dispatch `on_chain_start` to all handlers.
176    pub async fn dispatch_chain_start(&self, run: &RunTree, inputs: &serde_json::Value) {
177        for handler in &self.inner.handlers {
178            handler.on_chain_start(run, inputs).await;
179        }
180    }
181
182    /// Dispatch `on_chain_end` to all handlers.
183    pub async fn dispatch_chain_end(&self, run: &RunTree, outputs: &serde_json::Value) {
184        for handler in &self.inner.handlers {
185            handler.on_chain_end(run, outputs).await;
186        }
187    }
188
189    /// Dispatch `on_chain_error` to all handlers.
190    pub async fn dispatch_chain_error(&self, run: &RunTree, error: &str) {
191        for handler in &self.inner.handlers {
192            handler.on_chain_error(run, error).await;
193        }
194    }
195
196    /// Dispatch `on_llm_start` to all handlers.
197    pub async fn dispatch_llm_start(&self, run: &RunTree, messages: &[lc_schema::Message]) {
198        for handler in &self.inner.handlers {
199            handler.on_llm_start(run, messages).await;
200        }
201    }
202
203    /// Dispatch `on_llm_end` to all handlers.
204    pub async fn dispatch_llm_end(&self, run: &RunTree, response: &str) {
205        for handler in &self.inner.handlers {
206            handler.on_llm_end(run, response).await;
207        }
208    }
209
210    /// Dispatch `on_llm_error` to all handlers.
211    pub async fn dispatch_llm_error(&self, run: &RunTree, error: &str) {
212        for handler in &self.inner.handlers {
213            handler.on_llm_error(run, error).await;
214        }
215    }
216
217    /// Dispatch `on_llm_new_token` to all handlers.
218    pub async fn dispatch_llm_new_token(&self, run: &RunTree, token: &str) {
219        for handler in &self.inner.handlers {
220            handler.on_llm_new_token(run, token).await;
221        }
222    }
223
224    /// Dispatch `on_tool_start` to all handlers.
225    pub async fn dispatch_tool_start(&self, run: &RunTree, tool_name: &str, input: &str) {
226        for handler in &self.inner.handlers {
227            handler.on_tool_start(run, tool_name, input).await;
228        }
229    }
230
231    /// Dispatch `on_tool_end` to all handlers.
232    pub async fn dispatch_tool_end(&self, run: &RunTree, output: &str) {
233        for handler in &self.inner.handlers {
234            handler.on_tool_end(run, output).await;
235        }
236    }
237
238    /// Dispatch `on_tool_error` to all handlers.
239    pub async fn dispatch_tool_error(&self, run: &RunTree, error: &str) {
240        for handler in &self.inner.handlers {
241            handler.on_tool_error(run, error).await;
242        }
243    }
244
245    /// Dispatch `on_retriever_start` to all handlers.
246    pub async fn dispatch_retriever_start(&self, run: &RunTree, query: &str) {
247        for handler in &self.inner.handlers {
248            handler.on_retriever_start(run, query).await;
249        }
250    }
251
252    /// Dispatch `on_retriever_end` to all handlers.
253    pub async fn dispatch_retriever_end(&self, run: &RunTree, documents: &[serde_json::Value]) {
254        for handler in &self.inner.handlers {
255            handler.on_retriever_end(run, documents).await;
256        }
257    }
258
259    /// Dispatch `on_retriever_error` to all handlers.
260    pub async fn dispatch_retriever_error(&self, run: &RunTree, error: &str) {
261        for handler in &self.inner.handlers {
262            handler.on_retriever_error(run, error).await;
263        }
264    }
265}