Skip to main content

lc_agents/hooks/
logging.rs

1// lc-agents/src/hooks/logging.rs
2//! LoggingHook — logs all hook points for debugging.
3//!
4//! Prints a log message at each hook point, useful for debugging
5//! agent execution flow.
6
7use async_trait::async_trait;
8
9use super::{
10    AgentHook, CompletionAction, CompletionContext, CompletionResult, ErrorAction, HookError,
11    StreamAction, ToolCallAction, ToolCallContext, ToolResultContext,
12};
13
14/// A hook that logs all lifecycle events for debugging.
15///
16/// # Example
17///
18/// ```rust,ignore
19/// use lc_agents::hooks::LoggingHook;
20///
21/// let hook = LoggingHook::new();
22/// let executor = AgentExecutor::new(agent, tools).hook(hook);
23/// ```
24pub struct LoggingHook {
25    /// Whether to log stream tokens (can be very verbose).
26    log_tokens: bool,
27}
28
29impl LoggingHook {
30    /// Creates a new LoggingHook.
31    pub fn new() -> Self {
32        Self { log_tokens: false }
33    }
34
35    /// Creates a LoggingHook that also logs stream tokens.
36    pub fn with_tokens() -> Self {
37        Self { log_tokens: true }
38    }
39
40    /// Sets whether to log stream tokens.
41    pub fn with_log_tokens(mut self, log: bool) -> Self {
42        self.log_tokens = log;
43        self
44    }
45}
46
47impl Default for LoggingHook {
48    fn default() -> Self {
49        Self::new()
50    }
51}
52
53#[async_trait]
54impl AgentHook for LoggingHook {
55    fn on_before_completion(&self, ctx: &mut CompletionContext) -> CompletionAction {
56        log::info!(
57            "[Hook] LLM call starting: model={}, messages={}",
58            ctx.model,
59            ctx.messages.len()
60        );
61        CompletionAction::Continue
62    }
63
64    fn on_after_completion(&self, ctx: &mut CompletionResult) -> Result<(), HookError> {
65        log::info!(
66            "[Hook] LLM call completed: content_len={}",
67            ctx.message.content.len()
68        );
69        Ok(())
70    }
71
72    fn on_before_tool_call(&self, ctx: &mut ToolCallContext) -> ToolCallAction {
73        log::info!("[Hook] Tool call starting: name={}", ctx.name);
74        ToolCallAction::Continue
75    }
76
77    fn on_after_tool_call(&self, ctx: &mut ToolResultContext) -> Result<(), HookError> {
78        log::info!(
79            "[Hook] Tool call completed: name={}, result_len={}",
80            ctx.name,
81            ctx.result.len()
82        );
83        Ok(())
84    }
85
86    fn on_stream_chunk(&self, chunk: &str) -> StreamAction {
87        if self.log_tokens {
88            log::debug!("[Hook] Stream token: {:?}", chunk);
89        }
90        StreamAction::Forward(chunk.to_string())
91    }
92
93    fn on_agent_start(&self, input: &str) -> Result<(), HookError> {
94        log::info!("[Hook] Agent starting: input_len={}", input.len());
95        Ok(())
96    }
97
98    fn on_agent_end(&self, output: &str) -> Result<(), HookError> {
99        log::info!("[Hook] Agent completed: output_len={}", output.len());
100        Ok(())
101    }
102
103    fn on_error(&self, error: &HookError) -> ErrorAction {
104        log::warn!("[Hook] Error: {}", error);
105        ErrorAction::Propagate
106    }
107}