Skip to main content

walrus_daemon/
hook.rs

1//! Stateful Hook implementation for the daemon.
2//!
3//! [`DaemonHook`] composes memory, skill, MCP, and cron sub-hooks.
4//! `on_build_agent` delegates to skills and memory; `on_register_tools`
5//! delegates to memory, cron, and MCP sub-hooks in sequence.
6
7use mcp::McpHandler;
8use memory::InMemory;
9use skill::SkillHandler;
10use std::future::Future;
11use wcore::{AgentConfig, AgentEvent, Hook, ToolRegistry};
12use wcron::CronHandler;
13
14/// Stateful Hook implementation for the daemon.
15///
16/// Composes memory, skill, MCP, and cron sub-hooks. Each sub-hook
17/// self-registers its tools via `on_register_tools`.
18pub struct DaemonHook {
19    pub memory: InMemory,
20    pub skills: SkillHandler,
21    pub mcp: McpHandler,
22    pub cron: CronHandler,
23}
24
25impl DaemonHook {
26    /// Create a new DaemonHook with the given backends.
27    pub fn new(memory: InMemory, skills: SkillHandler, mcp: McpHandler, cron: CronHandler) -> Self {
28        Self {
29            memory,
30            skills,
31            mcp,
32            cron,
33        }
34    }
35}
36
37impl Hook for DaemonHook {
38    fn on_build_agent(&self, config: AgentConfig) -> AgentConfig {
39        let config = self.skills.on_build_agent(config);
40        self.memory.on_build_agent(config)
41    }
42
43    fn on_event(&self, agent: &str, event: &AgentEvent) {
44        match event {
45            AgentEvent::TextDelta(text) => {
46                tracing::trace!(%agent, text_len = text.len(), "agent text delta");
47            }
48            AgentEvent::ToolCallsStart(calls) => {
49                tracing::debug!(%agent, count = calls.len(), "agent tool calls started");
50            }
51            AgentEvent::ToolResult { call_id, .. } => {
52                tracing::debug!(%agent, %call_id, "agent tool result");
53            }
54            AgentEvent::ToolCallsComplete => {
55                tracing::debug!(%agent, "agent tool calls complete");
56            }
57            AgentEvent::Done(response) => {
58                tracing::info!(
59                    %agent,
60                    iterations = response.iterations,
61                    stop_reason = ?response.stop_reason,
62                    "agent run complete"
63                );
64            }
65        }
66    }
67
68    fn on_register_tools(&self, tools: &mut ToolRegistry) -> impl Future<Output = ()> + Send {
69        // Memory and cron: inserts happen synchronously inside on_register_tools;
70        // the returned trivial async{} futures are intentionally dropped.
71        drop(self.memory.on_register_tools(tools));
72        drop(self.cron.on_register_tools(tools));
73        // MCP: captures bridge Arc synchronously, registers tools async.
74        self.mcp.on_register_tools(tools)
75    }
76}