abu_agent/hook/
consolelog.rs1use colored::Colorize;
2use super::{Hook, HookEvent};
3
4pub struct ConsoleLoggerHook;
5
6impl ConsoleLoggerHook {
7 pub fn new() -> Self {
8 Self
9 }
10
11 fn truncate(text: &str, max_len: usize) -> String {
12 let text = text.replace('\n', " ");
13 if text.chars().count() > max_len {
14 let truncated: String = text.chars().take(max_len).collect();
15 format!("{}...", truncated)
16 } else {
17 text
18 }
19 }
20}
21
22#[async_trait::async_trait]
23impl Hook for ConsoleLoggerHook {
24 type Error = std::convert::Infallible;
25
26 #[allow(unused)]
27 async fn on_event(&self, event: &HookEvent<'_>) -> Result<(), Self::Error> {
28 match event {
29 HookEvent::AgentStart { query } => {
33 println!("\n{}", "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓".bold().blue());
34 println!("┃ 🤖 {} {}", "AGENT START".bold().green(), "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━".bold().blue());
35 println!("┃ {} {}", "Query:".bold().cyan(), query.white());
36 println!("{}", "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛".bold().blue());
37 }
38 HookEvent::AgentEnd { result } => {
39 println!("\n{}", "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓".bold().blue());
40 println!("┃ 🏁 {} {}", "AGENT FINISHED".bold().green(), "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━".bold().blue());
41 println!("┃ {}", result.green());
42 println!("{}", "┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\n".bold().blue());
43 }
44 HookEvent::AgentMaxIteration => {
45 println!("\n{}", "🛑 [WARNING] Agent halted: Reached maximum iterations!".bold().on_red().white());
46 }
47
48 HookEvent::AgentStepStart { step } => {
52 println!("\n{}", format!("╭── [ 🔄 Step {} ] ───────────────────────────────────────────", step).bold().yellow());
53 }
54 HookEvent::AgentStepEnd { step, message } => {
55 let status = if message.tool_calls.is_empty() {
56 "Final Answer Generated".green()
57 } else {
58 format!("Requested {} Tools", message.tool_calls.len()).yellow()
59 };
60 println!("{}", format!("╰── [ Step {} End ] : {} ──────────────────────────────────────", step, status).bold().yellow());
61 }
62
63 HookEvent::MemorySearch { query, results } => {
67 let count = results.len();
68 if count > 0 {
69 println!("│ 🧠 {} Searched for '{}', found {} records.", "Memory:".bold().cyan(), Self::truncate(query, 20), count);
70 } else {
71 println!("│ 🧠 {} No relevant memory found.", "Memory:".bold().bright_black());
72 }
73 }
74 HookEvent::MemoryAdd { user, assistant } => {
75 println!("│ 💾 {} Saved latest interaction to memory.", "Memory:".bold().cyan());
76 }
80 HookEvent::ContextBuild { query: _, messages } => {
81 println!("│ 🏗️ {} Assembled {} messages.", "Context:".bold().magenta(), messages.len());
82 }
83
84 HookEvent::LlmStart { step: _, messages } => {
88 println!("│ 💬 {} Sending prompt ({} msgs)...", "LLM Req:".bold().blue(), messages.len());
89 }
90 HookEvent::LlmEnd { step: _, message } => {
91 if !message.content.is_empty() {
92 println!("│ 💡 {} {}", "LLM Res:".bold().blue(), Self::truncate(&message.content, 80).white());
93 }
94 if !message.tool_calls.is_empty() {
95 println!("│ 🛠️ {} Model decided to call {} tool(s).", "LLM Res:".bold().yellow(), message.tool_calls.len());
96 }
97 }
98
99 HookEvent::ToolStart { step: _, tool_call } => {
103 let args = Self::truncate(&tool_call.arguments, 50);
104 println!("│ ▶ {} {}({})", "Executing:".bold().magenta(), tool_call.name.bold().white(), args.bright_black());
105 }
106 HookEvent::ToolEnd { step: _, result } => {
107 let out = Self::truncate(&result.context, 60);
108 if result.is_error {
109 println!("│ ❌ {} {}", "Tool Fail:".bold().red(), out.red());
110 } else {
111 println!("│ ✅ {} {}", "Tool Done:".bold().green(), out.bright_black());
112 }
113 }
114 HookEvent::ToolError { step: _, context } => {
115 println!("│ 🚨 {} {}", "Tool Fatal:".bold().red().on_black(), context.red());
116 }
117 }
118
119 Ok(())
120 }
121}