lc_callbacks/handlers/
stdout_handler.rs1use async_trait::async_trait;
5use std::io::Write;
6
7use crate::{CallbackHandler, RunTree};
8use lc_schema::Message;
9
10pub struct StdOutHandler {
14 verbose: bool,
15}
16
17impl StdOutHandler {
18 pub fn new() -> Self {
19 Self { verbose: true }
20 }
21
22 pub fn with_verbose(mut self, verbose: bool) -> Self {
23 self.verbose = verbose;
24 self
25 }
26}
27
28impl Default for StdOutHandler {
29 fn default() -> Self {
30 Self::new()
31 }
32}
33
34#[async_trait]
35impl CallbackHandler for StdOutHandler {
36 async fn on_run_start(&self, run: &RunTree) {
37 if self.verbose {
38 println!(
39 "\n{} [{}] START: {}",
40 run.run_type.emoji(),
41 run.run_type.as_str().to_uppercase(),
42 run.name
43 );
44 println!(" ID: {}", run.id);
45 if run.inputs != serde_json::Value::Null {
46 println!(
47 " Inputs: {}",
48 serde_json::to_string_pretty(&run.inputs).unwrap_or_default()
49 );
50 }
51 }
52 }
53
54 async fn on_run_end(&self, run: &RunTree) {
55 if self.verbose {
56 let duration = run
57 .duration_ms()
58 .map(|d| format!("{}ms", d))
59 .unwrap_or_default();
60
61 println!(
62 "\n{} [{}] END: {} ({})",
63 run.run_type.emoji(),
64 run.run_type.as_str().to_uppercase(),
65 run.name,
66 duration
67 );
68
69 if let Some(outputs) = &run.outputs {
70 println!(
71 " Outputs: {}",
72 serde_json::to_string_pretty(outputs).unwrap_or_default()
73 );
74 }
75 }
76 }
77
78 async fn on_run_error(&self, run: &RunTree, error: &str) {
79 if self.verbose {
80 println!(
81 "\n❌ [{}] ERROR: {}",
82 run.run_type.as_str().to_uppercase(),
83 run.name
84 );
85 println!(" Error: {}", error);
86 }
87 }
88
89 async fn on_llm_start(&self, run: &RunTree, messages: &[Message]) {
90 if self.verbose {
91 self.on_run_start(run).await;
92 println!(" Messages: {} message(s)", messages.len());
93 }
94 }
95
96 async fn on_llm_new_token(&self, _run: &RunTree, token: &str) {
97 if self.verbose {
98 print!("{}", token);
99 let _ = std::io::stdout().flush();
100 }
101 }
102
103 async fn on_tool_start(&self, run: &RunTree, tool_name: &str, input: &str) {
104 if self.verbose {
105 self.on_run_start(run).await;
106 println!(" Tool: {}", tool_name);
107 println!(" Input: {}", input);
108 }
109 }
110
111 async fn on_retriever_start(&self, run: &RunTree, query: &str) {
112 if self.verbose {
113 self.on_run_start(run).await;
114 println!(" Query: {}", query);
115 }
116 }
117
118 async fn on_retriever_end(&self, run: &RunTree, documents: &[serde_json::Value]) {
119 if self.verbose {
120 self.on_run_end(run).await;
121 println!(" Documents: {} result(s)", documents.len());
122 }
123 }
124}