Skip to main content

AgentHook

Trait AgentHook 

Source
pub trait AgentHook<M>: WasmCompatSend + WasmCompatSync
where M: CompletionModel,
{ // Provided methods fn on_event( &self, ctx: &HookContext, event: StepEvent<'_, M>, ) -> impl Future<Output = Flow> + WasmCompatSend { ... } fn observes(&self, kind: StepEventKind) -> bool { ... } }
Expand description

A per-run hook that observes and steers an agent run.

Implement on_event and match on the StepEvent variants you care about; every other event falls through to the default Flow::Continue. Hooks must be cheap to share (Clone is not required — hooks are held behind an Arc once registered).

§Example

use rig_core::agent::{AgentHook, Flow, HookContext, StepEvent};
use rig_core::completion::CompletionModel;

#[derive(Clone)]
struct Logger;

impl<M: CompletionModel> AgentHook<M> for Logger {
    async fn on_event(&self, ctx: &HookContext, event: StepEvent<'_, M>) -> Flow {
        if let StepEvent::ToolCall { tool_name, args, .. } = event {
            println!("[run {}] calling {tool_name}({args})", ctx.run_id());
        }
        Flow::cont()
    }
}

Provided Methods§

Source

fn on_event( &self, ctx: &HookContext, event: StepEvent<'_, M>, ) -> impl Future<Output = Flow> + WasmCompatSend

Called at every observable point of the agent run (subject to observes). Receives the run-scoped HookContext and the StepEvent. The default implementation is a no-op: it ignores every event and returns Flow::Continue. It does not narrow observes (which defaults to true), so a hook that takes this default is still dispatched every event — override observes to skip the high-frequency delta events. (The () no-op hook overrides observes to false, so the runner skips dispatching those delta events to it; it still receives, and returns Flow::Continue for, every other event.)

Source

fn observes(&self, kind: StepEventKind) -> bool

Whether this hook observes events of the given StepEventKind.

This is a performance hint for the high-frequency streaming TextDelta / ToolCallDelta events, which otherwise cost one boxed future per delta. The runner skips building and dispatching a delta event only when no hook in the stack observes it (interest is OR-combined across the stack), so a hook may still be invoked for a delta a sibling observes — on_event must therefore stay total (return Flow::Continue for events it ignores) rather than assume it is only called for observed kinds.

Control flow is never changed by observes: the shared, steering events (ToolCall, InvalidToolCall, …) fire identically regardless of this method, so run() and stream() stay in lock-step. The default observes everything.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementations on Foreign Types§

Source§

impl<M> AgentHook<M> for ()
where M: CompletionModel,

The no-op hook: observes nothing, never alters control flow.

Source§

fn observes(&self, _kind: StepEventKind) -> bool

Observe nothing, so the runner skips building/dispatching the high-frequency streaming delta events (TextDelta / ToolCallDelta, the only events gated on observes) for a () hook.

Implementors§

Source§

impl<M> AgentHook<M> for HookStack<M>
where M: CompletionModel,