Trait HookHandler
pub trait HookHandler: Send + Sync {
Show 21 methods
// Required method
fn name(&self) -> &str;
// Provided methods
fn priority(&self) -> i32 { ... }
fn on_gateway_start<'life0, 'life1, 'async_trait>(
&'life0 self,
_host: &'life1 str,
_port: u16,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn on_gateway_stop<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
fn on_session_start<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_session_id: &'life1 str,
_channel: &'life2 str,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait { ... }
fn on_session_end<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_session_id: &'life1 str,
_channel: &'life2 str,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait { ... }
fn on_llm_input<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_messages: &'life1 [ChatMessage],
_model: &'life2 str,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait { ... }
fn on_llm_output<'life0, 'life1, 'async_trait>(
&'life0 self,
_response: &'life1 ChatResponse,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn on_after_tool_call<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_tool: &'life1 str,
_result: &'life2 ToolResult,
_duration: Duration,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait { ... }
fn on_after_tool_call_with_context<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
_context: &'life1 ToolCallHookContext,
tool: &'life2 str,
result: &'life3 ToolResult,
duration: Duration,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait { ... }
fn on_after_tool_call_with_context_and_args<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
context: &'life1 ToolCallHookContext,
tool: &'life2 str,
_args: &'life3 Value,
result: &'life4 ToolResult,
duration: Duration,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait { ... }
fn on_tool_call_abandoned<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_context: &'life1 ToolCallHookContext,
_tool: &'life2 str,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait { ... }
fn on_message_sent<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
_channel: &'life1 str,
_recipient: &'life2 str,
_content: &'life3 str,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait { ... }
fn on_heartbeat_tick<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
fn before_model_resolve<'life0, 'async_trait>(
&'life0 self,
model_provider: String,
model: String,
) -> Pin<Box<dyn Future<Output = HookResult<(String, String)>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
fn before_prompt_build<'life0, 'async_trait>(
&'life0 self,
prompt: String,
) -> Pin<Box<dyn Future<Output = HookResult<String>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
fn before_llm_call<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_messages: &'life1 mut Vec<ChatMessage>,
_model: &'life2 mut String,
) -> Pin<Box<dyn Future<Output = HookResult<()>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait { ... }
fn before_tool_call<'life0, 'async_trait>(
&'life0 self,
name: String,
args: Value,
) -> Pin<Box<dyn Future<Output = HookResult<(String, Value)>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
fn before_tool_call_with_context<'life0, 'life1, 'async_trait>(
&'life0 self,
_context: &'life1 ToolCallHookContext,
name: String,
args: Value,
) -> Pin<Box<dyn Future<Output = HookResult<(String, Value)>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn on_message_received<'life0, 'async_trait>(
&'life0 self,
message: ChannelMessage,
) -> Pin<Box<dyn Future<Output = HookResult<ChannelMessage>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
fn on_message_sending<'life0, 'async_trait>(
&'life0 self,
channel: String,
recipient: String,
content: String,
) -> Pin<Box<dyn Future<Output = HookResult<(String, String, String)>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait { ... }
}Expand description
Trait for hook handlers. All methods have default no-op implementations. Implement only the events you care about.
Required Methods§
Provided Methods§
fn priority(&self) -> i32
fn on_gateway_start<'life0, 'life1, 'async_trait>(
&'life0 self,
_host: &'life1 str,
_port: u16,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn on_gateway_stop<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn on_session_start<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_session_id: &'life1 str,
_channel: &'life2 str,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn on_session_end<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_session_id: &'life1 str,
_channel: &'life2 str,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn on_llm_input<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_messages: &'life1 [ChatMessage],
_model: &'life2 str,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn on_llm_output<'life0, 'life1, 'async_trait>(
&'life0 self,
_response: &'life1 ChatResponse,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn on_after_tool_call<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_tool: &'life1 str,
_result: &'life2 ToolResult,
_duration: Duration,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Sourcefn on_after_tool_call_with_context<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
_context: &'life1 ToolCallHookContext,
tool: &'life2 str,
result: &'life3 ToolResult,
duration: Duration,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn on_after_tool_call_with_context<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
_context: &'life1 ToolCallHookContext,
tool: &'life2 str,
result: &'life3 ToolResult,
duration: Duration,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Observe tool completion with explicit correlation context.
When context.is_correlated() is false, handlers must not use its
phase-local identity to pair callbacks or retain attributed state.
Sourcefn on_after_tool_call_with_context_and_args<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
context: &'life1 ToolCallHookContext,
tool: &'life2 str,
_args: &'life3 Value,
result: &'life4 ToolResult,
duration: Duration,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
fn on_after_tool_call_with_context_and_args<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
context: &'life1 ToolCallHookContext,
tool: &'life2 str,
_args: &'life3 Value,
result: &'life4 ToolResult,
duration: Duration,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
Observe tool completion with explicit correlation context and the arguments that were actually dispatched.
Runners that know the final prepared arguments dispatch this variant
instead of HookHandler::on_after_tool_call_with_context; the
default delegates there, dropping the arguments. Handlers that audit
arguments should override this variant so their export reflects what
was dispatched — and so they never need to retain arguments between
the before and after phases.
Sourcefn on_tool_call_abandoned<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_context: &'life1 ToolCallHookContext,
_tool: &'life2 str,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn on_tool_call_abandoned<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_context: &'life1 ToolCallHookContext,
_tool: &'life2 str,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Observe that a tool-call context will never reach its after phase.
Fired exactly once per correlated context whose before phase ran, when the call cannot complete: the before hook chain cancelled it, approval denied or replaced it, duplicate suppression skipped it, or execution failed or was interrupted before post-execution handling. Abandonment is NOT execution completion — handlers must never synthesize a tool result from it.
Best-effort by nature: the runner dispatches abandonment on every awaited non-completion path, but a turn future dropped outright (an outer timeout, outer cancellation, or hard task abort) cannot run any async callback, abandonment included. Handlers must therefore avoid retaining safety-critical state between the before and after phases in the first place, and treat abandonment as a best-effort release signal rather than a guarantee.
fn on_message_sent<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
_channel: &'life1 str,
_recipient: &'life2 str,
_content: &'life3 str,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn on_heartbeat_tick<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn before_model_resolve<'life0, 'async_trait>(
&'life0 self,
model_provider: String,
model: String,
) -> Pin<Box<dyn Future<Output = HookResult<(String, String)>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn before_prompt_build<'life0, 'async_trait>(
&'life0 self,
prompt: String,
) -> Pin<Box<dyn Future<Output = HookResult<String>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn before_llm_call<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
_messages: &'life1 mut Vec<ChatMessage>,
_model: &'life2 mut String,
) -> Pin<Box<dyn Future<Output = HookResult<()>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn before_tool_call<'life0, 'async_trait>(
&'life0 self,
name: String,
args: Value,
) -> Pin<Box<dyn Future<Output = HookResult<(String, Value)>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Sourcefn before_tool_call_with_context<'life0, 'life1, 'async_trait>(
&'life0 self,
_context: &'life1 ToolCallHookContext,
name: String,
args: Value,
) -> Pin<Box<dyn Future<Output = HookResult<(String, Value)>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn before_tool_call_with_context<'life0, 'life1, 'async_trait>(
&'life0 self,
_context: &'life1 ToolCallHookContext,
name: String,
args: Value,
) -> Pin<Box<dyn Future<Output = HookResult<(String, Value)>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Inspect or modify a tool call with explicit correlation context.
When context.is_correlated() is false, handlers must not retain state
that assumes the after phase will receive the same identity.
fn on_message_received<'life0, 'async_trait>(
&'life0 self,
message: ChannelMessage,
) -> Pin<Box<dyn Future<Output = HookResult<ChannelMessage>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn on_message_sending<'life0, 'async_trait>(
&'life0 self,
channel: String,
recipient: String,
content: String,
) -> Pin<Box<dyn Future<Output = HookResult<(String, String, String)>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".