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#[derive(Serialize)]
24pub enum HookEvent<'a> {
25 AgentStart { query: &'a str, },
27 AgentEnd { result: &'a str, },
28 AgentMaxIteration,
29 AgentStepStart { step: usize, },
30 AgentStepEnd { step: usize, message: &'a AssistantMessage,},
31
32 ContextBuild { query: &'a str, messages: &'a [ChatMessage] },
34
35 MemorySearch { query: &'a str, results: &'a [ChatMessage] },
37 MemoryAdd { user: &'a str, assistant: &'a str },
38
39 LlmStart { step: usize, messages: &'a [ChatMessage] },
41 LlmEnd { step: usize, message: &'a AssistantMessage },
42
43 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}