pub trait AgentHooks: Send + Sync {
// Provided methods
fn pre_tool_use<'life0, 'life1, 'async_trait>(
&'life0 self,
invocation: &'life1 ToolInvocation,
) -> Pin<Box<dyn Future<Output = ToolDecision> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait { ... }
fn post_tool_use<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_tool_name: &'life1 str,
_result: &'life2 ToolResult,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait { ... }
fn on_event<'life0, 'life1, 'async_trait>(
&'life0 self,
_event: &'life1 AgentEvent,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait { ... }
fn on_error<'life0, 'life1, 'async_trait>(
&'life0 self,
_error: &'life1 Error,
) -> Pin<Box<dyn Future<Output = bool> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait { ... }
fn on_context_compact<'life0, 'life1, 'async_trait>(
&'life0 self,
_messages: &'life1 [Message],
) -> Pin<Box<dyn Future<Output = Option<String>> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait { ... }
fn pre_llm_request<'life0, 'life1, 'async_trait>(
&'life0 self,
_request: &'life1 ChatRequest,
) -> Pin<Box<dyn Future<Output = RequestDecision> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait { ... }
fn on_llm_response<'life0, 'life1, 'async_trait>(
&'life0 self,
_response: &'life1 ChatResponse,
) -> Pin<Box<dyn Future<Output = ResponseDecision> + Send + 'async_trait>>
where 'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait { ... }
}Expand description
Lifecycle hooks for the agent loop. Implement this trait to customize agent behavior.
Provided Methods§
Sourcefn pre_tool_use<'life0, 'life1, 'async_trait>(
&'life0 self,
invocation: &'life1 ToolInvocation,
) -> Pin<Box<dyn Future<Output = ToolDecision> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn pre_tool_use<'life0, 'life1, 'async_trait>(
&'life0 self,
invocation: &'life1 ToolInvocation,
) -> Pin<Box<dyn Future<Output = ToolDecision> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Called before a tool is executed.
Receives a structured ToolInvocation that bundles tool identity,
tier, requested input, effective input, and listen-context — everything
a server-side policy engine needs for an allow / block / confirm decision.
Return ToolDecision::Allow to proceed, ToolDecision::Block to
reject, or ToolDecision::RequiresConfirmation to yield for user
approval.
Sourcefn post_tool_use<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_tool_name: &'life1 str,
_result: &'life2 ToolResult,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
fn post_tool_use<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_tool_name: &'life1 str,
_result: &'life2 ToolResult,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Self: 'async_trait,
Called after a tool completes execution.
Sourcefn on_event<'life0, 'life1, 'async_trait>(
&'life0 self,
_event: &'life1 AgentEvent,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn on_event<'life0, 'life1, 'async_trait>(
&'life0 self,
_event: &'life1 AgentEvent,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Called when the agent emits an event. Can be used for logging, metrics, or custom handling.
Sourcefn on_error<'life0, 'life1, 'async_trait>(
&'life0 self,
_error: &'life1 Error,
) -> Pin<Box<dyn Future<Output = bool> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn on_error<'life0, 'life1, 'async_trait>(
&'life0 self,
_error: &'life1 Error,
) -> Pin<Box<dyn Future<Output = bool> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Called when an error occurs. Return true to attempt recovery, false to abort.
Sourcefn on_context_compact<'life0, 'life1, 'async_trait>(
&'life0 self,
_messages: &'life1 [Message],
) -> Pin<Box<dyn Future<Output = Option<String>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn on_context_compact<'life0, 'life1, 'async_trait>(
&'life0 self,
_messages: &'life1 [Message],
) -> Pin<Box<dyn Future<Output = Option<String>> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Called when context is about to be compacted due to length. Return a summary to use, or None to use default summarization.
Sourcefn pre_llm_request<'life0, 'life1, 'async_trait>(
&'life0 self,
_request: &'life1 ChatRequest,
) -> Pin<Box<dyn Future<Output = RequestDecision> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn pre_llm_request<'life0, 'life1, 'async_trait>(
&'life0 self,
_request: &'life1 ChatRequest,
) -> Pin<Box<dyn Future<Output = RequestDecision> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Input guardrail: called with the outbound llm::ChatRequest before it
is sent to the provider.
Return RequestDecision::Proceed to send it unchanged,
RequestDecision::Modify to substitute a sanitized request, or
RequestDecision::Block to refuse the call (e.g. prompt-injection or
PII policy). The default proceeds unchanged.
Fresh-input timing: for a run’s first call on fresh Text /
Message input the hook runs at ingestion time, against the
request built from existing history plus the candidate message —
BEFORE the message is durably appended, so a Block leaves nothing
in history. The request actually sent may then differ only by
SDK-added content: context compaction (a summary of the exact
content the hook already saw — Block decisions err conservative)
or a turn-budget reminder. A Modify on that first call is sent
as-is (bypassing compaction once; an oversized replacement degrades
to the normal overflow recovery). The hook fires exactly once per
LLM call in every mode.
Sourcefn on_llm_response<'life0, 'life1, 'async_trait>(
&'life0 self,
_response: &'life1 ChatResponse,
) -> Pin<Box<dyn Future<Output = ResponseDecision> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
fn on_llm_response<'life0, 'life1, 'async_trait>(
&'life0 self,
_response: &'life1 ChatResponse,
) -> Pin<Box<dyn Future<Output = ResponseDecision> + Send + 'async_trait>>where
'life0: 'async_trait,
'life1: 'async_trait,
Self: 'async_trait,
Output guardrail: called with the provider’s llm::ChatResponse before
it is persisted or surfaced.
Return ResponseDecision::Accept to keep it,
ResponseDecision::Block to reject it, or
ResponseDecision::RetryWithFeedback to reject it and steer a retry
(e.g. output moderation or secret-leakage detection). The default
accepts.
Retry cap: every RetryWithFeedback pays for another LLM
round-trip, so the loop bounds consecutive rejections at 8. When
the cap is reached the run terminates with an error naming this hook
instead of retrying (and billing) indefinitely. The rejection streak
is persisted in the thread’s AgentState, so the cap binds both
in-process looping runs and host-driven single-turn orchestration
(repeated run_turn calls rehydrate the streak from the state
store). The counter resets whenever a response is accepted.
Streaming caveat: the hook runs on the complete response, after
the model has finished. In streaming mode the text deltas have already
been emitted (and recorded) as stream events by then, so a Block /
RetryWithFeedback decision keeps the response out of the thread’s
message history and out of the model’s context, but a live consumer
may have rendered the deltas. Disable streaming when blocked content
must never be surfaced.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".