OpenAI Agents SDK

The OpenAI Agents SDK reports the lifecycle of a run through hooks: model calls, tool calls, handoffs and agent turns. AgentPing ships a hooks implementation for both the Python (openai-agents) and TypeScript (@openai/agents) packages, so a multi-agent run lands as one AgentPing run with an llm_call per model call, a tool_call per tool, and a step per handoff and agent turn.

Install / enable

Python:

pip install "agentping-io[openai-agents]"
import agentping
from agents import Agent, Runner

agentping.init()
agentping.instrument_openai_agents()

triage = Agent(name="triage", instructions="Route the ticket.")

with agentping.run("support-triage", customer_id="acme-corp"):
    result = await Runner.run(triage, "My invoice is wrong")

instrument_openai_agents() patches Runner.run and Runner.run_sync so an AgentPingHooks instance is attached to every run that does not pass its own hooks=. If you already use hooks, or want to pin the events to a specific run, attach them yourself instead:

from agentping import AgentPingHooks

result = await Runner.run(triage, "My invoice is wrong", hooks=AgentPingHooks(run=r))

AgentPingHooks(run=None, capture_tool_payloads=True, tool_payload_max_chars=4000). Supported openai-agents versions: below 2.0.

TypeScript:

npm install @agentping/sdk @openai/agents openai
import { Agent, Runner, setDefaultOpenAIClient } from "@openai/agents";
import OpenAI from "openai";
import * as agentping from "@agentping/sdk";

agentping.init({ apiKey: process.env.AGENTPING_API_KEY });

const run = agentping.run("support-triage", { customerId: "acme-corp" });

// Model calls: the Agents SDK does not expose them through hooks,
// so give it an instrumented OpenAI client.
setDefaultOpenAIClient(agentping.instrumentOpenAI(new OpenAI(), { run }));

// Tool calls, handoffs and agent turns: attach the hooks to the runner.
const runner = new Runner();
new agentping.AgentPingHooks(run).attach(runner);

const result = await runner.run(triage, "My invoice is wrong");
await run.finish({ status: "success" });

new AgentPingHooks(run?, { captureToolPayloads?, toolPayloadMaxChars? }). The run argument is optional; without it the hooks resolve the active run from runScopeAsync.

Events

Agents SDK hook AgentPing event What is recorded
on_llm_end (Python only) llm_call Provider and model, gross input tokens, output tokens, cached and reasoning tokens when non-zero, number of tool calls the model requested, latency. Models routed through LiteLLM (litellm/anthropic/claude-...) or written as provider/model get the right provider; anything else is openai.
on_tool_end tool_call Tool name, tool_invocation_id (the SDK's tool_call_id), arguments and result (capped at tool_payload_max_chars, off with capture_tool_payloads=False), latency.
on_handoff step with kind: "handoff" from and to agent names.
on_agent_end step with kind: "agent" Agent name and the turn's latency.

In TypeScript the hooks emit the tool_call and step rows; the llm_call rows come from the instrumented OpenAI client, with the same fields as the OpenAI page.

Two gaps worth knowing. The Agents SDK does not pass tool failures through its hooks, so tool_call events always carry status: "success"; a tool that throws ends the run instead, and you record that with run.finish(status="error") or your own error event. Model call failures likewise never reach on_llm_end, so a failed request is visible as the run's error, not as an errored llm_call.

Naming

The AgentPing run name is whatever you pass to agentping.run(...); it is not taken from the agent, since one run usually spans several agents. Each agent's name shows up on its step events and on handoffs, which is enough to follow the route a ticket took through the agents.

Source / notes

For span-level traces rather than events, OpenInference's openinference-instrumentation-openai-agents exports the SDK's traces over OTLP; point it at the OpenTelemetry endpoint.