> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://respan.ai/docs/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://respan.ai/_mcp/server.

# OpenAI Agents (tracing)

> Trace OpenAI Agents SDK workflows with Respan — auto-instrumented spans, gateway routing, and full observability.

The [OpenAI Agents SDK](https://openai.github.io/openai-agents-python/) (`openai-agents`) is a lightweight framework for building multi-agent workflows with tools, handoffs, and guardrails. Respan gives you full observability over every agent run, LLM generation, tool call, and handoff — and gateway routing to 250+ models.

#### Set up Respan

Create an account at [platform.respan.ai](https://platform.respan.ai) and grab an [API key](https://platform.respan.ai/platform/api/api-keys).

Run `npx @respan/cli setup` to set up with your coding agent.

#### Use Respan Gateway

See [OpenAI Agents SDK gateway setup](/docs/gateway/openai-agents-sdk) to route this integration through the Respan gateway.

#### Example projects

* [Python examples](https://github.com/respanai/respan-example-projects/tree/main/python/tracing/openai-agents-sdk)
* [TypeScript examples](https://github.com/respanai/respan-example-projects/tree/main/typescript/tracing/openai-agents-sdk)

## Setup

#### Install packages

```bash Python
pip install respan-ai respan-instrumentation-openai-agents
```

```bash TypeScript
npm install @respan/respan @respan/instrumentation-openai-agents
```

#### Set environment variables

```bash
export OPENAI_API_KEY="YOUR_OPENAI_API_KEY"
export RESPAN_API_KEY="YOUR_RESPAN_API_KEY"
```

#### Initialize and run

```python Python
import os
import asyncio
from dotenv import load_dotenv

load_dotenv()

from respan import Respan
from respan_instrumentation_openai_agents import OpenAIAgentsInstrumentor
from agents import Agent, Runner, trace

respan = Respan(instrumentations=[OpenAIAgentsInstrumentor()])

agent = Agent(
    name="Assistant",
    instructions="You only respond in haikus.",
)

async def main():
    with trace("Hello world"):
        result = await Runner.run(agent, "Tell me about recursion.")
        print(result.final_output)

asyncio.run(main())
```

```typescript TypeScript
import { Agent, run } from "@openai/agents";
import { Respan } from "@respan/respan";
import { OpenAIAgentsInstrumentor } from "@respan/instrumentation-openai-agents";

const respan = new Respan({
  apiKey: process.env.RESPAN_API_KEY,
  baseURL: process.env.RESPAN_BASE_URL,
  instrumentations: [new OpenAIAgentsInstrumentor()],
});
await respan.initialize();

const agent = new Agent({
  name: "Assistant",
  instructions: "You only respond in haikus.",
});

const result = await run(agent, "Tell me about recursion.");
console.log(result.finalOutput);
```

#### View your trace

Open the [Traces page](https://platform.respan.ai/platform/traces) to see your workflow with agent spans, LLM generations, tool calls, and handoffs.

## Configuration

| Parameter             | Type           | Default | Description                                                              |
| --------------------- | -------------- | ------- | ------------------------------------------------------------------------ |
| `api_key`             | `str \| None`  | `None`  | Falls back to `RESPAN_API_KEY` env var.                                  |
| `base_url`            | `str \| None`  | `None`  | Falls back to `RESPAN_BASE_URL` env var.                                 |
| `instrumentations`    | `list`         | `[]`    | Plugin instrumentations to activate (e.g. `OpenAIAgentsInstrumentor()`). |
| `customer_identifier` | `str \| None`  | `None`  | Default customer identifier for all spans.                               |
| `metadata`            | `dict \| None` | `None`  | Default metadata attached to all spans.                                  |
| `environment`         | `str \| None`  | `None`  | Environment tag (e.g. `"production"`).                                   |

## Attributes

### In Respan()

Set defaults at initialization — these apply to all spans.

```python Python
from respan import Respan
from respan_instrumentation_openai_agents import OpenAIAgentsInstrumentor

respan = Respan(
    instrumentations=[OpenAIAgentsInstrumentor()],
    customer_identifier="user_123",
    metadata={"service": "agent-api", "version": "1.0.0"},
)
```

```typescript TypeScript
import { Respan } from "@respan/respan";
import { OpenAIAgentsInstrumentor } from "@respan/instrumentation-openai-agents";

// Note: default attributes are set via propagateAttributes() in TypeScript
const respan = new Respan({
  instrumentations: [new OpenAIAgentsInstrumentor()],
});
```

### With propagate\_attributes

Override per-request using a context scope.

```python Python
from respan import Respan, propagate_attributes
from respan_instrumentation_openai_agents import OpenAIAgentsInstrumentor
from agents import Agent, Runner, trace

respan = Respan(instrumentations=[OpenAIAgentsInstrumentor()])

agent = Agent(name="Assistant", instructions="You are a helpful assistant.")

async def handle_request(user_id: str, message: str):
    with trace("User request"):
        with propagate_attributes(
            customer_identifier=user_id,
            thread_identifier="conv_abc_123",
            metadata={"plan": "pro"},
        ):
            result = await Runner.run(agent, message)
            print(result.final_output)
```

```typescript TypeScript
import { Agent, run } from "@openai/agents";
import { Respan } from "@respan/respan";
import { OpenAIAgentsInstrumentor } from "@respan/instrumentation-openai-agents";

const respan = new Respan({
  instrumentations: [new OpenAIAgentsInstrumentor()],
});
await respan.initialize();

const agent = new Agent({
  name: "Assistant",
  instructions: "You are a helpful assistant.",
});

async function handleRequest(userId: string, message: string) {
  await respan.propagateAttributes(
    {
      customer_identifier: userId,
      thread_identifier: "conv_abc_123",
      metadata: { plan: "pro" },
    },
    async () => {
      const result = await run(agent, message);
      console.log(result.finalOutput);
    }
  );
}
```

| Attribute             | Type   | Description                                           |
| --------------------- | ------ | ----------------------------------------------------- |
| `customer_identifier` | `str`  | Identifies the end user in Respan analytics.          |
| `thread_identifier`   | `str`  | Groups related messages into a conversation.          |
| `metadata`            | `dict` | Custom key-value pairs. Merged with default metadata. |

## Decorators (optional)

Decorators are not required. All agent runs, LLM calls, tool calls, and handoffs are auto-traced by the instrumentor. Use `@workflow` and `@task` to add structure when you want to group agent runs into named workflows with nested tasks.

```python
from respan import Respan, workflow, task
from respan_instrumentation_openai_agents import OpenAIAgentsInstrumentor
from agents import Agent, Runner, function_tool

respan = Respan(instrumentations=[OpenAIAgentsInstrumentor()])

@function_tool
def search_docs(query: str) -> str:
    """Search the documentation."""
    return f"Results for: {query}"

researcher = Agent(
    name="Researcher",
    instructions="You research topics using the search tool.",
    tools=[search_docs],
)

writer = Agent(
    name="Writer",
    instructions="You write concise summaries.",
)

@task(name="research")
async def research(topic: str) -> str:
    result = await Runner.run(researcher, f"Research: {topic}")
    return result.final_output

@workflow(name="research_and_write")
async def pipeline(topic: str):
    findings = await research(topic)
    result = await Runner.run(writer, f"Summarize: {findings}")
    print(result.final_output)

import asyncio
asyncio.run(pipeline("API gateways"))
```

## Examples

### Tool calls

Tool calls are automatically captured as spans with inputs, outputs, and timing.

```python
from agents import Agent, Runner, function_tool, trace

@function_tool
def get_weather(city: str) -> str:
    """Get the weather for a city."""
    return f"The weather in {city} is sunny, 72F"

agent = Agent(
    name="Weather Agent",
    instructions="Help users check the weather.",
    tools=[get_weather],
)

async def main():
    with trace("Weather check"):
        result = await Runner.run(agent, "What's the weather in San Francisco?")
        print(result.final_output)
```

### Handoffs

Agent-to-agent handoffs are traced with full context.

```python
from agents import Agent, Runner, trace

billing_agent = Agent(
    name="Billing Agent",
    instructions="Handle billing questions.",
)

support_agent = Agent(
    name="Support Agent",
    instructions="Route billing questions to the billing agent.",
    handoffs=[billing_agent],
)

async def main():
    with trace("Support handoff"):
        result = await Runner.run(support_agent, "I have a billing question")
        print(result.final_output)
```

### Streaming

Stream agent responses with real-time text deltas.

```python
from openai.types.responses import ResponseTextDeltaEvent
from agents import Agent, Runner

agent = Agent(name="Joker", instructions="You tell jokes.")

result = Runner.run_streamed(agent, input="Tell me 3 jokes.")
async for event in result.stream_events():
    if event.type == "raw_response_event" and isinstance(
        event.data, ResponseTextDeltaEvent
    ):
        print(event.data.delta, end="", flush=True)
```