Skip to main content

Hooks Overview

Hooks are decorator-based lifecycle handlers that let you observe and modify agent behavior at key execution points.

Hook Categories

Egregore provides 5 hook categories:
CategoryPurposeExample
ToolTool execution lifecycleLog tool calls, modify results
ContextContext tree operationsValidate changes, audit operations
StreamingReal-time response streamingProcess chunks, filter content
MessageMessage handlingModify user/provider messages
ScaffoldScaffold state changesTrack scaffold updates

Basic Usage

from egregore import Agent

agent = Agent(provider="openai:gpt-4")

@agent.hooks.tool.pre_call
def log_tool(ctx):
    print(f"Calling tool: {ctx.tool_name}")

@agent.hooks.tool.post_call
def log_result(ctx):
    print(f"Result: {ctx.tool_result}")

# Hooks fire automatically
agent.call("Use the calculator tool")
# Output: "Calling tool: calculator"
# Output: "Result: 42"

Hook Registration

Use decorators directly on agent instance:
# Tool hooks
@agent.hooks.tool.pre_call
@agent.hooks.tool.post_call
@agent.hooks.tool.on_error

# Context hooks
@agent.hooks.context.before_change
@agent.hooks.context.after_change

# Streaming hooks
@agent.hooks.streaming.on_chunk

# Message hooks
@agent.hooks.message.on_user_msg
@agent.hooks.message.on_provider_msg

# Scaffold hooks
@agent.hooks.scaffold.on_state_change

Hook Context Objects

Every hook receives a context object with relevant data:
@agent.hooks.tool.pre_call
def my_hook(ctx: ToolExecContext):
    # Common fields
    ctx.agent          # Agent instance
    ctx.context        # Context tree

    # Tool-specific fields
    ctx.tool_name      # Tool being called
    ctx.tool_args      # Tool arguments
    ctx.tool_kwargs    # Tool keyword arguments

Common Use Cases

Logging and Monitoring

@agent.hooks.tool.pre_call
def log_tool_usage(ctx):
    print(f"[TOOL] {ctx.tool_name} called with {ctx.tool_args}")

@agent.hooks.context.after_change
def log_context_changes(ctx):
    print(f"[CONTEXT] {ctx.operation_type} at {ctx.selector}")

Error Handling

@agent.hooks.tool.on_error
def handle_tool_error(ctx):
    print(f"Tool {ctx.tool_name} failed: {ctx.error}")
    # Log to monitoring service
    monitor.log_error(ctx.tool_name, ctx.error)

Content Filtering

@agent.hooks.streaming.on_chunk
def filter_sensitive_data(ctx):
    # Remove sensitive patterns
    filtered = ctx.chunk_data.replace("SECRET", "[REDACTED]")
    return filtered, True  # (content, was_modified)

Validation

@agent.hooks.context.before_change
def validate_changes(ctx):
    if ctx.operation_type == "delete" and ctx.component.critical:
        raise ValueError("Cannot delete critical component")

Hook Execution Order

Multiple hooks execute in registration order:
@agent.hooks.tool.pre_call
def first_hook(ctx):
    print("1")

@agent.hooks.tool.pre_call
def second_hook(ctx):
    print("2")

agent.call("Use tool")
# Output: "1"
# Output: "2"

What’s Next?