---
title: OpenAI Agents SDK
description: Attach AgentPing hooks to the OpenAI Agents SDK so model calls, tool calls, handoffs and agent turns land as events on one run.
section: frameworks
order: 1
---

# 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:

```bash
pip install "agentping-io[openai-agents]"
```

```python
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:

```python
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:

```bash
npm install @agentping/sdk @openai/agents openai
```

```typescript
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](/docs/providers/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

- Python: `agentping.instrument_openai_agents()` and `agentping.AgentPingHooks` in [agent-ping-python](https://github.com/agent-ping/agent-ping-python)
- TypeScript: `AgentPingHooks` in [agent-ping-typescript](https://github.com/agent-ping/agent-ping-typescript)

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](/docs/integrations/opentelemetry) endpoint.
