//! Pod-layer hook infrastructure //! //! Provides the `Hook` trait and `HookRegistry` for orchestration hooks //! that govern control-flow decisions in the Worker execution loop. //! //! The type system (`HookEventKind` / `Hook`) mirrors the pattern //! originally in llm-worker, now at the insomnia layer where orchestration //! concerns belong. use async_trait::async_trait; use llm_worker::Item; use llm_worker::interceptor::{ PostToolAction, PreRequestAction, PreToolAction, PromptAction, ToolCallInfo, ToolResultInfo, TurnEndAction, }; // ============================================================================= // Hook Event Kinds // ============================================================================= /// Marker trait for hook event kinds. /// /// Each event kind specifies its input (passed mutably to hooks) and /// output (the control-flow action returned by hooks). pub trait HookEventKind: Send + Sync + 'static { /// Mutable input passed to the hook. type Input; /// Control-flow action returned by the hook. type Output; } // --- Event kind markers --- /// After receiving user input, before adding to history. pub struct OnPromptSubmit; /// Before each LLM request. pub struct PreLlmRequest; /// Before each tool is executed. pub struct PreToolCall; /// After each tool completes. pub struct PostToolCall; /// When a turn ends with no tool calls. pub struct OnTurnEnd; /// When execution is interrupted. pub struct OnAbort; impl HookEventKind for OnPromptSubmit { type Input = Item; type Output = PromptAction; } impl HookEventKind for PreLlmRequest { type Input = Vec; type Output = PreRequestAction; } impl HookEventKind for PreToolCall { type Input = ToolCallInfo; type Output = PreToolAction; } impl HookEventKind for PostToolCall { type Input = ToolResultInfo; type Output = PostToolAction; } impl HookEventKind for OnTurnEnd { type Input = Vec; type Output = TurnEndAction; } impl HookEventKind for OnAbort { type Input = String; type Output = (); } // ============================================================================= // Hook Trait // ============================================================================= /// Async hook for a specific event kind. /// /// Hooks receive mutable access to the event's input and return a /// control-flow action. Multiple hooks can be registered per event; /// they are evaluated in registration order and short-circuit on the /// first non-Continue result. #[async_trait] pub trait Hook: Send + Sync { async fn call(&self, input: &mut E::Input) -> E::Output; } // ============================================================================= // Hook Registry // ============================================================================= /// Builder for constructing a frozen `HookRegistry`. /// /// Hooks are added during setup, then `build()` produces an immutable /// registry that can be shared via `Arc`. #[derive(Default)] pub struct HookRegistryBuilder { on_prompt_submit: Vec>>, pre_llm_request: Vec>>, pre_tool_call: Vec>>, post_tool_call: Vec>>, on_turn_end: Vec>>, on_abort: Vec>>, } impl HookRegistryBuilder { pub fn new() -> Self { Self::default() } pub fn add_on_prompt_submit(&mut self, hook: impl Hook + 'static) { self.on_prompt_submit.push(Box::new(hook)); } pub fn add_pre_llm_request(&mut self, hook: impl Hook + 'static) { self.pre_llm_request.push(Box::new(hook)); } pub fn add_pre_tool_call(&mut self, hook: impl Hook + 'static) { self.pre_tool_call.push(Box::new(hook)); } pub fn add_post_tool_call(&mut self, hook: impl Hook + 'static) { self.post_tool_call.push(Box::new(hook)); } pub fn add_on_turn_end(&mut self, hook: impl Hook + 'static) { self.on_turn_end.push(Box::new(hook)); } pub fn add_on_abort(&mut self, hook: impl Hook + 'static) { self.on_abort.push(Box::new(hook)); } /// Freeze the builder into an immutable registry. pub fn build(self) -> HookRegistry { HookRegistry { on_prompt_submit: self.on_prompt_submit, pre_llm_request: self.pre_llm_request, pre_tool_call: self.pre_tool_call, post_tool_call: self.post_tool_call, on_turn_end: self.on_turn_end, on_abort: self.on_abort, } } } /// Frozen registry of hooks. Constructed via [`HookRegistryBuilder::build()`]. pub struct HookRegistry { pub(crate) on_prompt_submit: Vec>>, pub(crate) pre_llm_request: Vec>>, pub(crate) pre_tool_call: Vec>>, pub(crate) post_tool_call: Vec>>, pub(crate) on_turn_end: Vec>>, pub(crate) on_abort: Vec>>, }