Skip to main content

abu_agent/hook/
consolelog.rs

1use 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            // ==========================================
30            // Agent 总体生命周期
31            // ==========================================
32            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            // ==========================================
49            // Step 生命周期
50            // ==========================================
51            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            // ==========================================
64            // 记忆与上下文
65            // ==========================================
66            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                // 仅在 Debug 时可以取消注释打印详细记忆
77                // println!("│       User: {}", Self::truncate(user, 30).bright_black());
78                // println!("│       AI:   {}", Self::truncate(assistant, 30).bright_black());
79            }
80            HookEvent::ContextBuild { query: _, messages } => {
81                println!("│  🏗️  {} Assembled {} messages.", "Context:".bold().magenta(), messages.len());
82            }
83
84            // ==========================================
85            // LLM 交互
86            // ==========================================
87            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            // ==========================================
100            // 工具执行
101            // ==========================================
102            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}