Skip to main content

lc_callbacks/handlers/
langsmith_handler.rs

1// lc-callbacks/src/handlers/langsmith_handler.rs
2//! LangSmith callback handler
3
4use async_trait::async_trait;
5use std::sync::Arc;
6
7use crate::{CallbackHandler, LangSmithClient, LangSmithConfig, LangSmithError, RunTree};
8use lc_schema::Message;
9
10/// LangSmith callback handler
11///
12/// Automatically sends trace data to LangSmith.
13pub struct LangSmithHandler {
14    client: Arc<LangSmithClient>,
15    async_mode: bool,
16}
17
18impl LangSmithHandler {
19    /// Creates a new handler with the given LangSmith configuration.
20    pub fn new(config: LangSmithConfig) -> Self {
21        Self {
22            client: Arc::new(LangSmithClient::new(config)),
23            async_mode: false, // default to sync mode so the request completes
24        }
25    }
26
27    /// Creates a handler from environment variables.
28    pub fn from_env() -> Result<Self, LangSmithError> {
29        let config = LangSmithConfig::from_env()?;
30        Ok(Self::new(config))
31    }
32
33    /// Enables or disables asynchronous mode for sending traces.
34    pub fn with_async_mode(mut self, async_mode: bool) -> Self {
35        self.async_mode = async_mode;
36        self
37    }
38}
39
40#[async_trait]
41impl CallbackHandler for LangSmithHandler {
42    async fn on_run_start(&self, run: &RunTree) {
43        if !self.client.is_tracing_enabled() {
44            return;
45        }
46
47        if self.async_mode {
48            let run = run.clone();
49            let client = Arc::clone(&self.client);
50            tokio::spawn(async move {
51                if let Err(e) = client.create_run(&run).await {
52                    eprintln!("[LangSmith] create_run failed: {}", e);
53                }
54            });
55        } else if let Err(e) = self.client.create_run(run).await {
56            eprintln!("[LangSmith] create_run failed: {}", e);
57        }
58    }
59
60    async fn on_run_end(&self, run: &RunTree) {
61        if !self.client.is_tracing_enabled() {
62            return;
63        }
64
65        if self.async_mode {
66            let run = run.clone();
67            let client = Arc::clone(&self.client);
68            tokio::spawn(async move {
69                if let Err(e) = client.update_run(&run).await {
70                    eprintln!("[LangSmith] update_run failed: {}", e);
71                }
72            });
73        } else if let Err(e) = self.client.update_run(run).await {
74            eprintln!("[LangSmith] update_run failed: {}", e);
75        }
76    }
77
78    async fn on_run_error(&self, run: &RunTree, error: &str) {
79        let mut run = run.clone();
80        run.end_with_error(error);
81        self.on_run_end(&run).await;
82    }
83
84    async fn on_llm_start(&self, run: &RunTree, _messages: &[Message]) {
85        self.on_run_start(run).await;
86    }
87
88    async fn on_llm_end(&self, run: &RunTree, _response: &str) {
89        self.on_run_end(run).await;
90    }
91
92    async fn on_llm_error(&self, run: &RunTree, error: &str) {
93        self.on_run_error(run, error).await;
94    }
95
96    async fn on_chain_start(&self, run: &RunTree, _inputs: &serde_json::Value) {
97        self.on_run_start(run).await;
98    }
99
100    async fn on_chain_end(&self, run: &RunTree, _outputs: &serde_json::Value) {
101        self.on_run_end(run).await;
102    }
103
104    async fn on_chain_error(&self, run: &RunTree, error: &str) {
105        self.on_run_error(run, error).await;
106    }
107
108    async fn on_tool_start(&self, run: &RunTree, _tool_name: &str, _input: &str) {
109        self.on_run_start(run).await;
110    }
111
112    async fn on_tool_end(&self, run: &RunTree, _output: &str) {
113        self.on_run_end(run).await;
114    }
115
116    async fn on_tool_error(&self, run: &RunTree, error: &str) {
117        self.on_run_error(run, error).await;
118    }
119
120    async fn on_retriever_start(&self, run: &RunTree, _query: &str) {
121        self.on_run_start(run).await;
122    }
123
124    async fn on_retriever_end(&self, run: &RunTree, _documents: &[serde_json::Value]) {
125        self.on_run_end(run).await;
126    }
127
128    async fn on_retriever_error(&self, run: &RunTree, error: &str) {
129        self.on_run_error(run, error).await;
130    }
131}