Skip to main content

walrus_core/runtime/
hook.rs

1//! Hook trait — lifecycle backend for agent building, event observation,
2//! and tool schema registration.
3//!
4//! All hook crates implement this trait. [`Runtime`](crate) calls these
5//! methods at the appropriate lifecycle points. `DaemonHook` composes
6//! multiple Hook implementations by delegating to each.
7
8use crate::{AgentConfig, AgentEvent, agent::tool::ToolRegistry, model::Message};
9use std::future::Future;
10
11/// Lifecycle backend for agent building, event observation, and tool registration.
12///
13/// Default implementations are no-ops so implementors only override what they need.
14pub trait Hook: Send + Sync {
15    /// Called by `Runtime::add_agent()` before building the `Agent`.
16    ///
17    /// Enriches the agent config: appends skill instructions, injects memory
18    /// into the system prompt, etc. The returned config is passed to `AgentBuilder`.
19    ///
20    /// Default: returns config unchanged.
21    fn on_build_agent(&self, config: AgentConfig) -> AgentConfig {
22        config
23    }
24
25    /// Called by Runtime after each agent step during execution.
26    ///
27    /// Receives every `AgentEvent` produced during `send_to` and `stream_to`.
28    /// Use for logging, metrics, persistence, or forwarding.
29    ///
30    /// Default: no-op.
31    fn on_event(&self, _agent: &str, _event: &AgentEvent) {}
32
33    /// Called by `Runtime::new()` to register tool schemas into the registry.
34    ///
35    /// Implementations call `tools.insert(tool)` with schema-only `Tool` values.
36    /// No handlers or closures are stored — dispatch is handled by the daemon.
37    ///
38    /// Default: no-op async.
39    fn on_register_tools(&self, _tools: &mut ToolRegistry) -> impl Future<Output = ()> + Send {
40        async {}
41    }
42
43    /// Called during context compaction to enrich the compaction prompt.
44    ///
45    /// Hooks append memory context (profile facts, recent entries) to the
46    /// prompt before the LLM summarizes the conversation. The runtime passes
47    /// the base prompt from `compact.md`; hooks mutate it in place.
48    ///
49    /// Default: no-op.
50    fn on_compact(&self, _agent: &str, _prompt: &mut String) {}
51
52    /// Called by Runtime before each agent run (send_to / stream_to).
53    ///
54    /// Receives the agent name and conversation history (including the
55    /// latest user message). Returns messages to inject before the user
56    /// message for additional context (e.g. auto-recalled memory).
57    ///
58    /// Default: no injection.
59    fn on_before_run(&self, _agent: &str, _history: &[Message]) -> Vec<Message> {
60        Vec::new()
61    }
62
63    /// Called by Runtime after agent execution completes (send_to / stream_to).
64    ///
65    /// Receives the agent name, final conversation history, and system prompt.
66    /// Synchronous — implementations that need async work should spawn
67    /// their own background tasks internally.
68    ///
69    /// Default: no-op.
70    fn on_after_run(&self, _agent: &str, _history: &[Message], _system_prompt: &str) {}
71}
72
73impl Hook for () {}