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