> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bitfab.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenAI Agents SDK

> Automatic tracing for OpenAI Agents SDK with Bitfab

Bitfab integrates with the [OpenAI Agents SDK](https://openai.github.io/openai-agents-python/) via a tracing processor that automatically captures agent runs, tool calls, handoffs, and guardrails as traced spans - no manual `withSpan` or `@span` decorators needed. To make those runs replayable, a thin run wrapper (`wrapRun` / `wrap_run`) records a root span carrying the run input; see [Replayable runs with the run wrapper](#replayable-runs-with-the-run-wrapper).

**Canonical signatures:** [TypeScript reference](/reference/typescript#framework-integrations) · [Python reference](/reference/python#framework-integrations)

## Supported Languages

| Language   | Method                                                          | Status            |
| ---------- | --------------------------------------------------------------- | ----------------- |
| TypeScript | `getOpenAiTracingProcessor()` + `getOpenAiAgentHandler()`       | ✅ Supported       |
| Python     | `get_openai_tracing_processor()` + `get_openai_agent_handler()` | ✅ Supported       |
| Ruby       | -                                                               | Not yet supported |
| Go         | -                                                               | Not yet supported |

## Quick Start

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { Bitfab } from "@bitfab/sdk"
  import { addTraceProcessor, Agent } from "@openai/agents"

  const bitfab = new Bitfab({ apiKey: process.env.BITFAB_API_KEY })

  // Register the processor once: it captures agent internals (LLM/tool/handoff spans).
  addTraceProcessor(bitfab.getOpenAiTracingProcessor())

  const agent = new Agent({ name: "my-agent", instructions: "..." })
  const handler = bitfab.getOpenAiAgentHandler("my-agent")

  // Use wrapRun (a drop-in for run) so the trace gets a replayable root.
  const result = await handler.wrapRun(agent, "user input here")
  ```

  ```python Python theme={null}
  import os
  from bitfab import Bitfab
  from agents import Agent, add_trace_processor

  bitfab = Bitfab(api_key=os.environ["BITFAB_API_KEY"])

  # Register the processor once: it captures agent internals (LLM/tool/handoff spans).
  add_trace_processor(bitfab.get_openai_tracing_processor())

  agent = Agent(name="my-agent", instructions="...")
  handler = bitfab.get_openai_agent_handler("my-agent")

  # Use wrap_run (a drop-in for Runner.run) so the trace gets a replayable root.
  result = await handler.wrap_run(agent, "user input here")
  ```
</CodeGroup>

<Note>
  Use `addTraceProcessor` / `add_trace_processor` (shown above) to **add** the Bitfab processor alongside any existing ones. The OpenAI Agents SDK also exposes `setTraceProcessors` / `set_trace_processors`, which **replaces** the entire processor list, including the SDK's default exporter to the OpenAI platform dashboard. Only use the `set` form if you want Bitfab to be the sole destination and intend to disable OpenAI's own tracing.
</Note>

## TypeScript

### Installation

```bash theme={null}
npm install @bitfab/sdk @openai/agents
```

### Method Signature

```typescript theme={null}
bitfab.getOpenAiTracingProcessor(): BitfabOpenAITracingProcessor
```

**Parameters:** None.

**Returns:** A `BitfabOpenAITracingProcessor` instance that implements the OpenAI Agents SDK `TracingProcessor` interface.

### Usage

```typescript theme={null}
import { Bitfab } from "@bitfab/sdk"
import { addTraceProcessor, Agent } from "@openai/agents"

const bitfab = new Bitfab({ apiKey: process.env.BITFAB_API_KEY })

// Processor captures agent internals; register once.
addTraceProcessor(bitfab.getOpenAiTracingProcessor())

const agent = new Agent({
  name: "my-agent",
  instructions: "You are a helpful assistant.",
  model: "gpt-4o",
})

// wrapRun is a drop-in for run() that records a replayable root.
const handler = bitfab.getOpenAiAgentHandler("my-agent")
const result = await handler.wrapRun(agent, "What's the weather?")
```

### What Gets Captured

The processor implements the `TracingProcessor` interface and captures:

| Event          | What's Captured                     |
| -------------- | ----------------------------------- |
| `onTraceStart` | Trace ID, workflow name, group ID   |
| `onTraceEnd`   | Trace completion with timing        |
| `onSpanStart`  | Span ID, parent ID, span type, name |
| `onSpanEnd`    | Output data, error (if any), timing |

Span types from the OpenAI Agents SDK (agent, function, generation, guardrail, handoff, etc.) are mapped to Bitfab span data automatically.

### Nesting with Core Tracing

If you wrap an agent invocation with `withSpan`, the OpenAI Agents spans nest as children:

```typescript theme={null}
const pipeline = bitfab.getFunction("my-pipeline")

const tracedRun = pipeline.withSpan(
  { name: "RunAgent", type: "agent" },
  async (query: string) => {
    return run(agent, query)
  },
)

await tracedRun("What's the weather?")
// OpenAI Agents spans appear nested under the "RunAgent" span
```

### Error Handling

All processor callbacks are wrapped in try/catch - errors are logged but never thrown. Your agent execution is never affected by tracing failures.

## Python

### Installation

```bash theme={null}
pip install bitfab-py[openai-tracing]
```

The `openai-tracing` extra installs `openai-agents` as a dependency.

### Method Signature

```python theme={null}
bitfab.get_openai_tracing_processor() -> BitfabOpenAITracingProcessor
```

**Parameters:** None.

**Returns:** A `BitfabOpenAITracingProcessor` instance that implements the OpenAI Agents SDK `TracingProcessor` interface.

### Usage

```python theme={null}
import os
from bitfab import Bitfab
from agents import Agent, add_trace_processor

bitfab = Bitfab(api_key=os.environ["BITFAB_API_KEY"])

# Processor captures agent internals; register once.
add_trace_processor(bitfab.get_openai_tracing_processor())

agent = Agent(
    name="my-agent",
    instructions="You are a helpful assistant.",
    model="gpt-4o",
)

# wrap_run is a drop-in for Runner.run that records a replayable root.
handler = bitfab.get_openai_agent_handler("my-agent")
result = await handler.wrap_run(agent, "What's the weather?")
```

### What Gets Captured

Same as TypeScript - the processor implements the `TracingProcessor` interface:

| Event            | What's Captured                     |
| ---------------- | ----------------------------------- |
| `on_trace_start` | Trace ID, workflow name, group ID   |
| `on_trace_end`   | Trace completion with timing        |
| `on_span_start`  | Span ID, parent ID, span type, name |
| `on_span_end`    | Output data, error (if any), timing |

### Nesting with Core Tracing

```python theme={null}
@bitfab.span("my-pipeline", type="agent")
async def run_agent(query: str):
    return await Runner.run(agent, query)

await run_agent("What's the weather?")
# OpenAI Agents spans appear nested under the "my-pipeline" span
```

### Error Handling

All processor callbacks are wrapped in try/except - errors are logged but never raised. Your agent execution is never affected by tracing failures. Traces flush automatically via `atexit` hook.

## Replayable runs with the run wrapper

The tracing processor captures the agent run for observability, but **the processor alone records a root span with no input**. The OpenAI Agents *agent* span is the trace root, and the run input never lands on it (only a response *child* span carries the model-request input). Replay re-runs the trace's root span against its recorded input, so a processor-only trace would replay with nothing to feed it.

**The run wrapper makes a run replayable with no hand-written root.** `getOpenAiAgentHandler(key).wrapRun` (TS) / `get_openai_agent_handler(key).wrap_run` (Python) is a drop-in for the run call: it opens a keyed root span carrying the run input and final output, and the processor's auto-captured spans nest underneath. Keep the processor registered for the internals; swap the run call for the wrapper.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { Bitfab } from "@bitfab/sdk"
  import { addTraceProcessor, Agent } from "@openai/agents"

  const bitfab = new Bitfab({ apiKey: process.env.BITFAB_API_KEY })
  addTraceProcessor(bitfab.getOpenAiTracingProcessor()) // captures internals

  const agent = new Agent({ name: "my-agent", instructions: "..." })
  const handler = bitfab.getOpenAiAgentHandler("my-agent-workflow")

  // Swap run(agent, input) -> handler.wrapRun(agent, input)
  const result = await handler.wrapRun(agent, "What is 21 + 21?")

  // Replay re-runs each recorded input through the same wrapper, by key.
  await bitfab.replay("my-agent-workflow", (input: string) =>
    handler.wrapRun(agent, input),
  )
  ```

  ```python Python theme={null}
  import os
  from bitfab import Bitfab
  from agents import Agent, add_trace_processor

  bitfab = Bitfab(api_key=os.environ["BITFAB_API_KEY"])
  add_trace_processor(bitfab.get_openai_tracing_processor())  # captures internals

  agent = Agent(name="my-agent", instructions="...")
  handler = bitfab.get_openai_agent_handler("my-agent-workflow")

  # Swap Runner.run(agent, input) -> handler.wrap_run(agent, input)
  result = await handler.wrap_run(agent, "What is 21 + 21?")

  # Replay re-runs each recorded input through the same wrapper, by key.
  await bitfab.replay("my-agent-workflow", lambda input: handler.wrap_run(agent, input))
  ```
</CodeGroup>

The wrapper's root carries the serializable run input, so replay re-runs each historical input through your code by key - no `@span`/`withSpan`-decorated function needs to exist. Rebuild any runtime environment inside the callable (agent construction, tools, API keys); use no-op substitutes for side-effectful wiring.

**Alternative: a hand-written root.** When there is meaningful work *around* the run (input prep, orchestration, post-processing), wrap the whole workflow in a `withSpan` / `@span` root that takes the workflow input (the same wrap shown in [Nesting with Core Tracing](#nesting-with-core-tracing)). The processor's spans nest underneath it, and replay re-runs the root against its recorded input. Full details in the [Python SDK](/python-sdk#replay) and [TypeScript SDK](/typescript-sdk#replay) Replay sections.

## Streaming runs

Streamed runs are also traced: the run input lands on the root span and the final output is captured once the stream drains, so first-byte latency is untouched.

<CodeGroup>
  ```typescript TypeScript theme={null}
  // wrapRun is a drop-in for run(agent, input, { stream: true }).
  const handler = bitfab.getOpenAiAgentHandler("my-agent-workflow")

  const stream = await handler.wrapRun(agent, "Find X", { stream: true })
  for await (const event of stream) {
    // handle each streamed event
  }
  // The root's output is recorded once the stream completes.
  ```

  ```python Python theme={null}
  # wrap_run_streamed is an async-generator drop-in for Runner.run_streamed:
  # iterate it to consume the same stream events while the run is traced.
  handler = bitfab.get_openai_agent_handler("my-agent-workflow")

  async for event in handler.wrap_run_streamed(agent, "Find X"):
      ...  # handle each streamed event
  # The root's output (the run's final_output) is recorded once the stream drains.
  ```
</CodeGroup>

In TypeScript, `wrapRun` returns the streamed run result (drained by the caller) and records the root in the background once it completes. In Python, `wrap_run_streamed` is itself an async generator that yields each event from `Runner.run_streamed(...).stream_events()`; the span stays open for the whole iteration so the processor's spans nest beneath the root.

<Note>
  To replay a recorded run as a regression with `bitfab.replay()`, use the non-streaming wrapper (`wrapRun` / `wrap_run`), which replay re-runs directly. `bitfab.replay()` does not drive the Python `wrap_run_streamed` async generator.
</Note>
