Skip to main content

Hooks Module

The hooks module provides a powerful hook system for intercepting and modifying agent behavior at various lifecycle points. Unlike callbacks (which are for UI events), hooks can intercept, modify, or block tool execution.

Installation

pip install praisonaiagents

Features

  • Event-based hook system - BeforeTool, AfterTool, BeforeAgent, etc.
  • Shell command hooks - External integrations via shell commands
  • Python function hooks - In-process customization
  • Matcher patterns - Selective hook execution
  • Decision outcomes - allow, deny, block, ask

Quick Start (Simplified API)

The simplest way to use hooks:
from praisonaiagents.hooks import add_hook, has_hook, remove_hook

# Register a hook - no HookResult needed!
@add_hook('before_tool')
def log_tools(event_data):
    print(f"Tool: {event_data.tool_name}")
    # No return = allow

@add_hook('before_tool')
def block_dangerous(event_data):
    if 'delete' in event_data.tool_name:
        return "Delete not allowed"  # String = deny with reason
    # No return = allow

# Check and manage hooks
has_hook('before_tool')  # True
remove_hook(hook_id)     # Remove by ID

Return Values

ReturnMeaning
None / no returnAllow
TrueAllow
FalseDeny
"reason"Deny with message
HookResult(...)Full control (advanced)

Classes

HookEvent

Enumeration of available hook events.
from praisonaiagents.hooks import HookEvent

# Available events
HookEvent.BEFORE_TOOL      # Before tool execution
HookEvent.AFTER_TOOL       # After tool execution
HookEvent.BEFORE_AGENT     # Before agent runs
HookEvent.AFTER_AGENT      # After agent completes
HookEvent.SESSION_START    # When session starts
HookEvent.SESSION_END      # When session ends

HookDecision

Possible decisions a hook can return.
DecisionDescription
allowAllow the operation to proceed
denyDeny the operation with a reason
blockBlock the operation silently
askPrompt for user confirmation

HookResult

Result returned by a hook function.
from praisonaiagents.hooks import HookResult

# Allow the operation
result = HookResult(decision="allow")

# Deny with reason
result = HookResult(decision="deny", reason="Tool blocked by policy")

# Modify the input
result = HookResult(decision="allow", modified_input={"query": "sanitized"})

Attributes

AttributeTypeDescription
decisionstrThe decision (allow/deny/block/ask)
reasonstrReason for the decision
modified_inputdictModified input to pass to the operation
metadatadictAdditional metadata

HookRegistry

Registry for managing hooks.
from praisonaiagents.hooks import HookRegistry, HookEvent

registry = HookRegistry()

# Register a function hook using decorator
@registry.on(HookEvent.BEFORE_TOOL)
def my_hook(event_data):
    return HookResult(decision="allow")

# Register a command hook
registry.register_command_hook(
    event=HookEvent.BEFORE_TOOL,
    command="python /path/to/validator.py",
    matcher="write_*"  # Only match tools starting with write_
)

Methods

MethodDescription
on(event)Decorator to register a function hook
register_command_hook(event, command, matcher)Register a shell command hook
register_function_hook(event, func, matcher)Register a function hook
get_hooks(event)Get all hooks for an event
clear()Clear all registered hooks

HookRunner

Executes hooks for events.
from praisonaiagents.hooks import HookRunner, HookRegistry

registry = HookRegistry()
runner = HookRunner(registry)

# Run hooks for an event
result = runner.run(HookEvent.BEFORE_TOOL, event_data)

Event Input Types

BeforeToolInput

from praisonaiagents.hooks import BeforeToolInput

input_data = BeforeToolInput(
    tool_name="write_file",
    tool_input={"path": "/tmp/file.txt", "content": "data"},
    agent_name="Writer"
)

AfterToolInput

from praisonaiagents.hooks import AfterToolInput

input_data = AfterToolInput(
    tool_name="write_file",
    tool_input={"path": "/tmp/file.txt"},
    tool_output="File written successfully",
    agent_name="Writer"
)

BeforeAgentInput / AfterAgentInput

from praisonaiagents.hooks import BeforeAgentInput, AfterAgentInput

before = BeforeAgentInput(
    agent_name="Researcher",
    task_description="Research AI trends"
)

after = AfterAgentInput(
    agent_name="Researcher",
    task_description="Research AI trends",
    result="Research completed"
)

Usage Examples

Basic Hook Registration

from praisonaiagents import Agent
from praisonaiagents.hooks import HookRegistry, HookEvent, HookResult

# Create registry
registry = HookRegistry()

# Register a hook to block dangerous tools
@registry.on(HookEvent.BEFORE_TOOL)
def security_hook(event_data):
    dangerous_tools = ["delete_file", "execute_command"]
    if event_data.tool_name in dangerous_tools:
        return HookResult(
            decision="deny",
            reason=f"Tool '{event_data.tool_name}' is blocked by security policy"
        )
    return HookResult(decision="allow")

# Use with agent
agent = Agent(
    name="Assistant",
    hooks=registry
)

Logging Hook

from praisonaiagents.hooks import HookRegistry, HookEvent, HookResult
import logging

registry = HookRegistry()

@registry.on(HookEvent.BEFORE_TOOL)
def log_tool_calls(event_data):
    logging.info(f"Tool called: {event_data.tool_name}")
    logging.info(f"Input: {event_data.tool_input}")
    return HookResult(decision="allow")

@registry.on(HookEvent.AFTER_TOOL)
def log_tool_results(event_data):
    logging.info(f"Tool result: {event_data.tool_output}")
    return HookResult(decision="allow")

Input Sanitization Hook

from praisonaiagents.hooks import HookRegistry, HookEvent, HookResult

registry = HookRegistry()

@registry.on(HookEvent.BEFORE_TOOL)
def sanitize_input(event_data):
    if event_data.tool_name == "search_web":
        # Sanitize the query
        sanitized_query = event_data.tool_input.get("query", "").strip()
        return HookResult(
            decision="allow",
            modified_input={"query": sanitized_query}
        )
    return HookResult(decision="allow")

Shell Command Hook

from praisonaiagents.hooks import HookRegistry, HookEvent

registry = HookRegistry()

# Run external validator before file writes
registry.register_command_hook(
    event=HookEvent.BEFORE_TOOL,
    command="python /path/to/file_validator.py",
    matcher="write_*"  # Only for tools starting with write_
)

Matcher Patterns

from praisonaiagents.hooks import HookRegistry, HookEvent, HookResult

registry = HookRegistry()

# Match specific tools
registry.register_function_hook(
    event=HookEvent.BEFORE_TOOL,
    func=my_hook,
    matcher="write_file"  # Exact match
)

# Match with wildcard
registry.register_function_hook(
    event=HookEvent.BEFORE_TOOL,
    func=my_hook,
    matcher="file_*"  # Matches file_read, file_write, etc.
)

# Match multiple patterns
registry.register_function_hook(
    event=HookEvent.BEFORE_TOOL,
    func=my_hook,
    matcher=["read_*", "write_*"]  # Multiple patterns
)

Best Practices

  1. Keep hooks lightweight - Hooks run synchronously, avoid heavy operations
  2. Use matchers - Only run hooks for relevant tools
  3. Return early - Return allow quickly for non-matching cases
  4. Log decisions - Log why hooks deny operations for debugging
  5. Handle errors - Wrap hook logic in try/except to avoid breaking agents