lc_callbacks/handlers/
langsmith_handler.rs1use async_trait::async_trait;
5use std::sync::Arc;
6
7use crate::{CallbackHandler, LangSmithClient, LangSmithConfig, LangSmithError, RunTree};
8use lc_schema::Message;
9
10pub struct LangSmithHandler {
14 client: Arc<LangSmithClient>,
15 async_mode: bool,
16}
17
18impl LangSmithHandler {
19 pub fn new(config: LangSmithConfig) -> Self {
21 Self {
22 client: Arc::new(LangSmithClient::new(config)),
23 async_mode: false, }
25 }
26
27 pub fn from_env() -> Result<Self, LangSmithError> {
29 let config = LangSmithConfig::from_env()?;
30 Ok(Self::new(config))
31 }
32
33 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}