Contents
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
Install the SDK
pip install agentcompilenpm install agentcompileWrap your client
client = agentcompile.wrap(OpenAI())const client = wrap(new OpenAI());Give each conversation its id
with agentcompile.conversation(ticket.id): run_agent()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
Examples
Wrap an OpenAI agent
Wrap the client your agent already uses, and give each conversation its id. Your agent loop doesn't change.
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
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.
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,
)
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.
client = agentcompile.wrap(OpenAI(), mode="shadow")
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.
client = agentcompile.wrap(OpenAI(), capture=True) # scrubbed before sending
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.
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)
Streaming
Nothing changes: streaming works as before, and a compiled answer streams in the provider's own chunk format.
stream = client.chat.completions.create(model="gpt-4.1", messages=msgs, stream=True,
conversation_id=ticket.id)
for chunk in stream:
...
Tune the timeout
How long to wait for a decision before failing open to your model.
client = agentcompile.wrap(OpenAI(), timeout=1.0) # seconds; then fail open to your model
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.
agentcompile trail -f
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.
agentcompile.flush() # sends captured calls still queued (also runs at exit)
import { flush } from "agentcompile";
await flush();
Reference
wrap() options
key- Your AgentCompile key. Defaults to AGENTCOMPILE_KEY.
mode- live by default. shadow: AgentCompile decides, but your model always answers.
timeout- How long to wait for a decision before failing open.
trail- The local log, ~/.agentcompile/trail.jsonl by default. A path, or off.
on_event- Called with each trail event.
capture- Send each call in the background so AgentCompile can find repeated jobs. Off by default.
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.