Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions components/IntegrationTitleMark.astro
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const logos: Record<string, string> = {
"/integrations/mcp": "model-context-protocol",
"/integrations/omp": "oh-my-pi",
"/integrations/openai": "openai",
"/integrations/openai-agents": "openai",
"/integrations/openclaw": "openclaw",
"/integrations/opencode": "opencode",
"/integrations/openrouter": "openrouter",
Expand Down
1 change: 1 addition & 0 deletions docs/integrations/(frameworks)/meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default defineMeta({
"langchain-langgraph",
"crewai",
"pydantic-ai",
"openai-agents",
"eve",
"mcp",
],
Expand Down
189 changes: 189 additions & 0 deletions docs/integrations/(frameworks)/openai-agents.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
---
title: OpenAI Agents SDK
description: Trace TypeScript OpenAI Agents SDK runs, model calls, tool calls, and sandbox commands with their exit codes.
lastModified: 2026-11-05
seo:
title: "OpenAI Agents SDK Tracing and Observability"
description: "Send TypeScript OpenAI Agents SDK traces to telemetry.dev: agents, turns, model calls with token usage and cost, tool calls, and sandbox commands with exit codes and sandbox IDs."
---

`@telemetry-dev/openai-agents` sends the runs of the TypeScript [OpenAI Agents SDK](https://openai.github.io/openai-agents-js/) to telemetry.dev: the agents and their turns, each model call with its token usage, each tool call, and each command that a sandbox agent ran, with its exit code and the sandbox it ran in.

The package is a trace processor for the Agents SDK. It reads the spans the SDK already records, so you don't change your agents or tools.

## Install

```package-install
npm i @telemetry-dev/openai-agents @openai/agents
```

The package supports `@openai/agents` 0.21.0 and later 0.x releases, and needs Node.js 22 or later, the Agents SDK's minimum.

## Set the API key

Create a project at [telemetry.dev](https://telemetry.dev), then create an API key on the project's **Setup** page. Set it where your app runs:

```sh
export TELEMETRY_DEV_API_KEY=td_live_...
export TELEMETRY_DEV_ENVIRONMENT=development
export OTEL_SERVICE_NAME=support-agent
```

Without an API key, the processor does nothing.

## Add the processor

Register the processor once, before the first run:

```ts agent.ts
import { addTraceProcessor, Agent, run } from "@openai/agents";
import { telemetryDevProcessor } from "@telemetry-dev/openai-agents";

addTraceProcessor(telemetryDevProcessor());

const agent = new Agent({ name: "Assistant", instructions: "Answer briefly." });
await run(agent, "What is OpenTelemetry?");
```

`addTraceProcessor` keeps the Agents SDK's default exporter, so traces also reach the OpenAI Traces dashboard. To send them only to telemetry.dev, replace the default exporter instead:

```ts agent.ts
import { setTraceProcessors } from "@openai/agents";
import { telemetryDevProcessor } from "@telemetry-dev/openai-agents";

setTraceProcessors([telemetryDevProcessor()]);
```

`setTraceProcessors` is also how you keep content away from OpenAI. With `addTraceProcessor`, the OpenAI exporter still receives tool arguments and results, Chat Completions inputs and outputs, sandbox commands and working directories, and trace metadata.

## Check the trace

Run your agent once and open [Traces](/platform/traces) in your project. A run contains:

- A root span named after the run's workflow, `Agent workflow` unless you set `workflowName`, and a `task {workflowName}` span under it
- A span for each agent, and a `turn N` span for each of its turns
- A `chat {model}` span for each model call, with its token usage, which telemetry.dev prices
- A span for each tool call, named after the tool
- Handoff, guardrail, and MCP tool-listing spans when the run has them

How runs group into traces:

- A run is one trace by default.
- A run that starts inside an active OpenTelemetry span, such as an HTTP request span, joins that span's trace.
- Runs that share a `groupId` share a session: the processor sends the `groupId` as the session ID (`gen_ai.conversation.id`). Runs inside the same [`propagateAttributes({ sessionId })`](/sdk/typescript#add-user-session-and-metadata) session (from `@telemetry-dev/sdk`) do too; a `groupId` takes precedence. Outside an active span, the runs of a session land in [one trace per session](/sdk/typescript#one-trace-per-session), each run as a root span.
- With `telemetryDevProcessor({ sessionMode: "process" })`, runs without a session of their own share the process's [generated session](/sdk/typescript#process-sessions) in the same way. Use this in a CLI or script that holds one conversation per process, not in a long-running server.

In short-lived runtimes such as serverless functions, flush at the end of each request:

```ts
import { getGlobalTraceProvider } from "@openai/agents";

await getGlobalTraceProvider().forceFlush();
```

A run that throws never ends its Agents SDK trace. The processor ends its root span after one minute without new spans, or at the next `forceFlush` or `shutdown` of the trace provider.

## Trace sandbox agents

Sandbox runs need no extra setup. Each `sandbox.*` span of the Agents SDK, such as `sandbox.create_session` and `sandbox.exec`, arrives with:

| Attribute | Value |
| --- | --- |
| `sandbox.operation` | The operation, such as `create_session` or `exec` |
| `sandbox.backend` | The sandbox backend, such as `e2b` or `modal`, when the run created or resumed its session |
| `sandbox.id` | The provider's sandbox ID, when you wrap the client as shown below |

The `exec_command` and `write_stdin` tool spans get `process.exit.code` once the command has exited. A command that exits with a non-zero code is not marked as an error, because many commands, such as `grep`, exit non-zero without failing.

### Record the provider's sandbox ID

Wrap the sandbox client with `instrumentSandboxClient()` to record the ID that the provider uses in its own dashboard, logs, and webhooks. The hosted clients are in `@openai/agents-extensions`, and most also need their provider's SDK, such as `e2b` for E2B:

```package-install
npm i @openai/agents-extensions e2b
```

The Docker and local clients come with `@openai/agents`.

```ts agent.ts
import { run } from "@openai/agents";
import { SandboxAgent } from "@openai/agents/sandbox";
import { E2BSandboxClient } from "@openai/agents-extensions/sandbox/e2b";
import { instrumentSandboxClient } from "@telemetry-dev/openai-agents";

const agent = new SandboxAgent({ name: "Coder", instructions: "Run the tests." });
const client = instrumentSandboxClient(new E2BSandboxClient());
await run(agent, "Run the tests.", { sandbox: { client } });
```

The session, command, and tool spans of that agent then carry `sandbox.id`. The wrapper reads the ID from the session the client creates or resumes, and not every backend keeps one there:

| Backend | Client | `sandbox.id` |
| --- | --- | --- |
| E2B | `E2BSandboxClient` | The E2B sandbox ID |
| Modal | `ModalSandboxClient` | The Modal sandbox ID |
| Daytona | `DaytonaSandboxClient` | The Daytona sandbox ID |
| Vercel | `VercelSandboxClient` | The Vercel sandbox ID |
| Cloudflare | `CloudflareSandboxClient` | The Cloudflare sandbox ID |
| Blaxel | `BlaxelSandboxClient` | Not recorded |
| Docker | `DockerSandboxClient` | Not recorded |
| Local | `UnixLocalSandboxClient` | Not recorded |

All of these clients still get `sandbox.backend`.

The backend and the ID come from the span that creates or resumes the session. A session that your app passes in with `sandbox: { session }`, or that a resumed run reuses while it is still live in the same process, has no such span, so the spans of that run have neither.

## Control captured content

The processor takes the [`init()` options](/sdk/typescript#configure-init) of `@telemetry-dev/sdk`. Use `captureInput` and `captureOutput` to keep content out of telemetry.dev, and `mask` to redact it:

```ts
addTraceProcessor(
telemetryDevProcessor({
captureInput: false,
captureOutput: false,
}),
);
```

These count as content:

- Model inputs and outputs
- Tool arguments and results
- The command and working directory of `sandbox.exec`, in `process.command_line` and `process.working_directory`

With capture off, telemetry.dev still receives span names and timing, model names, response IDs, token usage, turn numbers, agent, tool, handoff, and guardrail names, each agent's tools, handoffs, and output type, whether a guardrail triggered, the MCP server of a tool call and the number of tools an MCP server listed, exit codes, sandbox backends and IDs, error types, the session ID (such as the run's `groupId`, a `propagateAttributes()` session, or the process session), the user ID and metadata of `propagateAttributes()`, the Agents SDK trace ID, and the string, number, and boolean values of trace metadata and of the data of custom spans. Trace metadata, custom span data, and `propagateAttributes()` metadata do not go through `mask`.

Keep the Agents SDK's `traceIncludeSensitiveData` on, which is its default. With it off, the SDK leaves token usage and tool output off its spans, and the Responses API model leaves off the model name too, so telemetry.dev cannot price model calls or read exit codes. Turn content off with `captureInput` and `captureOutput` instead.

## Don't also instrument the OpenAI client

The processor already records each model call as a `chat` span. Don't also instrument the OpenAI client that the Agents SDK uses with [`@telemetry-dev/openai`](/integrations/openai): neither a client wrapped with `wrapOpenAI()` and passed to `setDefaultOpenAIClient`, nor `instrumentOpenAI()`, which instruments every client in the process. Each model call would be recorded and priced twice.

## Options

`telemetryDevProcessor()` accepts every [`init()` option](/sdk/typescript#configure-init) of `@telemetry-dev/sdk`. The variables you are most likely to set:

| Variable | Default | Description |
| --- | --- | --- |
| `TELEMETRY_DEV_API_KEY` | None | Ingest API key. Without a key, the processor does nothing. |
| `TELEMETRY_DEV_BASE_URL` | `https://api.telemetry.dev` | Ingest base URL |
| `TELEMETRY_DEV_ENVIRONMENT` | `production` | Environment on exported telemetry |
| `OTEL_SERVICE_NAME` | SDK default | Service name |

The first processor created in a process sets up the SDK, and later processors ignore their options. Pass SDK options to the processor rather than calling `init()` yourself: the processor replaces a client that an earlier `init()` call made.

## Limitations

The Agents SDK shuts the trace provider down on `SIGTERM`, `SIGINT`, and unhandled rejections. The processor then ends every open span so nothing is lost if the process exits. A model call that was in progress at that moment is sent without its token usage.

For the package source and changelog, see [`@telemetry-dev/openai-agents` on GitHub](https://github.com/telemetry-dev/telemetry/tree/main/packages/openai-agents).

<CardGroup cols={2}>
<Card title="View traces" href="/platform/traces" icon="activity">
Open the trace explorer and examine the span waterfall.
</Card>
<Card title="API key setup" href="/quickstart" icon="key">
Set the telemetry.dev API key and service name.
</Card>
</CardGroup>
4 changes: 3 additions & 1 deletion docs/integrations/(model-providers)/openai.mdx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
---
title: OpenAI
description: Trace OpenAI chat, Responses API, embedding, media, batch, and stream calls from TypeScript or Python.
lastModified: 2026-10-26
lastModified: 2026-11-05
seo:
title: "OpenAI API Tracing and Token Usage"
description: "Trace OpenAI chat completions, Responses API, embedding, and stream calls from TypeScript or Python, with token usage, errors, and time to first chunk."
---

Wrap your OpenAI client, and each call you make with it becomes a span in telemetry.dev. Your calls and their return values don't change.

To trace runs of the TypeScript OpenAI Agents SDK, see [OpenAI Agents SDK](/integrations/openai-agents); don't wrap the client the Agents SDK uses or call `instrumentOpenAI()` in a process that runs the Agents SDK, or each model call is recorded twice.

## What you get

- Chat messages, Responses API input, system instructions, model parameters, and embedding input
Expand Down
3 changes: 2 additions & 1 deletion docs/integrations/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Integrations
description: Choose a telemetry.dev integration for your framework, model provider, coding agent, SDK, or OpenTelemetry setup.
sidebar: { label: "Overview" }
lastModified: 2026-10-27
lastModified: 2026-11-05
seo:
title: "LLM and AI Agent Integrations"
description: "Connect telemetry.dev to the Vercel AI SDK, LangChain, OpenAI, Anthropic, LiteLLM, Claude Code, Cursor, opencode, and more through SDKs or native OpenTelemetry."
Expand All @@ -23,6 +23,7 @@ Pick the guide for the code that makes your model calls:
<IntegrationCard title="LangChain and LangGraph" href="/integrations/langchain-langgraph" mark="langchain">Trace chains, model calls, and tools through OpenTelemetry.</IntegrationCard>
<IntegrationCard title="CrewAI" href="/integrations/crewai" mark="crewai">Export CrewAI and model spans with OpenLIT.</IntegrationCard>
<IntegrationCard title="Pydantic AI" href="/integrations/pydantic-ai" mark="pydantic-ai">Use Pydantic AI's native OpenTelemetry instrumentation.</IntegrationCard>
<IntegrationCard title="OpenAI Agents SDK" href="/integrations/openai-agents" mark="openai">Trace TypeScript Agents SDK runs, tool calls, and sandbox commands.</IntegrationCard>
<IntegrationCard title="Eve" href="/integrations/eve" mark="eve">Trace Eve agent-framework runs.</IntegrationCard>
<IntegrationCard title="Model Context Protocol" href="/integrations/mcp" mark="model-context-protocol">Trace official TypeScript MCP SDK v2 transports.</IntegrationCard>
</CardGroup>
Expand Down
1 change: 1 addition & 0 deletions test/routing.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const integrationMarks = {
"/docs/integrations/mcp": "/docs/integrations/model-context-protocol.svg",
"/docs/integrations/omp": "/docs/integrations/oh-my-pi.svg",
"/docs/integrations/openai": "/docs/integrations/openai.svg",
"/docs/integrations/openai-agents": "/docs/integrations/openai.svg",
"/docs/integrations/openclaw": "/docs/integrations/openclaw.svg",
"/docs/integrations/opencode": "/docs/integrations/opencode.svg",
"/docs/integrations/openrouter": "/docs/integrations/openrouter.svg",
Expand Down