pub struct HookDecision { /* private fields */ }Expand description
Decision returned by a hook handler to control agent execution flow.
When a hook returns Some(HookDecision), it takes control of the execution flow.
This struct determines whether execution should continue, whether inputs/prompts should
be modified, and provides a reason for logging and debugging.
§“First Non-None Wins” Model
The hooks system uses a sequential “first non-None wins” execution model:
- Hooks are executed in the order they were registered
- Each hook returns
Option<HookDecision>:None= “I don’t care, let the next hook decide”Some(decision)= “I’m taking control, stop checking other hooks”
- The first hook that returns
Some(decision)determines the outcome - Remaining hooks are skipped after a decision is made
- If all hooks return
None, execution continues normally
This model ensures:
- Predictable behavior (order matters)
- Performance (no unnecessary hook executions)
- Priority (earlier hooks can’t be overridden by later ones)
§Fields
continue_execution: Iffalse, abort the current operation (tool execution or prompt processing)modified_input: For PreToolUse hooks - replaces the tool input with this valuemodified_prompt: For UserPromptSubmit hooks - replaces the user prompt with this valuereason: Optional explanation for why this decision was made (useful for debugging/logging)
§Example: Hook Priority Order
use open_agent::{Hooks, PreToolUseEvent, HookDecision};
let hooks = Hooks::new()
// First hook - security gate (highest priority)
.add_pre_tool_use(|event| async move {
if event.tool_name == "dangerous_tool" {
// This blocks execution - later hooks won't run
return Some(HookDecision::block("Blocked by security"));
}
None // Pass to next hook
})
// Second hook - rate limiting
.add_pre_tool_use(|event| async move {
// This only runs if first hook returned None
if over_rate_limit(&event) {
return Some(HookDecision::block("Rate limit exceeded"));
}
None
})
// Third hook - logging
.add_pre_tool_use(|event| async move {
// This only runs if previous hooks returned None
println!("Tool {} called", event.tool_name);
None // Always pass through
});
fn over_rate_limit(_event: &PreToolUseEvent) -> bool { false }§Builder Methods
The struct provides convenient builder methods for common scenarios:
HookDecision::continue_()- Allow execution to proceed normallyHookDecision::block(reason)- Block execution with a reasonHookDecision::modify_input(input, reason)- Continue with modified tool inputHookDecision::modify_prompt(prompt, reason)- Continue with modified user prompt
Implementations§
Source§impl HookDecision
impl HookDecision
Sourcepub fn continue_() -> Self
pub fn continue_() -> Self
Creates a decision to continue execution normally without modifications.
This is typically used when a hook wants to explicitly signal “continue” rather
than returning None. In most cases, returning None is simpler and preferred.
§Example
use open_agent::{PreToolUseEvent, HookDecision};
async fn my_hook(event: PreToolUseEvent) -> Option<HookDecision> {
// Log the tool use
println!("Tool called: {}", event.tool_name);
// Explicitly continue (though returning None would be simpler)
Some(HookDecision::continue_())
}Note: Named continue_() with trailing underscore because continue is a Rust keyword.
Sourcepub fn block(reason: impl Into<String>) -> Self
pub fn block(reason: impl Into<String>) -> Self
Creates a decision to block execution with a reason.
When a hook returns this decision, the current operation (tool execution or prompt processing) is aborted, and the reason is logged.
§Parameters
reason: Human-readable explanation for why execution was blocked
§Example
use open_agent::{PreToolUseEvent, HookDecision};
async fn security_gate(event: PreToolUseEvent) -> Option<HookDecision> {
if event.tool_name == "Bash" {
if let Some(cmd) = event.tool_input.get("command") {
if cmd.as_str()?.contains("rm -rf /") {
return Some(HookDecision::block(
"Dangerous recursive delete blocked"
));
}
}
}
None
}Sourcepub fn modify_input(input: Value, reason: impl Into<String>) -> Self
pub fn modify_input(input: Value, reason: impl Into<String>) -> Self
Creates a decision to modify tool input before execution.
Use this in PreToolUse hooks to change the parameters that will be passed to the tool. The tool will execute with the modified input instead of the original.
§Parameters
input: The new tool input (as JSON Value) that replaces the originalreason: Explanation for why the input was modified
§Example
use open_agent::{PreToolUseEvent, HookDecision};
use serde_json::json;
async fn inject_security_token(event: PreToolUseEvent) -> Option<HookDecision> {
if event.tool_name == "WebFetch" {
// Add authentication to all web requests
let mut modified = event.tool_input.clone();
modified["headers"] = json!({
"Authorization": "Bearer secret-token",
"X-User-ID": "user-123"
});
return Some(HookDecision::modify_input(
modified,
"Injected authentication headers"
));
}
None
}Sourcepub fn modify_prompt(
prompt: impl Into<String>,
reason: impl Into<String>,
) -> Self
pub fn modify_prompt( prompt: impl Into<String>, reason: impl Into<String>, ) -> Self
Creates a decision to modify the user’s prompt before processing.
Use this in UserPromptSubmit hooks to enhance, sanitize, or transform user input. The agent will process the modified prompt instead of the original.
§Parameters
prompt: The new prompt text that replaces the user’s original inputreason: Explanation for why the prompt was modified
§Example
use open_agent::{UserPromptSubmitEvent, HookDecision};
async fn add_context(event: UserPromptSubmitEvent) -> Option<HookDecision> {
// Add system context to every user prompt
let enhanced = format!(
"{}\n\n[System Context: You are in production mode. Be extra careful with destructive operations.]",
event.prompt
);
Some(HookDecision::modify_prompt(
enhanced,
"Added production safety context"
))
}§Warning
Modifying prompts can be confusing for users if done excessively or without clear communication. Use this feature judiciously and consider logging modifications.
Sourcepub fn continue_execution(&self) -> bool
pub fn continue_execution(&self) -> bool
Returns whether execution should continue.
Sourcepub fn modified_input(&self) -> Option<&Value>
pub fn modified_input(&self) -> Option<&Value>
Returns the modified input, if any.
Sourcepub fn modified_prompt(&self) -> Option<&str>
pub fn modified_prompt(&self) -> Option<&str>
Returns the modified prompt, if any.
Trait Implementations§
Source§impl Clone for HookDecision
impl Clone for HookDecision
Source§fn clone(&self) -> HookDecision
fn clone(&self) -> HookDecision
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more