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

# OpenAI Agents SDK

> Durable execution, policy, and approvals for OpenAI Agents SDK agents in TypeScript

An OpenAI Agents SDK agent runs on Rebuno unchanged apart from two seams. The
OpenAI client under the model takes `rebunoFetch`, so every model call is
recorded as an `llm_call` step, and tools run through `defineTool`, so every
tool call is recorded as a `tool_call` step. On a re-dispatch the agent runs
from the top and recorded steps replay instead of calling the model or the tool
again.

## Install

```bash theme={"theme":{"light":"min-light","dark":"material-theme-ocean"}}
npm install rebuno @openai/agents openai zod
```

## Model calls

Build the `OpenAI` client yourself with `rebunoFetch`, and hand it to the model:

```ts theme={"theme":{"light":"min-light","dark":"material-theme-ocean"}}
import { OpenAIResponsesModel } from "@openai/agents";
import OpenAI from "openai";
import { rebunoFetch } from "rebuno";

const client = new OpenAI({ fetch: rebunoFetch });
const model = new OpenAIResponsesModel(client, "gpt-5.5");
```

See [LLM calls](/sdk/typescript/llm-calls).

## Tools

Declare the Rebuno side with `defineTool`, and pass it as the `execute` of an
SDK tool:

```ts theme={"theme":{"light":"min-light","dark":"material-theme-ocean"}}
import { tool } from "@openai/agents";
import { defineTool } from "rebuno";
import { z } from "zod";

const sendEmail = tool({
  name: "send_email",
  description: "Email the support summary.",
  parameters: z.object({ body: z.string() }),
  execute: defineTool({
    name: "send_email",
    idempotency: "at_most_once",
    execute: async ({ body }: { body: string }) => mail.send("ops@acme.com", body),
  }),
  errorFunction: null,
});
```

By default a tool's error becomes an error message for the model. A tool held
for approval throws to park the execution, so pass `errorFunction: null` to let
it unwind the run instead. A denied tool still returns the rule's reason to the
model, since a denial doesn't throw.

Mark anything with a side effect, such as sending an email or creating a
ticket, `at_most_once`. See [idempotency](/sdk/typescript/tools#idempotency).

## The agent

The SDK's `Agent` and Rebuno's `Agent` share a name, so import one under an
alias:

```ts theme={"theme":{"light":"min-light","dark":"material-theme-ocean"}}
import { Agent as OpenAIAgent, run } from "@openai/agents";
import { Agent } from "rebuno";

async function process(input: { query: string }) {
  const client = new OpenAI({ fetch: rebunoFetch });
  const specialist = new OpenAIAgent({
    name: "support specialist",
    model: new OpenAIResponsesModel(client, "gpt-5.5"),
    tools: [sendEmail],
  });
  const result = await run(specialist, input.query);
  return { answer: result.finalOutput };
}

const agent = new Agent("support");
await agent.serve({ port: 5000 }, process);
```

## What Rebuno adds

* **Policy.** Every model and tool call is checked against [policy](/policy)
  before it runs. A denied tool returns the rule's reason to the model as the
  tool result, so the agent can take a different path.
* **Approvals.** A tool that requires approval parks the execution. Once it's
  approved, the agent is dispatched again, the earlier steps replay, and the
  approved call runs.
* **Recovery.** If the worker dies partway through, the next dispatch replays
  every completed step and continues from the first one that didn't finish.
  Model calls that already ran are not paid for twice.

## Full example

[`examples/frameworks/typescript/openai_agents_agent.ts`](https://github.com/rebuno/rebuno/blob/main/examples/frameworks/typescript/openai_agents_agent.ts)
is a support agent that investigates a customer issue, creates a ticket, and
emails a summary after approval.
