Hooks

Lifecycle hooks for intercepting agent behavior in PraisonAI Rust SDK

Hooks intercept and modify agent behavior at various lifecycle points – before/after tools, agents, and LLM calls.

Diagram

Hook Lifecycle

🚀 Init

🤖 BeforeAgent

💭 BeforeLLM

🔧 BeforeTool

✅ AfterTool

📝 AfterLLM

✨ AfterAgent

Quick Start

  1. Create a Hook with HookRegistry
    rust
    use praisonai::{HookRegistry, HookEvent, HookInput, HookResult};
    
    let mut registry = HookRegistry::new();
    
    // Add a logging hook
    registry.add_hook(HookEvent::BeforeTool, |input: &HookInput| {
        println!("[{}] Event: {:?}", input.session_id, input.event);
        HookResult::allow()
    });
  2. Block Tool Execution
    rust
    use praisonai::{HookRegistry, HookEvent, HookInput, HookResult};
    
    let mut registry = HookRegistry::new();
    
    // Block dangerous tools
    registry.add_hook(HookEvent::BeforeTool, |input: &HookInput| {
        if let Some(tool) = &input.tool_name {
            if tool == "delete_file" {
                return HookResult::deny("Dangerous tool blocked");
            }
        }
        HookResult::allow()
    });
  3. Hook with Matcher
    rust
    use praisonai::{HookRegistry, HookEvent, HookInput, HookResult};
    
    let mut registry = HookRegistry::new();
    
    // Only match file-related tools
    registry.add_hook_with_matcher(
        HookEvent::BeforeTool,
        "file_*",  // Glob pattern
        |input: &HookInput| {
            println!("File operation: {:?}", input.tool_name);
            HookResult::allow()
        }
    );

User Interaction Flow

Diagram
ToolHookHookRunnerAgentUserToolHookHookRunnerAgentUseralt[Hook allows][Hook denies]“Execute task”run(BeforeAgent)run(input)HookResult::allow()run(BeforeTool)run(input)HookResult::allow()Proceedexecute()HookResult::deny(reason)Skip tool

HookEvent

Events that hooks can subscribe to.

rust
pub enum HookEvent {
    BeforeTool,
    AfterTool,
    BeforeAgent,
    AfterAgent,
    BeforeLLM,
    AfterLLM,
    SessionStart,
    SessionEnd,
    OnError,
    OnRetry,
    OnInit,
    OnShutdown,
}
EventDescription
BeforeToolBefore tool execution
AfterToolAfter tool execution
BeforeAgentBefore agent processes message
AfterAgentAfter agent processes message
BeforeLLMBefore LLM call
AfterLLMAfter LLM call
SessionStartNew session begins
SessionEndSession ends
OnErrorError occurred
OnRetryRetry triggered
OnInitInitialization
OnShutdownShutdown

HookInput

Data provided to hooks.

rust
pub struct HookInput {
    pub event: HookEvent,
    pub session_id: String,
    pub agent_name: Option<String>,
    pub tool_name: Option<String>,
    pub tool_args: Option<Value>,
    pub message: Option<String>,
    pub error: Option<String>,
    pub extra: HashMap<String, Value>,
}

Builder Methods

MethodSignatureDescription
new(event, session_id)`fn new(HookEvent, impl Into

) -> Self | Create input | | with_agent(name) | fn with_agent(self, impl Into

) -> Self | Set agent name | | with_tool(name, args) | fn with_tool(self, impl Into

, Value) -> Self | Set tool info | | with_message(msg) | fn with_message(self, impl Into

) -> Self | Set message | | with_error(err) | fn with_error(self, impl Into

) -> Self | Set error | | with_extra(key, value) | fn with_extra(self, impl Into

, Value) -> Self` | Add extra data |


HookResult

Result returned from hook execution.

rust
pub struct HookResult {
    pub decision: HookDecision,
    pub reason: Option<String>,
    pub modified_input: Option<HashMap<String, Value>>,
    pub additional_context: Option<String>,
    pub suppress_output: bool,
}

Factory Methods

MethodSignatureDescription
allow()fn allow() -> SelfAllow execution
allow_with_reason(r)`fn allow_with_reason(impl Into

) -> Self | Allow with reason | | deny(reason) | fn deny(impl Into

) -> Self | Deny execution | | block(reason) | fn block(impl Into

) -> Self | Block (stronger deny) | | ask(reason) | fn ask(impl Into

) -> Self` | Ask for confirmation |

Instance Methods

MethodSignatureDescription
is_allowed()fn is_allowed(&self) -> boolCheck if allowed
is_denied()fn is_denied(&self) -> boolCheck if denied
with_modified_input(input)fn with_modified_input(self, HashMap) -> SelfModify inputs
with_context(ctx)`fn with_context(self, impl Into

) -> Self | Add context | | suppress() | fn suppress(self) -> Self` | Suppress output |


HookDecision

Decision types for hook outputs.

rust
pub enum HookDecision {
    Allow,   // default - Allow operation
    Deny,    // Deny operation
    Block,   // Block (stronger than deny)
    Ask,     // Ask for user confirmation
}

HookDefinition

Define individual hooks with functions and metadata.

rust
pub struct HookDefinition {
    pub id: String,
    pub event: HookEvent,
    pub matcher: Option<String>,
    pub func: HookFn,
    pub enabled: bool,
    pub name: Option<String>,
}

Methods

MethodSignatureDescription
new(event, func)fn new(HookEvent, impl Fn(&HookInput) -> HookResult) -> SelfCreate definition
with_matcher(pattern)`fn with_matcher(self, impl Into

) -> Self | Set matcher pattern | | with_name(name) | fn with_name(self, impl Into

) -> Self | Set name | | matches(target) | fn matches(&self, &str) -> bool | Check if matches target | | execute(input) | fn execute(&self, &HookInput) -> HookResult` | Execute hook |


HookRegistry

Manages a collection of hooks.

rust
pub struct HookRegistry {
    hooks: HashMap<HookEvent, Vec<HookDefinition>>,
}

Methods

MethodSignatureDescription
new()fn new() -> SelfCreate empty registry
add_hook(event, func)fn add_hook(&mut self, HookEvent, impl Fn) -> &mut SelfAdd a hook
add_hook_with_matcher(event, matcher, func)`fn add_hook_with_matcher(&mut self, HookEvent, impl Into

, impl Fn) -> &mut Self | Add hook with matcher | | add_definition(hook) | fn add_definition(&mut self, HookDefinition) -> &mut Self | Add hook definition | | remove_hook(id) | fn remove_hook(&mut self, &str) -> bool | Remove hook by ID | | enable_hook(id) | fn enable_hook(&mut self, &str) -> bool | Enable hook | | disable_hook(id) | fn disable_hook(&mut self, &str) -> bool` | Disable hook |


Common Patterns

Rate Limiter Hook

rust
use praisonai::{HookRegistry, HookEvent, HookInput, HookResult};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

let counter = Arc::new(AtomicUsize::new(0));
let max_calls = 100;

let mut registry = HookRegistry::new();

let counter_clone = counter.clone();
registry.add_hook(HookEvent::BeforeTool, move |_input: &HookInput| {
    let count = counter_clone.fetch_add(1, Ordering::SeqCst);
    if count >= max_calls {
        HookResult::deny("Rate limit exceeded")
    } else {
        HookResult::allow()
    }
});

Best Practices

Subscribe to specific events

Only subscribe to events you need – reduces overhead and improves performance.

Use priority for ordering

Hooks with higher priority run first. Use for security checks before logging.

Keep hooks fast

Hooks run in the hot path – avoid expensive operations.

Return clear deny reasons

When denying, provide actionable error messages.


Related