Cookbook

## Copy, paste, compile.

Copy-paste examples for adding AgentCompile to your agent, in Python and TypeScript. The code is the SDK's own API.

### Quick start

01 Install the SDK

Python

```bash
pip install agentcompile
```

TypeScript

```bash
npm install agentcompile
```

02 Wrap your client

Python

```python
client = agentcompile.wrap(OpenAI())
```

TypeScript

```ts
const client = wrap(new OpenAI());
```

03 Give each conversation its id

Python

```python
with agentcompile.conversation(ticket.id): run_agent()
```

TypeScript

```ts
await conversation(ticket.id, () => runAgent());
```

### Requirements

- Python: 3.9 to 3.13, with the openai and anthropic clients, sync and async
- TypeScript: Node 20 or newer, ESM and CommonJS, with types, for openai and @anthropic-ai/sdk
- License: Apache-2.0

### Wrap an OpenAI agent

Wrap the client your agent already uses, and give each conversation its id. Your agent loop doesn't change.

Python

```python
from openai import OpenAI
import agentcompile

client = agentcompile.wrap(OpenAI())  # reads AGENTCOMPILE_KEY

def handle(ticket):
    with agentcompile.conversation(ticket.id):
        return run_agent(client, ticket)  # your loop, unchanged
```

TypeScript

```ts
import OpenAI from "openai";
import { wrap, conversation } from "agentcompile";

const client = wrap(new OpenAI()); // reads AGENTCOMPILE_KEY

export async function handle(ticket: { id: string }) {
  return conversation(ticket.id, () => runAgent(client, ticket)); // your loop, unchanged
}
```

### Wrap an Anthropic agent

The same for Anthropic's client. Here the conversation id rides on the call itself.

Python

```python
from anthropic import Anthropic
import agentcompile

client = agentcompile.wrap(Anthropic())
reply = client.messages.create(
    model="claude-sonnet-4-5", max_tokens=1024,
    messages=[{"role": "user", "content": "Where is my order?"}],
    conversation_id=ticket.id,
)
```

TypeScript

```ts
import Anthropic from "@anthropic-ai/sdk";
import { wrap } from "agentcompile";

const client = wrap(new Anthropic());
const reply = await client.messages.create({
  model: "claude-sonnet-4-5",
  max_tokens: 1024,
  messages: [{ role: "user", content: "Where is my order?" }],
  conversationId: ticket.id,
} as any);
```

In TypeScript, running the call inside conversation() avoids the cast: the provider's types don't know the extra field.

### Watch before it acts

With mode set to shadow, AgentCompile decides, but your model keeps answering everything.

Python

```python
client = agentcompile.wrap(OpenAI(), mode="shadow")
```

TypeScript

```ts
const client = wrap(new OpenAI(), { mode: "shadow" });
```

Then read the trail: each call's route shows shadow, with the action AgentCompile would have taken.

### Turn on capture

Capture sends each call in the background, so AgentCompile can find the jobs your agent repeats. It never slows a call. Personal data (emails, payment cards, phone numbers and account numbers) is scrubbed on your machine before it's sent.

Python

```python
client = agentcompile.wrap(OpenAI(), capture=True)  # scrubbed before sending
```

TypeScript

```ts
const client = wrap(new OpenAI(), { capture: true }); // scrubbed before sending
```

On a fleet of servers, set the same AGENTCOMPILE_SCRUB_KEY everywhere so tokens match. Scrubbing is in review and ships in the next release.

### OpenAI Agents SDK

The Agents SDK builds its own requests: wrap the client you give it, and set the conversation around the run.

Python

```python
from openai import AsyncOpenAI
from agents import Agent, OpenAIChatCompletionsModel, Runner
import agentcompile

client = agentcompile.wrap(AsyncOpenAI())
agent = Agent(
    name="support",
    instructions=POLICY,
    model=OpenAIChatCompletionsModel(model="gpt-4.1", openai_client=client),
    tools=TOOLS,
)

async def handle(ticket):
    with agentcompile.conversation(ticket.id):
        return await Runner.run(agent, ticket.messages)
```

Python only. In TypeScript the same option works the same way.

### Streaming

Nothing changes: streaming works as before, and a compiled answer streams in the provider's own chunk format.

Python

```python
stream = client.chat.completions.create(model="gpt-4.1", messages=msgs, stream=True,
                                        conversation_id=ticket.id)
for chunk in stream:
    ...
```

Python only. In TypeScript the same option works the same way.

### Tune the timeout

How long to wait for a decision before failing open to your model.

Python

```python
client = agentcompile.wrap(OpenAI(), timeout=1.0)  # seconds; then fail open to your model
```

TypeScript

```ts
const client = wrap(new OpenAI(), { timeoutMs: 1000 });
```

### See what happened

Every call is logged on your machine, one JSON line per call in ~/.agentcompile/trail.jsonl. Follow it from the command line, or get each event in code.

Python

```bash
agentcompile trail -f
```

TypeScript

```ts
const client = wrap(new OpenAI(), {
  onEvent: (e) => console.log(e.route, e.conversation, e.total_ms),
});
```

### Short scripts: flush before exit

Sends captured calls that are still queued. In Python it also runs at exit.

Python

```python
agentcompile.flush()  # sends captured calls still queued (also runs at exit)
```

TypeScript

```ts
import { flush } from "agentcompile";
await flush();
```

### wrap() options

- key / key: Your AgentCompile key. Defaults to AGENTCOMPILE_KEY.
- mode / mode: live by default. shadow: AgentCompile decides, but your model always answers.
- timeout / timeoutMs: How long to wait for a decision before failing open.
- trail / trail: The local log, ~/.agentcompile/trail.jsonl by default. A path, or off.
- on_event / onEvent: Called with each trail event.
- capture / capture: Send each call in the background so AgentCompile can find repeated jobs. Off by default.
- scrub / scrub: With capture: scrub personal data on your machine before sending. On by default.

### What happens on each call

- compiled: A known job: AgentCompile answers, in your provider's own response shape. Your model isn't called.
- forwarded: Anything else: your model is called, unchanged, with your own key.
- fail-open: AgentCompile is slow, unreachable or answering nonsense: your model is called.
- shadow: With mode set to shadow: AgentCompile decides, and your model answers.
- no-conversation: No conversation id: your model is called.

### Good to know

- Do my prompts or model change? No. Anything AgentCompile doesn't answer goes to your model exactly as before, with your own key.
- Does my provider key reach AgentCompile? No, never.
- What if AgentCompile is down? The call goes straight to your model, after at most the timeout.
- What data leaves my machine? Without capture, the request needed to decide, used in memory. With capture, each call, scrubbed on your machine before it's sent.
- Which frameworks? Anything that calls an OpenAI- or Anthropic-style client you can wrap. Verified: plain agent loops and the OpenAI Agents SDK. Frameworks that build their own client need the wrapped client passed in.
- How do I get a key? Keys are issued to beta teams.

Keys are issued to beta teams.
