cloudflare-deploy skill (openai/skills)
- Install
- SKILL.md (verbatim)
- Prerequisites
- Authentication (Required Before Deploy)
- Quick Decision Trees
- "I need to run code"
- "I need to store data"
- "I need AI/ML"
- "I need networking/connectivity"
- "I need security"
- "I need media/content"
- "I need infrastructure-as-code"
- Product Index
- Compute & Runtime
- Storage & Data
- AI & Machine Learning
- Networking & Connectivity
- Security
- Media & Content
- Real-Time Communication
- Developer Tools
- Infrastructure as Code
- Other Services
- Troubleshooting
- Escalated Network Access
- Other files in this skill
- references/agents-sdk/README.md (verbatim)
- Core Value
- When to Use
- What Type of Agent?
- Quick Start
- Reading Order
- Package Entry Points
- In This Reference
- See Also
- references/agents-sdk/api.md (verbatim)
- Agent Classes
- AIChatAgent
- Agent (Base Class)
- Lifecycle Hooks
- State, SQL, Scheduling
- RPC Methods (@callable)
- Connections & AI
- MCP Integration
- Task Queue
- Context & Cleanup
- AI Integration
- Client Hooks (React)
- references/agents-sdk/configuration.md (verbatim)
- Wrangler Setup
- Environment Bindings
- Deployment
- Agent Routing
- Email Routing
- AI Gateway (Optional)
- MCP Configuration (Optional)
- references/agents-sdk/gotchas.md (verbatim)
- Common Errors
- "setState() not syncing"
- "Message history grows unbounded (AIChatAgent)"
- "SQL injection vulnerability"
- "WebSocket connection timeout"
- "Schedule limit exceeded"
- "AI Gateway unavailable"
- "@callable method returns undefined"
- "Resumable stream not resuming"
- "MCP connection loss on hibernation"
- "Agent not found"
- Rate Limits & Quotas
- Best Practices
- State Management
- SQL Usage
- Scheduling
- WebSockets
- AI Integration
- Production Deployment
- references/agents-sdk/patterns.md (verbatim)
- AI Chat w/Tools
- Human-in-the-Loop (Client Tools)
- Task Queue & Scheduled Processing
- Manual WebSocket Chat
- Email Processing w/AI
- Real-time Collaboration
- references/ai-gateway/README.md (verbatim)
- When to Use This Reference
- Quick Start
- Pattern 1: Vercel AI SDK (Recommended)
- Pattern 2: OpenAI SDK
- Pattern 3: Workers AI Binding
- Headers Quick Reference
- In This Reference
- Reading Order
- Architecture
- Gateway Types
- Provider Authentication Options
- Related Skills
- Resources
- references/ai-gateway/configuration.md (verbatim)
- Creating a Gateway
- Dashboard
- API
- Wrangler Integration
- Authentication
- Gateway Auth (protects gateway access)
- Provider Auth Options
- API Token Permissions
- Gateway Management API
- Getting IDs
- Python Example
- Best Practices
- references/ai-gateway/dynamic-routing.md (verbatim)
- Usage
- Node Types
- Metadata
- Common Patterns
- Version Management
- Monitoring
- Limitations
- references/ai-gateway/features.md (verbatim)
- Caching
- Rate Limiting
- Guardrails
- Data Loss Prevention (DLP)
- Billing Modes
- Zero Data Retention
- Logging
- Custom Cost Tracking
- Supported Providers (22+)
- Best Practices
- references/ai-gateway/sdk-integration.md (verbatim)
- Vercel AI SDK (Recommended)
- Options
- OpenAI SDK
- Anthropic SDK
- Workers AI Binding
- LangChain / LlamaIndex
- HTTP / cURL
- Headers Reference
- references/ai-search/configuration.md (verbatim)
- Worker Setup
- Data Sources
- R2 Bucket
- Website Crawler
- Path Filtering (R2)
- Indexing
- Service API Token
- Multi-Environment
- Monitoring
What it does. Deploy applications and infrastructure to Cloudflare using Workers, Pages, and related platform services. Use when the user asks to deploy, host, publish, or set up a project on Cloudflare. Part of openai/skills (Skills Catalog for Codex) (openai/skills).
| Upstream | openai/skills |
| Skill file | skills/.curated/cloudflare-deploy/SKILL.md |
| License | Apache-2.0 (skill folder LICENSE.txt) |
| Author | OpenAI |
| Fetched | 2026-09-10 |
Install
- Codex:
$skill-installerinstalls from this catalog ($cloudflare-deployinvokes it); other agents:npx skills add openai/skills --skill cloudflare-deploy. - Raw file:
curl -sL https://raw.githubusercontent.com/openai/skills/HEAD/skills/.curated/cloudflare-deploy/SKILL.md
SKILL.md (verbatim)
name: cloudflare-deploy
description: Deploy applications and infrastructure to Cloudflare using Workers, Pages, and related platform services. Use when the user asks to deploy, host, publish, or set up a project on Cloudflare.
Cloudflare Deploy
Consolidated skill for building on the Cloudflare platform. Use decision trees below to find the right product, then load detailed references.
Prerequisites
- When sandboxing blocks the deployment network calls, rerun with
sandbox_permissions=require_escalated. - The deployment might take a few minutes. Use appropriate timeout values.
Authentication (Required Before Deploy)
Verify auth before wrangler deploy, wrangler pages deploy, or npm run deploy:
npx wrangler whoami # Shows account if authenticated
Not authenticated? → references/wrangler/auth.md
- Interactive/local:
wrangler login(one-time OAuth) - CI/CD: Set
CLOUDFLARE_API_TOKENenv var
Quick Decision Trees
"I need to run code"
Need to run code?
├─ Serverless functions at the edge → workers/
├─ Full-stack web app with Git deploys → pages/
├─ Stateful coordination/real-time → durable-objects/
├─ Long-running multi-step jobs → workflows/
├─ Run containers → containers/
├─ Multi-tenant (customers deploy code) → workers-for-platforms/
├─ Scheduled tasks (cron) → cron-triggers/
├─ Lightweight edge logic (modify HTTP) → snippets/
├─ Process Worker execution events (logs/observability) → tail-workers/
└─ Optimize latency to backend infrastructure → smart-placement/
"I need to store data"
Need storage?
├─ Key-value (config, sessions, cache) → kv/
├─ Relational SQL → d1/ (SQLite) or hyperdrive/ (existing Postgres/MySQL)
├─ Object/file storage (S3-compatible) → r2/
├─ Message queue (async processing) → queues/
├─ Vector embeddings (AI/semantic search) → vectorize/
├─ Strongly-consistent per-entity state → durable-objects/ (DO storage)
├─ Secrets management → secrets-store/
├─ Streaming ETL to R2 → pipelines/
└─ Persistent cache (long-term retention) → cache-reserve/
"I need AI/ML"
Need AI?
├─ Run inference (LLMs, embeddings, images) → workers-ai/
├─ Vector database for RAG/search → vectorize/
├─ Build stateful AI agents → agents-sdk/
├─ Gateway for any AI provider (caching, routing) → ai-gateway/
└─ AI-powered search widget → ai-search/
"I need networking/connectivity"
Need networking?
├─ Expose local service to internet → tunnel/
├─ TCP/UDP proxy (non-HTTP) → spectrum/
├─ WebRTC TURN server → turn/
├─ Private network connectivity → network-interconnect/
├─ Optimize routing → argo-smart-routing/
├─ Optimize latency to backend (not user) → smart-placement/
└─ Real-time video/audio → realtimekit/ or realtime-sfu/
"I need security"
Need security?
├─ Web Application Firewall → waf/
├─ DDoS protection → ddos/
├─ Bot detection/management → bot-management/
├─ API protection → api-shield/
├─ CAPTCHA alternative → turnstile/
└─ Credential leak detection → waf/ (managed ruleset)
"I need media/content"
Need media?
├─ Image optimization/transformation → images/
├─ Video streaming/encoding → stream/
├─ Browser automation/screenshots → browser-rendering/
└─ Third-party script management → zaraz/
"I need infrastructure-as-code"
Need IaC? → pulumi/ (Pulumi), terraform/ (Terraform), or api/ (REST API)
Product Index
Compute & Runtime
| Product | Reference |
|---|---|
| Workers | references/workers/ |
| Pages | references/pages/ |
| Pages Functions | references/pages-functions/ |
| Durable Objects | references/durable-objects/ |
| Workflows | references/workflows/ |
| Containers | references/containers/ |
| Workers for Platforms | references/workers-for-platforms/ |
| Cron Triggers | references/cron-triggers/ |
| Tail Workers | references/tail-workers/ |
| Snippets | references/snippets/ |
| Smart Placement | references/smart-placement/ |
Storage & Data
| Product | Reference |
|---|---|
| KV | references/kv/ |
| D1 | references/d1/ |
| R2 | references/r2/ |
| Queues | references/queues/ |
| Hyperdrive | references/hyperdrive/ |
| DO Storage | references/do-storage/ |
| Secrets Store | references/secrets-store/ |
| Pipelines | references/pipelines/ |
| R2 Data Catalog | references/r2-data-catalog/ |
| R2 SQL | references/r2-sql/ |
AI & Machine Learning
| Product | Reference |
|---|---|
| Workers AI | references/workers-ai/ |
| Vectorize | references/vectorize/ |
| Agents SDK | references/agents-sdk/ |
| AI Gateway | references/ai-gateway/ |
| AI Search | references/ai-search/ |
Networking & Connectivity
| Product | Reference |
|---|---|
| Tunnel | references/tunnel/ |
| Spectrum | references/spectrum/ |
| TURN | references/turn/ |
| Network Interconnect | references/network-interconnect/ |
| Argo Smart Routing | references/argo-smart-routing/ |
| Workers VPC | references/workers-vpc/ |
Security
| Product | Reference |
|---|---|
| WAF | references/waf/ |
| DDoS Protection | references/ddos/ |
| Bot Management | references/bot-management/ |
| API Shield | references/api-shield/ |
| Turnstile | references/turnstile/ |
Media & Content
| Product | Reference |
|---|---|
| Images | references/images/ |
| Stream | references/stream/ |
| Browser Rendering | references/browser-rendering/ |
| Zaraz | references/zaraz/ |
Real-Time Communication
| Product | Reference |
|---|---|
| RealtimeKit | references/realtimekit/ |
| Realtime SFU | references/realtime-sfu/ |
Developer Tools
| Product | Reference |
|---|---|
| Wrangler | references/wrangler/ |
| Miniflare | references/miniflare/ |
| C3 | references/c3/ |
| Observability | references/observability/ |
| Analytics Engine | references/analytics-engine/ |
| Web Analytics | references/web-analytics/ |
| Sandbox | references/sandbox/ |
| Workerd | references/workerd/ |
| Workers Playground | references/workers-playground/ |
Infrastructure as Code
| Product | Reference |
|---|---|
| Pulumi | references/pulumi/ |
| Terraform | references/terraform/ |
| API | references/api/ |
Other Services
| Product | Reference |
|---|---|
| Email Routing | references/email-routing/ |
| Email Workers | references/email-workers/ |
| Static Assets | references/static-assets/ |
| Bindings | references/bindings/ |
| Cache Reserve | references/cache-reserve/ |
Troubleshooting
Escalated Network Access
If deployment fails due to network issues (timeouts, DNS errors, connection resets), rerun the deploy with escalated permissions (use sandbox_permissions=require_escalated). The deploy requires escalated network access when sandbox networking blocks outbound requests.
Example guidance to the user:
The deploy needs escalated network access to deploy to Cloudflare. I can rerun the command with escalated permissions—want me to proceed?
Other files in this skill
- LICENSE.txt
- agents/openai.yaml
- assets/cloudflare-small.svg
- assets/cloudflare.png
- references/agents-sdk/README.md
- references/agents-sdk/api.md
- references/agents-sdk/configuration.md
- references/agents-sdk/gotchas.md
- references/agents-sdk/patterns.md
- references/ai-gateway/README.md
- references/ai-gateway/configuration.md
- references/ai-gateway/dynamic-routing.md
- references/ai-gateway/features.md
- references/ai-gateway/sdk-integration.md
- references/ai-gateway/troubleshooting.md
- references/ai-search/README.md
- references/ai-search/api.md
- references/ai-search/configuration.md
- references/ai-search/gotchas.md
- references/ai-search/patterns.md
- references/analytics-engine/README.md
- references/analytics-engine/api.md
- references/analytics-engine/configuration.md
- references/analytics-engine/gotchas.md
- references/analytics-engine/patterns.md
- references/api-shield/README.md
- references/api-shield/api.md
- references/api-shield/configuration.md
- references/api-shield/gotchas.md
- references/api-shield/patterns.md
- references/api/README.md
- references/api/api.md
- references/api/configuration.md
- references/api/gotchas.md
- references/api/patterns.md
- references/argo-smart-routing/README.md
- references/argo-smart-routing/api.md
- references/argo-smart-routing/configuration.md
- references/argo-smart-routing/gotchas.md
- references/argo-smart-routing/patterns.md
- references/bindings/README.md
- references/bindings/api.md
- references/bindings/configuration.md
- references/bindings/gotchas.md
- references/bindings/patterns.md
- references/bot-management/README.md
- references/bot-management/api.md
- references/bot-management/configuration.md
- references/bot-management/gotchas.md
- references/bot-management/patterns.md
- references/browser-rendering/README.md
- references/browser-rendering/api.md
- references/browser-rendering/configuration.md
- references/browser-rendering/gotchas.md
- references/browser-rendering/patterns.md
- references/c3/README.md
- references/c3/api.md
- references/c3/configuration.md
- references/c3/gotchas.md
- references/c3/patterns.md
- ... and 251 more (see the folder)
references/agents-sdk/README.md (verbatim)
Cloudflare Agents SDK
Cloudflare Agents SDK enables building AI-powered agents on Durable Objects with state, WebSockets, SQL, scheduling, and AI integration.
Core Value
Build stateful, globally distributed AI agents with persistent memory, real-time connections, scheduled tasks, and async workflows.
When to Use
- Persistent state + memory required
- Real-time WebSocket connections
- Long-running workflows (minutes/hours)
- Chat interfaces with AI models
- Scheduled/recurring tasks with state
- DB queries with agent state
What Type of Agent?
| Use Case | Class | Key Features |
|---|---|---|
| AI chat interface | AIChatAgent |
Auto-streaming, tools, message history, resumable |
| MCP tool provider | Agent + MCP |
Expose tools to AI systems |
| Custom logic/routing | Agent |
Full control, WebSockets, email, SQL |
| Real-time collaboration | Agent |
WebSocket state, broadcasts |
| Email processing | Agent |
onEmail() handler |
Quick Start
AI Chat Agent:
import { AIChatAgent } from "agents";
import { openai } from "@ai-sdk/openai";
export class ChatAgent extends AIChatAgent<Env> {
async onChatMessage(onFinish) {
return this.streamText({
model: openai("gpt-4"),
messages: this.messages,
onFinish,
});
}
}
Base Agent:
import { Agent } from "agents";
export class MyAgent extends Agent<Env> {
onStart() {
this.sql`CREATE TABLE IF NOT EXISTS users (id TEXT PRIMARY KEY)`;
}
async onRequest(request: Request) {
return Response.json({ state: this.state });
}
}
Reading Order
| Task | Files to Read |
|---|---|
| Quick start | README only |
| Build chat agent | README → api.md (AIChatAgent) → patterns.md |
| Setup project | README → configuration.md |
| Add React frontend | README → api.md (Client Hooks) → patterns.md |
| Build MCP server | api.md (MCP) → patterns.md |
| Background tasks | api.md (Scheduling, Task Queue) → patterns.md |
| Debug issues | gotchas.md |
Package Entry Points
| Import | Purpose |
|---|---|
agents |
Server-side Agent classes, lifecycle |
agents/react |
useAgent() hook for WebSocket connections |
agents/ai-react |
useAgentChat() hook for AI chat UIs |
In This Reference
- configuration.md - SDK setup, wrangler config, routing
- api.md - Agent classes, lifecycle, client hooks
- patterns.md - Common workflows, best practices
- gotchas.md - Common issues, limits
See Also
- durable-objects - Agent infrastructure
- d1 - External database integration
- workers-ai - AI model integration
- vectorize - Vector search for RAG patterns
references/agents-sdk/api.md (verbatim)
API Reference
Agent Classes
AIChatAgent
For AI chat with auto-streaming, message history, tools, resumable streaming.
import { AIChatAgent } from "agents";
import { openai } from "@ai-sdk/openai";
export class ChatAgent extends AIChatAgent<Env> {
async onChatMessage(onFinish) {
return this.streamText({
model: openai("gpt-4"),
messages: this.messages, // Auto-managed message history
tools: {
getWeather: {
description: "Get weather",
parameters: z.object({ city: z.string() }),
execute: async ({ city }) => `Sunny, 72°F in ${city}`
}
},
onFinish, // Persist response to this.messages
});
}
}
Agent (Base Class)
Full control for custom logic, WebSockets, email, and SQL.
import { Agent } from "agents";
export class MyAgent extends Agent<Env, State> {
// Lifecycle methods below
}
Type params: Agent<Env, State, ConnState> - Env bindings, agent state, connection state
Lifecycle Hooks
onStart() { // Init/restart
this.sql`CREATE TABLE IF NOT EXISTS users (id TEXT, name TEXT)`;
}
async onRequest(req: Request) { // HTTP
const {pathname} = new URL(req.url);
if (pathname === "/users") return Response.json(this.sql<{id,name}>`SELECT * FROM users`);
return new Response("Not found", {status: 404});
}
async onConnect(conn: Connection<ConnState>, ctx: ConnectionContext) { // WebSocket
conn.accept();
conn.setState({userId: ctx.request.headers.get("X-User-ID")});
conn.send(JSON.stringify({type: "connected", state: this.state}));
}
async onMessage(conn: Connection<ConnState>, msg: WSMessage) { // WS messages
const m = JSON.parse(msg as string);
this.setState({messages: [...this.state.messages, m]});
this.connections.forEach(c => c.send(JSON.stringify(m)));
}
async onEmail(email: AgentEmail) { // Email routing
this.sql`INSERT INTO emails (from_addr,subject,body) VALUES (${email.from},${email.headers.get("subject")},${await email.text()})`;
}
State, SQL, Scheduling
// State
this.setState({count: 42}); // Auto-syncs
this.setState({...this.state, count: this.state.count + 1});
// SQL (parameterized queries prevent injection)
this.sql`CREATE TABLE IF NOT EXISTS users (id TEXT PRIMARY KEY, name TEXT)`;
this.sql`INSERT INTO users (id,name) VALUES (${userId},${name})`;
const users = this.sql<{id,name}>`SELECT * FROM users WHERE id = ${userId}`;
// Scheduling
await this.schedule(new Date("2026-12-25"), "sendGreeting", {msg:"Hi"}); // Date
await this.schedule(60, "checkStatus", {}); // Delay (sec)
await this.schedule("0 0 * * *", "dailyCleanup", {}); // Cron
await this.cancelSchedule(scheduleId);
RPC Methods (@callable)
import { Agent, callable } from "agents";
export class MyAgent extends Agent<Env> {
@callable()
async processTask(input: {text: string}): Promise<{result: string}> {
return { result: await this.env.AI.run("@cf/meta/llama-3.1-8b-instruct", {prompt: input.text}) };
}
}
// Client: const result = await agent.processTask({ text: "Hello" });
// Must return JSON-serializable values
Connections & AI
// Connections (type: Agent<Env, State, ConnState>)
this.connections.forEach(c => c.send(JSON.stringify(msg))); // Broadcast
conn.setState({userId:"123"}); conn.close(1000, "Goodbye");
// Workers AI
const r = await this.env.AI.run("@cf/meta/llama-3.1-8b-instruct", {prompt});
// Manual streaming (prefer AIChatAgent)
const stream = await client.chat.completions.create({model: "gpt-4", messages, stream: true});
for await (const chunk of stream) conn.send(JSON.stringify({chunk: chunk.choices[0].delta.content}));
Type-safe state: Agent<Env, State, ConnState> - third param types conn.state
MCP Integration
Model Context Protocol for exposing tools:
// Register & use MCP server
await this.mcp.registerServer("github", {
url: env.MCP_SERVER_URL,
auth: { type: "oauth", clientId: env.GITHUB_CLIENT_ID, clientSecret: env.GITHUB_CLIENT_SECRET }
});
const tools = await this.mcp.getAITools(["github"]);
return this.streamText({ model: openai("gpt-4"), messages: this.messages, tools, onFinish });
Task Queue
await this.queue("processVideo", { videoId: "abc123" }); // Add task
const tasks = await this.dequeue(10); // Process up to 10
Context & Cleanup
const agent = getCurrentAgent<MyAgent>(); // Get current instance
async destroy() { /* cleanup before agent destroyed */ }
AI Integration
// Workers AI
const r = await this.env.AI.run("@cf/meta/llama-3.1-8b-instruct", {prompt});
// Manual streaming (prefer AIChatAgent for auto-streaming)
const stream = await client.chat.completions.create({model: "gpt-4", messages, stream: true});
for await (const chunk of stream) {
if (chunk.choices[0]?.delta?.content) conn.send(JSON.stringify({chunk: chunk.choices[0].delta.content}));
}
Client Hooks (React)
// useAgent() - WebSocket connection + RPC
import { useAgent } from "agents/react";
const agent = useAgent({ agent: "MyAgent", name: "user-123" }); // name for idFromName
const result = await agent.processTask({ text: "Hello" }); // Call @callable methods
// agent.readyState: 0=CONNECTING, 1=OPEN, 2=CLOSING, 3=CLOSED
// useAgentChat() - AI chat UI
import { useAgentChat } from "agents/ai-react";
const agent = useAgent({ agent: "ChatAgent" });
const { messages, input, handleInputChange, handleSubmit, isLoading, stop, clearHistory } =
useAgentChat({
agent,
maxSteps: 5, // Max tool iterations
resume: true, // Auto-resume on disconnect
onToolCall: async (toolCall) => {
// Client tools (human-in-the-loop)
if (toolCall.toolName === "confirm") return { ok: window.confirm("Proceed?") };
}
});
// status: "ready" | "submitted" | "streaming" | "error"
references/agents-sdk/configuration.md (verbatim)
Configuration
Wrangler Setup
{
"name": "my-agents-app",
"durable_objects": {
"bindings": [
{"name": "MyAgent", "class_name": "MyAgent"}
]
},
"migrations": [
{"tag": "v1", "new_sqlite_classes": ["MyAgent"]}
],
"ai": {
"binding": "AI"
}
}
Environment Bindings
Type-safe pattern:
interface Env {
AI?: Ai; // Workers AI
MyAgent?: DurableObjectNamespace<MyAgent>;
ChatAgent?: DurableObjectNamespace<ChatAgent>;
DB?: D1Database; // D1 database
KV?: KVNamespace; // KV storage
R2?: R2Bucket; // R2 bucket
OPENAI_API_KEY?: string; // Secrets
GITHUB_CLIENT_ID?: string; // MCP OAuth credentials
GITHUB_CLIENT_SECRET?: string;
QUEUE?: Queue; // Queues
}
Best practice: Define all DO bindings in Env interface for type safety.
Deployment
# Local dev
npx wrangler dev
# Deploy production
npx wrangler deploy
# Set secrets
npx wrangler secret put OPENAI_API_KEY
Agent Routing
Recommended: Use route helpers
import { routeAgent } from "agents";
export default {
fetch(request: Request, env: Env) {
return routeAgent(request, env);
}
}
Helper routes requests to agents automatically based on URL patterns.
Manual routing (advanced):
export default {
async fetch(request: Request, env: Env) {
const url = new URL(request.url);
// Named ID (deterministic)
const id = env.MyAgent.idFromName("user-123");
// Random ID (from URL param)
// const id = env.MyAgent.idFromString(url.searchParams.get("id"));
const stub = env.MyAgent.get(id);
return stub.fetch(request);
}
}
Multi-agent setup:
import { routeAgent } from "agents";
export default {
fetch(request: Request, env: Env) {
const url = new URL(request.url);
// Route by path
if (url.pathname.startsWith("/chat")) {
return routeAgent(request, env, "ChatAgent");
}
if (url.pathname.startsWith("/task")) {
return routeAgent(request, env, "TaskAgent");
}
return new Response("Not found", { status: 404 });
}
}
Email Routing
Code setup:
import { routeAgentEmail } from "agents";
export default {
fetch: (req: Request, env: Env) => routeAgent(req, env),
email: (message: ForwardableEmailMessage, env: Env) => {
return routeAgentEmail(message, env);
}
}
Dashboard setup:
Configure email routing in Cloudflare dashboard:
Destination: Workers with Durable Objects
Worker: my-agents-app
Then handle in agent:
export class EmailAgent extends Agent<Env> {
async onEmail(email: AgentEmail) {
const text = await email.text();
// Process email
}
}
AI Gateway (Optional)
// Enable caching/routing through AI Gateway
const response = await this.env.AI.run(
"@cf/meta/llama-3.1-8b-instruct",
{ prompt },
{
gateway: {
id: "my-gateway-id",
skipCache: false,
cacheTtl: 3600
}
}
);
MCP Configuration (Optional)
For exposing tools via Model Context Protocol:
// wrangler.jsonc - Add MCP OAuth secrets
{
"vars": {
"MCP_SERVER_URL": "https://mcp.example.com"
}
}
// Set secrets via CLI
// npx wrangler secret put GITHUB_CLIENT_ID
// npx wrangler secret put GITHUB_CLIENT_SECRET
Then register in agent code (see api.md MCP section).
references/agents-sdk/gotchas.md (verbatim)
Gotchas & Best Practices
Common Errors
"setState() not syncing"
Cause: Mutating state directly or not calling setState() after modifications
Solution: Always use setState() with immutable updates:
// ❌ this.state.count++
// ✅ this.setState({...this.state, count: this.state.count + 1})
"Message history grows unbounded (AIChatAgent)"
Cause: this.messages in AIChatAgent accumulates all messages indefinitely
Solution: Manually trim old messages periodically:
export class ChatAgent extends AIChatAgent<Env> {
async onChatMessage(onFinish) {
// Keep only last 50 messages
if (this.messages.length > 50) {
this.messages = this.messages.slice(-50);
}
return this.streamText({ model: openai("gpt-4"), messages: this.messages, onFinish });
}
}
"SQL injection vulnerability"
Cause: Direct string interpolation in SQL queries Solution: Use parameterized queries:
// ❌ this.sql`...WHERE id = '${userId}'`
// ✅ this.sql`...WHERE id = ${userId}`
"WebSocket connection timeout"
Cause: Not calling conn.accept() in onConnect
Solution: Always accept connections:
async onConnect(conn: Connection, ctx: ConnectionContext) { conn.accept(); conn.setState({userId: "123"}); }
"Schedule limit exceeded"
Cause: More than 1000 scheduled tasks per agent Solution: Clean up old schedules and limit creation rate:
async checkSchedules() { if ((await this.getSchedules()).length > 800) console.warn("Near limit!"); }
"AI Gateway unavailable"
Cause: AI service timeout or quota exceeded
Solution: Add error handling and fallbacks:
try {
return await this.env.AI.run(model, {prompt});
} catch (e) {
console.error("AI error:", e);
return {error: "Unavailable"};
}
"@callable method returns undefined"
Cause: Method doesn't return JSON-serializable value, or has non-serializable types
Solution: Ensure return values are plain objects/arrays/primitives:
// ❌ Returns class instance
@callable()
async getData() { return new Date(); }
// ✅ Returns serializable object
@callable()
async getData() { return { timestamp: Date.now() }; }
"Resumable stream not resuming"
Cause: Stream ID must be deterministic for resumption to work
Solution: Use AIChatAgent (automatic) or ensure consistent stream IDs:
// AIChatAgent handles this automatically
export class ChatAgent extends AIChatAgent<Env> {
// Resumption works out of the box
}
"MCP connection loss on hibernation"
Cause: MCP server connections don't survive hibernation
Solution: Re-register servers in onStart() or check connection status:
onStart() {
// Re-register MCP servers after hibernation
await this.mcp.registerServer("github", { url: env.MCP_URL, auth: {...} });
}
"Agent not found"
Cause: Durable Object binding missing or incorrect class name
Solution: Verify DO binding in wrangler.jsonc and class name matches
Rate Limits & Quotas
| Resource/Limit | Value | Notes |
|---|---|---|
| CPU per request | 30s (std), 300s (max) | Set in wrangler.jsonc |
| Memory per instance | 128MB | Shared with WebSockets |
| Storage per agent | 10GB | SQLite storage |
| Scheduled tasks | 1000 per agent | Monitor with getSchedules() |
| WebSocket connections | Unlimited | Within memory limits |
| SQL columns | 100 | Per table |
| SQL row size | 2MB | Key + value |
| WebSocket message | 32MiB | Max size |
| DO requests/sec | ~1000 | Per unique DO instance; rate limit if needed |
| AI Gateway (Workers AI) | Model-specific | Check dashboard for limits |
| MCP requests | Depends on server | Implement retry/backoff |
Best Practices
State Management
- Use immutable updates:
setState({...this.state, key: newValue}) - Trim unbounded arrays (messages, logs) periodically
- Store large data in SQL, not state
SQL Usage
- Create tables in
onStart(), notonRequest() - Use parameterized queries:
sql`WHERE id = ${id}`(NOTsql`WHERE id = '${id}'`) - Index frequently queried columns
Scheduling
- Monitor schedule count:
await this.getSchedules() - Cancel completed tasks to stay under 1000 limit
- Use cron strings for recurring tasks
WebSockets
- Always call
conn.accept()inonConnect() - Handle client disconnects gracefully
- Broadcast to
this.connectionsefficiently
AI Integration
- Use
AIChatAgentfor chat interfaces (auto-streaming, resumption) - Trim message history to avoid token limits
- Handle AI errors with try/catch and fallbacks
Production Deployment
- Rate limiting: Implement request throttling for high-traffic agents (>1000 req/s)
- Monitoring: Log critical errors, track schedule count, monitor storage usage
- Graceful degradation: Handle AI service outages with fallbacks
- Message trimming: Enforce max history length (e.g., 100 messages) in AIChatAgent
- MCP reliability: Re-register servers on hibernation, implement retry logic
references/agents-sdk/patterns.md (verbatim)
Patterns & Use Cases
AI Chat w/Tools
Server (AIChatAgent):
import { AIChatAgent } from "agents";
import { openai } from "@ai-sdk/openai";
import { tool } from "ai";
import { z } from "zod";
export class ChatAgent extends AIChatAgent<Env> {
async onChatMessage(onFinish) {
return this.streamText({
model: openai("gpt-4"),
messages: this.messages, // Auto-managed
tools: {
getWeather: tool({
description: "Get current weather",
parameters: z.object({ city: z.string() }),
execute: async ({ city }) => `Weather in ${city}: Sunny, 72°F`
}),
searchDocs: tool({
description: "Search documentation",
parameters: z.object({ query: z.string() }),
execute: async ({ query }) => JSON.stringify(
this.sql<{title, content}>`SELECT title, content FROM docs WHERE content LIKE ${'%' + query + '%'}`
)
})
},
onFinish,
});
}
}
Client (React):
import { useAgent } from "agents/react";
import { useAgentChat } from "agents/ai-react";
function ChatUI() {
const agent = useAgent({ agent: "ChatAgent" });
const { messages, input, handleInputChange, handleSubmit, isLoading } = useAgentChat({ agent });
return (
<div>
{messages.map(m => <div key={m.id}>{m.role}: {m.content}</div>)}
<form onSubmit={handleSubmit}>
<input value={input} onChange={handleInputChange} disabled={isLoading} />
<button disabled={isLoading}>Send</button>
</form>
</div>
);
}
Human-in-the-Loop (Client Tools)
Server defines tool, client executes:
// Server
export class ChatAgent extends AIChatAgent<Env> {
async onChatMessage(onFinish) {
return this.streamText({
model: openai("gpt-4"),
messages: this.messages,
tools: {
confirmAction: tool({
description: "Ask user to confirm",
parameters: z.object({ action: z.string() }),
execute: "client", // Client-side execution
})
},
onFinish,
});
}
}
// Client
const { messages } = useAgentChat({
agent,
onToolCall: async (toolCall) => {
if (toolCall.toolName === "confirmAction") {
return { confirmed: window.confirm(`Confirm: ${toolCall.args.action}?`) };
}
}
});
Task Queue & Scheduled Processing
export class TaskAgent extends Agent<Env> {
onStart() {
this.schedule("*/5 * * * *", "processQueue", {}); // Every 5 min
this.schedule("0 0 * * *", "dailyCleanup", {}); // Daily
}
async onRequest(req: Request) {
await this.queue("processVideo", { videoId: (await req.json()).videoId });
return Response.json({ queued: true });
}
async processQueue() {
const tasks = await this.dequeue(10);
for (const task of tasks) {
if (task.name === "processVideo") await this.processVideo(task.data.videoId);
}
}
async dailyCleanup() {
this.sql`DELETE FROM logs WHERE created_at < ${Date.now() - 86400000}`;
}
}
Manual WebSocket Chat
Custom protocols (non-AI):
export class ChatAgent extends Agent<Env> {
async onConnect(conn: Connection, ctx: ConnectionContext) {
conn.accept();
conn.setState({userId: ctx.request.headers.get("X-User-ID") || "anon"});
conn.send(JSON.stringify({type: "history", messages: this.state.messages}));
}
async onMessage(conn: Connection, msg: WSMessage) {
const newMsg = {userId: conn.state.userId, text: JSON.parse(msg as string).text, timestamp: Date.now()};
this.setState({messages: [...this.state.messages, newMsg]});
this.connections.forEach(c => c.send(JSON.stringify(newMsg)));
}
}
Email Processing w/AI
export class EmailAgent extends Agent<Env> {
async onEmail(email: AgentEmail) {
const [text, from, subject] = [await email.text(), email.from, email.headers.get("subject") || ""];
this.sql`INSERT INTO emails (from_addr, subject, body) VALUES (${from}, ${subject}, ${text})`;
const { text: summary } = await generateText({
model: openai("gpt-4o-mini"), prompt: `Summarize: ${subject}\n\n${text}`
});
this.connections.forEach(c => c.send(JSON.stringify({type: "new_email", from, summary})));
if (summary.includes("urgent")) await this.schedule(0, "sendAutoReply", { to: from });
}
}
Real-time Collaboration
export class GameAgent extends Agent<Env> {
initialState = { players: [], gameStarted: false };
async onConnect(conn: Connection, ctx: ConnectionContext) {
conn.accept();
const playerId = ctx.request.headers.get("X-Player-ID") || crypto.randomUUID();
conn.setState({ playerId });
const newPlayer = { id: playerId, score: 0 };
this.setState({...this.state, players: [...this.state.players, newPlayer]});
this.connections.forEach(c => c.send(JSON.stringify({type: "player_joined", player: newPlayer})));
}
async onMessage(conn: Connection, msg: WSMessage) {
const m = JSON.parse(msg as string);
if (m.type === "move") {
this.setState({
...this.state,
players: this.state.players.map(p => p.id === conn.state.playerId ? {...p, score: p.score + m.points} : p)
});
this.connections.forEach(c => c.send(JSON.stringify({type: "player_moved", playerId: conn.state.playerId})));
}
if (m.type === "start" && this.state.players.length >= 2) {
this.setState({...this.state, gameStarted: true});
this.connections.forEach(c => c.send(JSON.stringify({type: "game_started"})));
}
}
}
references/ai-gateway/README.md (verbatim)
2 placeholder credentials shortened to pass the site's secret filter.
Cloudflare AI Gateway
Expert guidance for implementing Cloudflare AI Gateway - a universal gateway for AI model providers with analytics, caching, rate limiting, and routing capabilities.
When to Use This Reference
- Setting up AI Gateway for any AI provider (OpenAI, Anthropic, Workers AI, etc.)
- Implementing caching, rate limiting, or request retry/fallback
- Configuring dynamic routing with A/B testing or model fallbacks
- Managing provider API keys securely with BYOK
- Adding security features (guardrails, DLP)
- Setting up observability with logging and custom metadata
- Debugging AI Gateway requests or optimizing configurations
Quick Start
What's your setup?
- Using Vercel AI SDK → Pattern 1 (recommended) - see sdk-integration.md
- Using OpenAI SDK → Pattern 2 - see sdk-integration.md
- Cloudflare Worker + Workers AI → Pattern 3 - see sdk-integration.md
- Direct HTTP (any language) → Pattern 4 - see configuration.md
- Framework (LangChain, etc.) → See sdk-integration.md
Pattern 1: Vercel AI SDK (Recommended)
Most modern pattern using official ai-gateway-provider package with automatic fallbacks.
import { createAiGateway } from 'ai-gateway-provider';
import { createOpenAI } from '@ai-sdk/openai';
import { generateText } from 'ai';
const gateway = createAiGateway({
accountId: process.env.CF_ACCOUNT_ID,
gateway: process.env.CF_GATEWAY_ID,
});
const openai = createOpenAI({
apiKey: YOUR_KEY
});
// Single model
const { text } = await generateText({
model: gateway(openai('gpt-4o')),
prompt: 'Hello'
});
// Automatic fallback array
const { text } = await generateText({
model: gateway([
openai('gpt-4o'), // Try first
anthropic('claude-sonnet-4-5'), // Fallback
]),
prompt: 'Hello'
});
Install: npm install ai-gateway-provider ai @ai-sdk/openai @ai-sdk/anthropic
Pattern 2: OpenAI SDK
Drop-in replacement for OpenAI API with multi-provider support.
import OpenAI from 'openai';
const client = new OpenAI({
apiKey: YOUR_KEY
baseURL: `https://gateway.ai.cloudflare.com/v1/${accountId}/${gatewayId}/compat`,
defaultHeaders: {
'cf-aig-authorization': `Bearer ${cfToken}` // For authenticated gateways
}
});
// Switch providers by changing model format: {provider}/{model}
const response = await client.chat.completions.create({
model: 'openai/gpt-4o', // or 'anthropic/claude-sonnet-4-5'
messages: [{ role: 'user', content: 'Hello!' }]
});
Pattern 3: Workers AI Binding
For Cloudflare Workers using Workers AI.
export default {
async fetch(request, env, ctx) {
const response = await env.AI.run(
'@cf/meta/llama-3-8b-instruct',
{ messages: [{ role: 'user', content: 'Hello!' }] },
{
gateway: {
id: 'my-gateway',
metadata: { userId: '123', team: 'engineering' }
}
}
);
return Response.json(response);
}
};
Headers Quick Reference
| Header | Purpose | Example | Notes |
|---|---|---|---|
cf-aig-authorization |
Gateway auth | Bearer {token} |
Required for authenticated gateways |
cf-aig-metadata |
Tracking | {"userId":"x"} |
Max 5 entries, flat structure |
cf-aig-cache-ttl |
Cache duration | 3600 |
Seconds, min 60, max 2592000 (30 days) |
cf-aig-skip-cache |
Bypass cache | true |
- |
cf-aig-cache-key |
Custom cache key | my-key |
Must be unique per response |
cf-aig-collect-log |
Skip logging | false |
Default: true |
cf-aig-cache-status |
Cache hit/miss | Response only | HIT or MISS |
In This Reference
| File | Purpose |
|---|---|
| sdk-integration.md | Vercel AI SDK, OpenAI SDK, Workers binding patterns |
| configuration.md | Dashboard setup, wrangler, API tokens |
| features.md | Caching, rate limits, guardrails, DLP, BYOK, unified billing |
| dynamic-routing.md | Fallbacks, A/B testing, conditional routing |
| troubleshooting.md | Debugging, errors, observability, gotchas |
Reading Order
| Task | Files |
|---|---|
| First-time setup | README + configuration.md |
| SDK integration | README + sdk-integration.md |
| Enable caching | README + features.md |
| Setup fallbacks | README + dynamic-routing.md |
| Debug errors | README + troubleshooting.md |
Architecture
AI Gateway acts as a proxy between your application and AI providers:
Your App → AI Gateway → AI Provider (OpenAI, Anthropic, etc.)
↓
Analytics, Caching, Rate Limiting, Logging
Key URL patterns:
- Unified API (OpenAI-compatible):
https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_id}/compat/chat/completions - Provider-specific:
https://gateway.ai.cloudflare.com/v1/{account_id}/{gateway_id}/{provider}/{endpoint} - Dynamic routes: Use route name instead of model:
dynamic/{route-name}
Gateway Types
- Unauthenticated Gateway: Open access (not recommended for production)
- Authenticated Gateway: Requires
cf-aig-authorizationheader with Cloudflare API token (recommended)
Provider Authentication Options
- Unified Billing: Use AI Gateway billing to pay for inference (keyless mode - no provider API key needed)
- BYOK (Store Keys): Store provider API keys in Cloudflare dashboard
- Request Headers: Include provider API key in each request
Related Skills
- Workers AI - For
env.AI.run()details - Agents SDK - For stateful AI patterns
- Vectorize - For RAG patterns with embeddings
Resources
references/ai-gateway/configuration.md (verbatim)
2 placeholder credentials shortened to pass the site's secret filter.
Configuration & Setup
Creating a Gateway
Dashboard
AI > AI Gateway > Create Gateway > Configure (auth, caching, rate limiting, logging)
API
curl -X POST https://api.cloudflare.com/client/v4/accounts/{account_id}/ai-gateway/gateways \
-H "Authorization: Bearer $CF_API_TOKEN" -H "Content-Type: application/json" \
-d '{"id":"my-gateway","cache_ttl":3600,"rate_limiting_interval":60,"rate_limiting_limit":100,"collect_logs":true}'
Naming: lowercase alphanumeric + hyphens (e.g., prod-api, dev-chat)
Wrangler Integration
[ai]
binding = "AI"
[[ai.gateway]]
id = "my-gateway"
wrangler secret put CF_API_TOKEN
wrangler secret put OPENAI_API_KEY # If not using BYOK
Authentication
Gateway Auth (protects gateway access)
const client = new OpenAI({
baseURL: `https://gateway.ai.cloudflare.com/v1/${accountId}/${gatewayId}/openai`,
defaultHeaders: { 'cf-aig-authorization': `Bearer ${cfToken}` }
});
Provider Auth Options
1. Unified Billing (keyless) - pay through Cloudflare, no provider key:
const client = new OpenAI({
baseURL: `https://gateway.ai.cloudflare.com/v1/${accountId}/${gatewayId}/openai`,
defaultHeaders: { 'cf-aig-authorization': `Bearer ${cfToken}` }
});
Supports: OpenAI, Anthropic, Google AI Studio
2. BYOK - store keys in dashboard (Provider Keys > Add), no key in code
3. Request Headers - pass provider key per request:
const client = new OpenAI({
apiKey: YOUR_KEY
baseURL: `https://gateway.ai.cloudflare.com/v1/${accountId}/${gatewayId}/openai`,
defaultHeaders: { 'cf-aig-authorization': `Bearer ${cfToken}` }
});
API Token Permissions
- Gateway management: AI Gateway - Read + Edit
- Gateway access: AI Gateway - Read (minimum)
Gateway Management API
# List
curl https://api.cloudflare.com/client/v4/accounts/{account_id}/ai-gateway/gateways \
-H "Authorization: Bearer $CF_API_TOKEN"
# Get
curl .../gateways/{gateway_id}
# Update
curl -X PUT .../gateways/{gateway_id} \
-d '{"cache_ttl":7200,"rate_limiting_limit":200}'
# Delete
curl -X DELETE .../gateways/{gateway_id}
Getting IDs
- Account ID: Dashboard > Overview > Copy
- Gateway ID: AI Gateway > Gateway name column
Python Example
from openai import OpenAI
import os
client = OpenAI(
api_key=YOUR_KEY
base_url=f"https://gateway.ai.cloudflare.com/v1/{os.environ['CF_ACCOUNT_ID']}/{os.environ['GATEWAY_ID']}/openai",
default_headers={"cf-aig-authorization": f"Bearer {os.environ['CF_API_TOKEN']}"}
)
Best Practices
- Always authenticate gateways in production
- Use BYOK or unified billing - secrets out of code
- Environment-specific gateways - separate dev/staging/prod
- Set rate limits - prevent runaway costs
- Enable logging - track usage, debug issues
references/ai-gateway/dynamic-routing.md (verbatim)
Dynamic Routing
Configure complex routing in dashboard without code changes. Use route names instead of model names.
Usage
const response = await client.chat.completions.create({
model: 'dynamic/smart-chat', // Route name from dashboard
messages: [{ role: 'user', content: 'Hello!' }]
});
Node Types
| Node | Purpose | Use Case |
|---|---|---|
| Conditional | Branch on metadata | Paid vs free users, geo routing |
| Percentage | A/B split traffic | Model testing, gradual rollouts |
| Rate Limit | Enforce quotas | Per-user/team limits |
| Budget Limit | Cost quotas | Per-user spending caps |
| Model | Call provider | Final destination |
Metadata
Pass via header (max 5 entries, flat only):
headers: {
'cf-aig-metadata': JSON.stringify({
userId: 'user-123',
tier: 'pro',
region: 'us-east'
})
}
Common Patterns
Multi-model fallback:
Start → GPT-4 → On error: Claude → On error: Llama
Tiered access:
Conditional: tier == 'enterprise' → GPT-4 (no limit)
Conditional: tier == 'pro' → Rate Limit 1000/hr → GPT-4o
Conditional: tier == 'free' → Rate Limit 10/hr → GPT-4o-mini
Gradual rollout:
Percentage: 10% → New model, 90% → Old model
Cost-based fallback:
Budget Limit: $100/day per teamId
< 80%: GPT-4
>= 80%: GPT-4o-mini
>= 100%: Error
Version Management
- Save changes as new version
- Test with
model: 'dynamic/route@v2' - Roll back by deploying previous version
Monitoring
Dashboard → Gateway → Dynamic Routes:
- Request count per path
- Success/error rates
- Latency/cost by path
Limitations
- Max 5 metadata entries
- Values: string/number/boolean/null only
- No nested objects
- Route names: alphanumeric + hyphens
references/ai-gateway/features.md (verbatim)
Features & Capabilities
Caching
Dashboard: Settings → Cache Responses → Enable
// Custom TTL (1 hour)
headers: { 'cf-aig-cache-ttl': '3600' }
// Skip cache
headers: { 'cf-aig-skip-cache': 'true' }
// Custom cache key
headers: { 'cf-aig-cache-key': 'greeting-en' }
Limits: TTL 60s - 30 days. Does NOT work with streaming.
Rate Limiting
Dashboard: Settings → Rate-limiting → Enable
- Fixed window: Resets at intervals
- Sliding window: Rolling window (more accurate)
- Returns
429when exceeded
Guardrails
Dashboard: Settings → Guardrails → Enable
Filter prompts/responses for inappropriate content. Actions: Flag (log) or Block (reject).
Data Loss Prevention (DLP)
Dashboard: Settings → DLP → Enable
Detect PII (emails, SSNs, credit cards). Actions: Flag, Block, or Redact.
Billing Modes
| Mode | Description | Setup |
|---|---|---|
| Unified Billing | Pay through Cloudflare, no provider keys | Use cf-aig-authorization header only |
| BYOK | Store provider keys in dashboard | Add keys in Provider Keys section |
| Pass-through | Send provider key with each request | Include provider's auth header |
Zero Data Retention
Dashboard: Settings → Privacy → Zero Data Retention
No prompts/responses stored. Request counts and costs still tracked.
Logging
Dashboard: Settings → Logs → Enable (up to 10M logs)
Each entry: prompt, response, provider, model, tokens, cost, duration, cache status, metadata.
// Skip logging for request
headers: { 'cf-aig-collect-log': 'false' }
Export: Use Logpush to S3, GCS, Datadog, Splunk, etc.
Custom Cost Tracking
For models not in Cloudflare's pricing database:
Dashboard: Gateway → Settings → Custom Costs
Or via API: set model, input_cost, output_cost.
Supported Providers (22+)
| Provider | Unified API | Notes |
|---|---|---|
| OpenAI | openai/gpt-4o |
Full support |
| Anthropic | anthropic/claude-sonnet-4-5 |
Full support |
| Google AI | google-ai-studio/gemini-2.0-flash |
Full support |
| Workers AI | workersai/@cf/meta/llama-3 |
Native |
| Azure OpenAI | azure-openai/* |
Deployment names |
| AWS Bedrock | Provider endpoint only | /bedrock/* |
| Groq | groq/* |
Fast inference |
| Mistral, Cohere, Perplexity, xAI, DeepSeek, Cerebras | Full support | - |
Best Practices
- Enable caching for deterministic prompts
- Set rate limits to prevent abuse
- Use guardrails for user-facing AI
- Enable DLP for sensitive data
- Use unified billing or BYOK for simpler key management
- Enable logging for debugging
- Use zero data retention when privacy required
references/ai-gateway/sdk-integration.md (verbatim)
4 placeholder credentials shortened to pass the site's secret filter.
AI Gateway SDK Integration
Vercel AI SDK (Recommended)
import { createAiGateway } from 'ai-gateway-provider';
import { createOpenAI } from '@ai-sdk/openai';
import { generateText } from 'ai';
const gateway = createAiGateway({
accountId: process.env.CF_ACCOUNT_ID,
gateway: process.env.CF_GATEWAY_ID,
apiKey: YOUR_KEY // Optional for auth gateways
});
const openai = createOpenAI({ apiKey: YOUR_KEY });
// Single model
const { text } = await generateText({
model: gateway(openai('gpt-4o')),
prompt: 'Hello'
});
// Automatic fallback array
const { text } = await generateText({
model: gateway([
openai('gpt-4o'),
anthropic('claude-sonnet-4-5'),
openai('gpt-4o-mini')
]),
prompt: 'Complex task'
});
Options
model: gateway(openai('gpt-4o'), {
cacheKey: 'my-key',
cacheTtl: 3600,
metadata: { userId: 'u123', team: 'eng' }, // Max 5 entries
retries: { maxAttempts: 3, backoff: 'exponential' }
})
OpenAI SDK
const client = new OpenAI({
apiKey: YOUR_KEY
baseURL: `https://gateway.ai.cloudflare.com/v1/${accountId}/${gatewayId}/openai`,
defaultHeaders: { 'cf-aig-authorization': `Bearer ${cfToken}` }
});
// Unified API - switch providers via model name
model: 'openai/gpt-4o' // or 'anthropic/claude-sonnet-4-5'
Anthropic SDK
const client = new Anthropic({
apiKey: YOUR_KEY
baseURL: `https://gateway.ai.cloudflare.com/v1/${accountId}/${gatewayId}/anthropic`,
defaultHeaders: { 'cf-aig-authorization': `Bearer ${cfToken}` }
});
Workers AI Binding
# wrangler.toml
[ai]
binding = "AI"
[[ai.gateway]]
id = "my-gateway"
await env.AI.run('@cf/meta/llama-3-8b-instruct',
{ messages: [...] },
{ gateway: { id: 'my-gateway', metadata: { userId: '123' } } }
);
LangChain / LlamaIndex
// Use OpenAI SDK pattern with custom baseURL
new ChatOpenAI({
configuration: {
baseURL: `https://gateway.ai.cloudflare.com/v1/${accountId}/${gatewayId}/openai`
}
});
HTTP / cURL
curl https://gateway.ai.cloudflare.com/v1/{account}/{gateway}/openai/chat/completions \
-H "Authorization: Bearer $OPENAI_KEY" \
-H "cf-aig-authorization: Bearer $CF_TOKEN" \
-H "cf-aig-metadata: {\"userId\":\"123\"}" \
-d '{"model":"gpt-4o","messages":[...]}'
Headers Reference
| Header | Purpose |
|---|---|
cf-aig-authorization |
Gateway auth token |
cf-aig-metadata |
JSON object (max 5 keys) |
cf-aig-cache-ttl |
Cache TTL in seconds |
cf-aig-skip-cache |
true to bypass cache |
references/ai-search/configuration.md (verbatim)
AI Search Configuration
Worker Setup
// wrangler.jsonc
{
"ai": { "binding": "AI" }
}
interface Env {
AI: Ai;
}
const answer = await env.AI.autorag("my-instance").aiSearch({
query: "How do I configure caching?",
model: "@cf/meta/llama-3.3-70b-instruct-fp8-fast"
});
Data Sources
R2 Bucket
Dashboard: AI Search → Create Instance → Select R2 bucket
Supported formats: .md, .txt, .html, .pdf, .doc, .docx, .csv, .json
Auto-indexed metadata: filename, folder, timestamp
Website Crawler
Requirements:
- Domain on Cloudflare
sitemap.xmlat root- Bot protection must allow
CloudflareAISearchuser agent
Path Filtering (R2)
docs/**/*.md # All .md in docs/ recursively
**/*.draft.md # Exclude (use in exclude patterns)
Indexing
- Automatic: Every 6 hours
- Force Sync: Dashboard button (30s rate limit between syncs)
- Pause: Settings → Pause Indexing (existing index remains searchable)
Service API Token
Dashboard: AI Search → Instance → Use AI Search → API → Create Token
Permissions:
- Read - search operations
- Edit - instance management
Store securely:
wrangler secret put AI_SEARCH_TOKEN
Multi-Environment
# wrangler.toml
[env.production.vars]
AI_SEARCH_INSTANCE = "prod-docs"
[env.staging.vars]
AI_SEARCH_INSTANCE = "staging-docs"
const answer = await env.AI.autorag(env.AI_SEARCH_INSTANCE).aiSearch({ query });
Monitoring
const instances = await env.AI.autorag("_").listInstances();
console.log(instances.find(i => i.name === "docs"));
Dashboard shows: files indexed, status, last index time, storage usage.
Back to openai/skills (Skills Catalog for Codex) or Agent skills.