Skip to content

Lifecycle hooks

Agents can have functions trigger at various stages of its run. You can provide a closure, or any function that implements the trait.

This is great for providing initial context, handling tool errors, modifying the output of multiple tools with a single function, and so on.

Hooks are initialized during when building an agent and can be added multiple times. The following hooks are available:

  • before_all: Runs only once when the agent starts for the first time
  • before_completion: Runs before each completion, yielding the ChatCompletionRequest as mutable
  • after_completion: Runs right after each completion, before any tool calls, and yields the full completion response mutable
  • after_each: Runs after each completion cycle
  • after_tool: Runs after each tool, yielding the tool call result as mutable
  • before_tool: Runs before each tool call, yields the ToolCall, not mutable
  • on_new_message: Runs right before a new message is added to the context, yielding the ChatMessage as mutable
  • on_start: Runs when the agent starts for the first time
  • on_stop: Runs when the agent stops; from a tool, no new messages, error, or other reasons
  • on_stream: Runs when an agent message is streamed

Each hook accepts an implementation of a trait named like the hook, suffixed with Fn, i.e. AfterCompletionFn.

Unlike tools, hooks are not called in parallel, but in the order they were added (FIFO).

The hooks are expected to be async. Because Rust does not have async closures yet (soon!), we need to be a bit verbose in the syntax, for example:

agent.before_all(move |agent: &Agent| {
println!("Calling the before all hook!");
Box::pin(async move {
agent.context().add_message(ChatMessage::new_user("Just want to say I think you are very special")).await?;
Ok(())
})
})