Skip to main content

abu_agent/hook/
mod.rs

1mod consolelog;
2pub use consolelog::*;
3mod auditfilelog;
4pub use auditfilelog::*;
5
6use abu_base::chat::{AssistantMessage, ChatMessage, ToolCall};
7use abu_tool::ToolCallResult;
8use serde::Serialize;
9use crate::{AgentError, AgentResult};
10
11/// All runtime events emitted by Agent
12/// 
13/// AgentStart
14///  1. MemorySearch
15///  2. ContextBuild
16///  3. StepStart
17///      1. LlmStart
18///      2. LlmEnd
19///      3. ToolStart
20///      4. ToolEnd
21///  4. StepEnd
22/// AgentEnd
23#[derive(Serialize)]
24pub enum HookEvent<'a> {
25    // ===== agent lifecycle =====
26    AgentStart { query: &'a str, },
27    AgentEnd { result: &'a str, },
28    AgentMaxIteration,
29    AgentStepStart { step: usize, },
30    AgentStepEnd { step: usize, message: &'a AssistantMessage,},
31
32    // ===== context =====
33    ContextBuild { query: &'a str, messages: &'a [ChatMessage] },
34
35    // ===== memory =====
36    MemorySearch { query: &'a str, results: &'a [ChatMessage] },
37    MemoryAdd { user: &'a str, assistant: &'a str },
38
39    // ===== llm =====
40    LlmStart { step: usize, messages: &'a [ChatMessage] },
41    LlmEnd { step: usize, message: &'a AssistantMessage },
42
43    // ===== tool =====
44    ToolStart { step: usize, tool_call: &'a ToolCall },
45    ToolEnd { step: usize, result: &'a ToolCallResult },
46    ToolError { step: usize, context: &'a str },
47}
48
49#[async_trait::async_trait]
50pub trait Hook: Send + Sync {
51    type Error: std::error::Error + Send + Sync + 'static;
52    async fn on_event(&self, event: &HookEvent<'_>) -> Result<(), Self::Error>;
53}
54
55#[derive(Default)]
56pub struct HookManager {
57    hooks: Vec<Box<dyn HookWrap>>,
58}
59
60impl HookManager {
61    pub fn new() -> Self {
62        Self::default()
63    }
64
65    pub fn add_hook<H: Hook + 'static>(&mut self, hook: H) {
66        self.hooks.push(Box::new(hook));
67    }
68
69    pub async fn on_agent_start(&self, query: &str) -> AgentResult<()> {
70        let event = HookEvent::agent_start(query);
71        self.dispatch(&event).await
72    }
73
74    pub async fn on_agent_end(&self, result: &str) -> AgentResult<()> {
75        let event = HookEvent::agent_end(result);
76        self.dispatch(&event).await
77    }
78
79    pub async fn on_agent_max_iteration(&self) -> AgentResult<()> {
80        let event = HookEvent::agent_max_iteration();
81        self.dispatch(&event).await
82    }
83
84    pub async fn on_step_start(&self, step: usize) -> AgentResult<()> {
85        let event = HookEvent::step_start(step);
86        self.dispatch(&event).await
87    }
88
89    pub async fn on_step_end(&self, step: usize, message: &AssistantMessage) -> AgentResult<()> {
90        let event = HookEvent::step_end(step, message);
91        self.dispatch(&event).await
92    }
93
94    pub async fn on_context_build(&self, query: &str, messages: &[ChatMessage]) -> AgentResult<()> {
95        let event = HookEvent::context_build(query, messages);
96        self.dispatch(&event).await
97    }
98
99    pub async fn on_memory_search(&self, query: &str, results: &[ChatMessage]) -> AgentResult<()> {
100        let event = HookEvent::memory_search(query, results);
101        self.dispatch(&event).await
102    }
103
104    pub async fn on_memory_add(&self, user: &str, assistant: &str) -> AgentResult<()> {
105        let event = HookEvent::memory_add(user, assistant);
106        self.dispatch(&event).await
107    }
108
109    pub async fn on_llm_start(&self, step: usize, messages: &[ChatMessage]) -> AgentResult<()> {
110        let event = HookEvent::llm_start(step, messages);
111        self.dispatch(&event).await
112    }
113
114    pub async fn on_llm_end(&self, step: usize, message: &AssistantMessage) -> AgentResult<()> {
115        let event = HookEvent::llm_end(step, message);
116        self.dispatch(&event).await
117    }
118
119    pub async fn on_tool_start(&self, step: usize, tool_call: &ToolCall) -> AgentResult<()> {
120        let event = HookEvent::tool_start(step, tool_call);
121        self.dispatch(&event).await
122    }
123
124    pub async fn on_tool_end(&self, step: usize, result: &ToolCallResult) -> AgentResult<()> {
125        let event = HookEvent::tool_end(step, result);
126        self.dispatch(&event).await
127    }
128
129    pub async fn on_tool_error(&self, step: usize, context: &str) -> AgentResult<()> {
130        let event = HookEvent::tool_error(step, context);
131        self.dispatch(&event).await
132    }
133
134    async fn dispatch(&self, event: &HookEvent<'_>) -> AgentResult<()> {
135        for hook in &self.hooks {
136            hook.on_event(event).await?;
137        }
138        Ok(())
139    }
140} 
141
142
143impl<'a> HookEvent<'a> {
144    pub fn agent_start(query: &'a str) -> Self {
145        Self::AgentStart { query }
146    }
147
148    pub fn agent_end(result: &'a str) -> Self {
149        Self::AgentEnd { result }
150    }
151
152    pub fn agent_max_iteration() -> Self {
153        Self::AgentMaxIteration
154    }
155
156    pub fn step_start(step: usize) -> Self {
157        Self::AgentStepStart { step }
158    }
159
160    pub fn step_end(step: usize, message: &'a AssistantMessage) -> Self {
161        Self::AgentStepEnd { step, message }
162    }
163
164    pub fn context_build(query: &'a str, messages: &'a [ChatMessage]) -> Self {
165        Self::ContextBuild { query, messages }
166    }
167
168    pub fn memory_search(query: &'a str, results: &'a [ChatMessage]) -> Self {
169        Self::MemorySearch { query, results }
170    }
171
172    pub fn memory_add(user: &'a str, assistant: &'a str) -> Self {
173        Self::MemoryAdd { user, assistant }
174    }
175
176    pub fn llm_start(step: usize, messages: &'a [ChatMessage]) -> Self {
177        Self::LlmStart { step, messages }
178    }
179
180    pub fn llm_end(step: usize, message: &'a AssistantMessage) -> Self {
181        Self::LlmEnd { step, message }
182    }
183
184    pub fn tool_start(step: usize, tool_call: &'a ToolCall) -> Self {
185        Self::ToolStart { step, tool_call }
186    }
187
188    pub fn tool_end(step: usize, result: &'a ToolCallResult) -> Self {
189        Self::ToolEnd { step, result }
190    }
191
192    pub fn tool_error(step: usize, context: &'a str) -> Self {
193        Self::ToolError { step, context }
194    }
195}
196
197#[async_trait::async_trait]
198pub trait HookWrap : Send + Sync {
199    async fn on_event(&self, event: &HookEvent<'_>) -> Result<(), AgentError>;
200} 
201
202#[async_trait::async_trait]
203impl<H: Hook> HookWrap for H {
204    #[inline]
205    async fn on_event(&self, event: &HookEvent<'_>) -> Result<(), AgentError> {
206        self
207            .on_event(event).await
208            .map_err(|e| AgentError::Hook(Box::new(e)))
209    }
210}