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

# OpenAI Agents API (Beta)

> Capture managed OpenAI Agents API turns, tool calls, and token usage in Raindrop.

Use `@raindrop-ai/openai-managed-agents` with the managed
[OpenAI Agents API](https://developers.openai.com/api/docs/guides/agents-api/quickstart),
accessed through `openai.beta.agents.sessions`. It supports hosted and self-hosted
session environments, including Astra World Builder.

For applications that import `Agent`, `run`, or tracing processors from
`@openai/agents`, use the separate [OpenAI Agents SDK integration](/docs/integrations/openai-agents).

## Installation

Requires Node.js 22+ and `openai >=7.15.0 <8`.

```bash theme={null}
pnpm add @raindrop-ai/openai-managed-agents openai
```

Create an OpenAI application key with the
[required Agents API permissions](https://developers.openai.com/api/docs/guides/agents-api/quickstart),
and get your Raindrop write key from your project settings.

## Quick start

```typescript theme={null}
import OpenAI from "openai";
import { createRaindropOpenAIManagedAgents } from "@raindrop-ai/openai-managed-agents";

const raindrop = createRaindropOpenAIManagedAgents({
  writeKey: process.env.RAINDROP_WRITE_KEY,
  userId: "user_123",
  properties: { feature: "world_builder" },
});
const client = raindrop.wrap(new OpenAI());

try {
  const events = await client.beta.agents.sessions.create({
    agent: {
      model: "gpt-6-astra",
      instructions: "Help build a simulation World.",
    },
    environment: { type: "openai_hosted" },
    input: "Describe the files needed for a simulation World.",
    stream: true,
  });
  try {
    for await (const event of events) {
      if (event.type === "agent.session.turn.output_text.delta") {
        process.stdout.write(event.delta);
      }
      if (event.type === "agent.session.idle") break;
    }
  } finally {
    events.controller.abort();
  }
} finally {
  await raindrop.shutdown();
}
```

The wrapper preserves native events, abort controls, request options, and
`withResponse()`. Consume parsed events to capture telemetry; raw
`asResponse()` bodies bypass capture.

## What is captured

Each turn creates one Raindrop event with its prompt, completed final answer,
configured session model, provider, session/turn IDs, and available per-turn
token usage. The session ID is the default conversation ID.

A root turn span contains child spans for command execution, function calls,
MCP calls, web search, and subagent control operations. Function results join
their original calls by call ID. Repeated tool receipts and completed turns
are deduplicated within the client.

The wrapper observes session creation/retrieval, accepted input events, direct
event streams, and the `sessions.stream` helper. Retrieve an existing session
through the wrapper before following its events to capture its model.
Use one wrapper per native client.

## Reconnecting sessions

Use the public typed handler with an unwrapped OpenAI client when a runner
reconnects streams. Keep the Raindrop client alive across reconnects and recover
stored items before completing the recovered turn snapshot:

```typescript theme={null}
import type { Turn } from "openai/resources/beta/agents/sessions/turns";

raindrop.handler.onSession(session);
raindrop.handler.onInput(session.id, input); // after input was accepted
const recoveredTurns: Turn[] = [];
for await (const turn of client.beta.agents.sessions.turns.list(session.id, { order: "asc" })) {
  recoveredTurns.push(turn);
}
for await (const item of client.beta.agents.sessions.items.list(session.id, { order: "asc" })) {
  raindrop.handler.onItem(session.id, item);
}
for (const turn of recoveredTurns) raindrop.handler.onTurn(turn);
for await (const event of stream) {
  raindrop.handler.onEvent(event);
}
await raindrop.flush();
```

Open the stream before recovery so it can buffer live updates. Read and buffer
turn statuses first, recover items next, then pass the buffered turns to the
handler. A turn completed after the status snapshot stays open until its live
terminal event arrives. This keeps its answer and tools ahead of completion.
Process callbacks serially during recovery and stream consumption.

Call `onInputEvents(sessionId, events)` after successful tool-result submission.
At runner shutdown, stop streams/recovery work, call
`forgetSession(sessionId)`, then await `raindrop.shutdown()`.

The simple wrapper closes unfinished captures when the last iterator for a
session stops, including early exit and transport failures. This records a
capture interruption without cancelling the backend turn. Session model and
context remain available across streams; the previous input is cleared.
Metadata retains the latest 10,000 idle sessions plus sessions with active turns
or streams. Call `forgetSession` when
the session is no longer needed. Stored history listing is not intercepted.
Completed-turn deduplication retains the latest 10,000 turns. Supply a stable
`eventId(turnId)` to reuse event identity across process restarts.

## Configuration

| Option                                         | Purpose                                                      |
| ---------------------------------------------- | ------------------------------------------------------------ |
| `writeKey`                                     | Raindrop write key. Blank keys disable cloud shipping.       |
| `endpoint`, `projectId`                        | Shared core ingestion destination and project.               |
| `userId`, `convoId`, `eventName`, `properties` | Default event context.                                       |
| `maxTextFieldChars`                            | Bound captured text through the shared core limits.          |
| `eventId(turnId)`                              | Customize or namespace the Raindrop event ID.                |
| `redact(text)`                                 | Redact captured prompts, answers, tool payloads, and errors. |
| `localWorkshopUrl`                             | Local Workshop destination; `false` disables mirroring.      |
| `appGit`, `debug`                              | Shared core application Git metadata and diagnostics.        |

`raindrop.wrap(client, context)` overrides context for sessions created or
retrieved through that wrapper. Caller-supplied properties and attachments
must be redacted by the caller.

Use `events.patch`, `events.finish`, `events.addAttachments`,
`events.setProperties`, `users.identify`, and `signals.track` to enrich events.
Await `flush()` to ship current buffers. Await `shutdown()` before process exit
to close unfinished captures and ship them.

## Known limitations

The managed service does not expose individual inference calls. Capture is
per turn. Usage comes only from `Turn.usage`, is best effort, and may change.
Missing counters stay absent; cumulative session usage is never used as turn
usage. Revisions after the first terminal receipt are not applied.

Automatic capture excludes reasoning text, intermediate commentary,
agent-to-agent messages, streaming text deltas, and image contents. Completed
final-answer items provide the captured answer.

Span timing reflects observed lifecycle events, including recovery. Native turn
timestamps are recorded as openai.turn.\* attributes. Subagent turns share the
conversation and carry their subagent ID; no cross-turn parent hierarchy is
inferred. Subagent model identity can differ from the session configuration.

<Note>
  Astra World Builder should send telemetry to its existing authenticated
  creator callback route. The worker uses a creator session token; the host
  supplies the Raindrop write key and enforces organization/project scope.
</Note>
