Skip to main content

crabtalk_runtime/
hook.rs

1//! Hook trait — lifecycle callbacks and tool dispatch for subsystems.
2//!
3//! Each tool/subsystem implements `Hook` to participate in the runtime
4//! lifecycle: provide schemas, inject context before runs, observe
5//! events, preprocess messages, and dispatch tool calls.
6
7use crabllm_core::Tool;
8use wcore::{AgentConfig, AgentEvent, ToolDispatch, ToolFuture, model::HistoryEntry};
9
10/// A pluggable subsystem that participates in the agent lifecycle.
11///
12/// All methods have default no-op implementations so subsystems only
13/// override what they need.
14pub trait Hook: Send + Sync {
15    /// Tool schemas this hook provides.
16    fn schema(&self) -> Vec<Tool> {
17        vec![]
18    }
19
20    /// System prompt fragment appended to agent configs at build time.
21    fn system_prompt(&self) -> Option<String> {
22        None
23    }
24
25    /// Called by `Runtime::add_agent()` before building the `Agent`.
26    fn on_build_agent(&self, config: AgentConfig) -> AgentConfig {
27        config
28    }
29
30    /// Inject context entries before each agent run.
31    fn on_before_run(
32        &self,
33        _agent: &str,
34        _conversation_id: u64,
35        _history: &[HistoryEntry],
36    ) -> Vec<HistoryEntry> {
37        Vec::new()
38    }
39
40    /// Called by Runtime after each agent step during execution.
41    fn on_event(&self, _agent: &str, _conversation_id: u64, _event: &AgentEvent) {}
42
43    /// Preprocess user content before it becomes a message.
44    /// Return `Some(modified)` to transform, `None` to pass through.
45    fn preprocess(&self, _agent: &str, _content: &str) -> Option<String> {
46        None
47    }
48
49    /// Tools to include when building a scoped agent's whitelist, plus an
50    /// optional scope prompt line (e.g. `"skills: foo, bar"`).
51    ///
52    /// Default: include all tools from `schema()` unconditionally, no
53    /// scope line. Override to gate inclusion on agent config fields.
54    fn scoped_tools(&self, _config: &AgentConfig) -> (Vec<String>, Option<String>) {
55        let tools = self
56            .schema()
57            .iter()
58            .map(|t| t.function.name.clone())
59            .collect();
60        (tools, None)
61    }
62
63    /// Dispatch a tool call by name. Return `None` if this hook doesn't
64    /// own the tool — Env will try the next hook or the legacy entries.
65    fn dispatch<'a>(&'a self, _name: &'a str, _call: ToolDispatch) -> Option<ToolFuture<'a>> {
66        None
67    }
68}
69
70/// No-op Hook for tests.
71impl Hook for () {}