Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:Openai Openai agents python Lifecycle Hooks Pattern

From Leeroopedia
Knowledge Sources
Domains Agent_Configuration, Observability, Design_Pattern
Last Updated 2026-02-11 00:00 GMT

Overview

Demonstrates both run-level RunHooks and agent-level AgentHooks for observing and logging lifecycle events during agent execution, including agent start/end, LLM calls, tool invocations, and handoffs.

Description

The lifecycle_example.py example demonstrates the SDK's two-tier hooks system for observing and reacting to events during agent execution. The run-level ExampleHooks(RunHooks) class provides comprehensive visibility across an entire run, tracking seven event types: on_agent_start, on_agent_end, on_llm_start, on_llm_end, on_tool_start, on_tool_end, and on_handoff. It maintains an event counter and prints detailed information including agent names, tool call IDs, arguments, results, and cumulative usage statistics (requests, input/output/total tokens) at each event.

The agent-level LoggingHooks(AgentHooks) class provides per-agent visibility with on_start and on_end callbacks. The on_start method receives an AgentHookContext with access to the turn_input showing what input the agent received, while on_end receives the agent's output. Each agent can have its own AgentHooks instance, enabling agent-specific logging or behavior.

The example sets up a two-agent pipeline: a start_agent that generates a random number and hands off to a multiply_agent if the number is odd. Both agents are configured with LoggingHooks() for agent-level tracking, and the run is executed with ExampleHooks() for run-level tracking. The tool hooks note that they apply only to local tools and do not fire for hosted tools (WebSearchTool, FileSearchTool, CodeInterpreterTool, HostedMCPTool).

Usage

Use this pattern when you need to observe, log, measure, or react to lifecycle events during agent execution. Common use cases include logging and debugging, usage tracking (token consumption per step), latency monitoring, audit trails for compliance, custom metrics collection, and building reactive systems that respond to specific lifecycle events.

Code Reference

Source Location

Signature

class ExampleHooks(RunHooks):
    def __init__(self): ...
    async def on_agent_start(self, context: AgentHookContext, agent: Agent) -> None: ...
    async def on_llm_start(self, context: RunContextWrapper, agent: Agent, system_prompt: Optional[str], input_items: list[TResponseInputItem]) -> None: ...
    async def on_llm_end(self, context: RunContextWrapper, agent: Agent, response: ModelResponse) -> None: ...
    async def on_agent_end(self, context: RunContextWrapper, agent: Agent, output: Any) -> None: ...
    async def on_tool_start(self, context: RunContextWrapper, agent: Agent, tool: Tool) -> None: ...
    async def on_tool_end(self, context: RunContextWrapper, agent: Agent, tool: Tool, result: str) -> None: ...
    async def on_handoff(self, context: RunContextWrapper, from_agent: Agent, to_agent: Agent) -> None: ...

class LoggingHooks(AgentHooks[Any]):
    async def on_start(self, context: AgentHookContext[Any], agent: Agent[Any]) -> None: ...
    async def on_end(self, context: RunContextWrapper[Any], agent: Agent[Any], output: Any) -> None: ...

Import

from agents import (
    Agent,
    AgentHookContext,
    AgentHooks,
    RunContextWrapper,
    RunHooks,
    Runner,
    Tool,
    Usage,
    function_tool,
)
from agents.items import ModelResponse, TResponseInputItem
from agents.tool_context import ToolContext

I/O Contract

Inputs

Name Type Required Description
hooks (run-level) RunHooks No Passed to Runner.run() to observe run-wide lifecycle events
hooks (agent-level) AgentHooks No Passed to Agent() constructor to observe per-agent lifecycle events
context (on_agent_start) AgentHookContext Yes Provides turn_input and usage data at agent start
context (on_tool_start/end) RunContextWrapper (castable to ToolContext) Yes Provides tool_name, tool_call_id, tool_arguments, and usage data

Outputs

Name Type Description
Event log lines stdout Numbered event entries with agent name, tool details, usage stats, and handoff information
Usage stats Usage Cumulative request count, input_tokens, output_tokens, and total_tokens at each event

Usage Examples

Define Run-Level Hooks

from agents import RunHooks, RunContextWrapper, Agent, AgentHookContext, Tool, Usage

class MyRunHooks(RunHooks):
    async def on_agent_start(self, context: AgentHookContext, agent: Agent) -> None:
        print(f"Agent {agent.name} started with input: {context.turn_input}")

    async def on_tool_start(self, context: RunContextWrapper, agent: Agent, tool: Tool) -> None:
        print(f"Tool {tool.name} invoked")

    async def on_handoff(self, context: RunContextWrapper, from_agent: Agent, to_agent: Agent) -> None:
        print(f"Handoff: {from_agent.name} -> {to_agent.name}")

Define Agent-Level Hooks

from agents import AgentHooks, AgentHookContext, RunContextWrapper, Agent

class MyAgentHooks(AgentHooks):
    async def on_start(self, context: AgentHookContext, agent: Agent) -> None:
        print(f"{agent.name} is starting")

    async def on_end(self, context: RunContextWrapper, agent: Agent, output) -> None:
        print(f"{agent.name} produced: {output}")

Attach Hooks and Run

import asyncio
from agents import Agent, Runner, function_tool
from pydantic import BaseModel

class FinalResult(BaseModel):
    number: int

agent = Agent(
    name="My Agent",
    instructions="Do something useful.",
    hooks=MyAgentHooks(),
)

hooks = MyRunHooks()

async def main():
    await Runner.run(agent, hooks=hooks, input="Process this request.")

asyncio.run(main())

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment