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 println!(
80 "\n❌ [{}] ERROR: {}",
81 run.run_type.as_str().to_uppercase(),
82 run.name
83 );
84 println!(" Error: {}", error);
85 }
86
87 async fn on_llm_start(&self, run: &RunTree, messages: &[Message]) {
88 if self.verbose {
89 self.on_run_start(run).await;
90 println!(" Messages: {} message(s)", messages.len());
91 }
92 }
93
94 async fn on_llm_new_token(&self, _run: &RunTree, token: &str) {
95 print!("{}", token);
96 let _ = std::io::stdout().flush();
97 }
98
99 async fn on_tool_start(&self, run: &RunTree, tool_name: &str, input: &str) {
100 if self.verbose {
101 self.on_run_start(run).await;
102 println!(" Tool: {}", tool_name);
103 println!(" Input: {}", input);
104 }
105 }
106
107 async fn on_retriever_start(&self, run: &RunTree, query: &str) {
108 if self.verbose {
109 self.on_run_start(run).await;
110 println!(" Query: {}", query);
111 }
112 }
113
114 async fn on_retriever_end(&self, run: &RunTree, documents: &[serde_json::Value]) {
115 if self.verbose {
116 self.on_run_end(run).await;
117 println!(" Documents: {} result(s)", documents.len());
118 }
119 }
120}