Agents SDK
OpenAIOfficialCreated by CloudflareDistributed by OpenAI
- Skill
- Tool integration
- Cloud and DevOps
- Apache-2.0
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
The Agents SDK provides a framework for building stateful, durable AI agents directly on Cloudflare Workers. It simplifies the development of complex agentic applications by offering built-in state management, RPC capabilities via WebSockets, durable workflows, and seamless integration with MCP servers. The SDK is designed to handle real-time interactions, scheduled tasks, and email routing, while providing React hooks for easy client-side integration.
What it does
- Enables creation of stateful agents with SQLite-backed persistence.
- Exposes agent methods as callable RPC endpoints via WebSockets.
- Supports durable, multi-step background workflows.
- Integrates with MCP servers for expanded tool capabilities.
- Provides React hooks for real-time agent communication.
- Handles scheduled tasks and cron jobs within the agent lifecycle.
When to use it
- When building stateful AI agents on the Cloudflare Workers platform.
- When you need durable, multi-step workflows for background processing.
- When implementing real-time WebSocket-based communication between clients and agents.
- When connecting to or building MCP servers for agent tool use.
- When you require persistent state that auto-syncs to client applications.
Advantages
- Native integration with Cloudflare Workers and Durable Objects.
- Simplifies complex state management and persistence.
- Reduces round-trips with callable RPC methods.
- Provides robust support for resumable streaming and durable workflows.
- Streamlines client-side development with dedicated React hooks.
Usage examples
- “How do I define a callable method in my Cloudflare Agent?”
- You use the @callable() decorator on your class method, which allows it to be invoked remotely via WebSocket RPC from a client.
- “How can I persist state in my agent?”
- You use the this.setState() method within your Agent class, which updates the SQLite-backed state and triggers any defined validation or update hooks.
- “How do I connect a React frontend to my agent?”
- You use the useAgent hook from the agents/react package, providing the agent name and instance identifier to manage state and communication.
- “Can I run background tasks in my agent?”
- Yes, you can use the this.schedule() or this.scheduleEvery() methods to trigger one-time or recurring tasks, or use AgentWorkflow for durable multi-step processes.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/openai/agents-sdk/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip agents-sdk.zip -d .agents/skills
Documentation by Cloudflare
Cloudflare Agents SDK
Your knowledge of the Agents SDK may be outdated. Prefer retrieval over pre-training for any Agents SDK task.
Retrieval Sources
Fetch current docs from https://github.com/cloudflare/agents/tree/main/docs before implementing.
| Topic | Doc | Use for |
|---|---|---|
| Getting started | docs/getting-started.md | First agent, project setup |
| State | docs/state.md | setState, validateStateChange, persistence |
| Routing | docs/routing.md | URL patterns, routeAgentRequest, basePath |
| Callable methods | docs/callable-methods.md | @callable, RPC, streaming, timeouts |
| Scheduling | docs/scheduling.md | schedule(), scheduleEvery(), cron |
| Workflows | docs/workflows.md | AgentWorkflow, durable multi-step tasks |
| HTTP/WebSockets | docs/http-websockets.md | Lifecycle hooks, hibernation |
docs/email.md | Email routing, secure reply resolver | |
| MCP client | docs/mcp-client.md | Connecting to MCP servers |
| MCP server | docs/mcp-servers.md | Building MCP servers with McpAgent |
| Client SDK | docs/client-sdk.md | useAgent, useAgentChat, React hooks |
| Human-in-the-loop | docs/human-in-the-loop.md | Approval flows, pausing workflows |
| Resumable streaming | docs/resumable-streaming.md | Stream recovery on disconnect |
Cloudflare docs: https://developers.cloudflare.com/agents/
Capabilities
The Agents SDK provides:
Persistent state - SQLite-backed, auto-synced to clients
Callable RPC -
@callable()methods invoked over WebSocketScheduling - One-time, recurring (
scheduleEvery), and cron tasksWorkflows - Durable multi-step background processing via
AgentWorkflowMCP integration - Connect to MCP servers or build your own with
McpAgentEmail handling - Receive and reply to emails with secure routing
Streaming chat -
AIChatAgentwith resumable streamsReact hooks -
useAgent,useAgentChatfor client apps
FIRST: Verify Installation
npm ls agents # Should show agents packageIf not installed:
npm install agentsWrangler Configuration
{
"durable_objects": {
"bindings": [{ "name": "MyAgent", "class_name": "MyAgent" }]
},
"migrations": [{ "tag": "v1", "new_sqlite_classes": ["MyAgent"] }]
}Agent Class
import { Agent, routeAgentRequest, callable } from "agents";
type State = { count: number };
export class Counter extends Agent<Env, State> {
initialState = { count: 0 };
// Validation hook - runs before state persists (sync, throwing rejects the update)
validateStateChange(nextState: State, source: Connection | "server") {
if (nextState.count < 0) throw new Error("Count cannot be negative");
}
// Notification hook - runs after state persists (async, non-blocking)
onStateUpdate(state: State, source: Connection | "server") {
console.log("State updated:", state);
}
@callable()
increment() {
this.setState({ count: this.state.count + 1 });
return this.state.count;
}
}
export default {
fetch: (req, env) => routeAgentRequest(req, env) ?? new Response("Not found", { status: 404 })
};Routing
Requests route to /agents/{agent-name}/{instance-name}:
| Class | URL |
|---|---|
Counter | /agents/counter/user-123 |
ChatRoom | /agents/chat-room/lobby |
Client: useAgent({ agent: "Counter", name: "user-123" })
Core APIs
| Task | API |
|---|---|
| Read state | this.state.count |
| Write state | this.setState({ count: 1 }) |
| SQL query | this.sql`SELECT * FROM users WHERE id = ${id}` |
| Schedule (delay) | await this.schedule(60, "task", payload) |
| Schedule (cron) | await this.schedule("0 * * * *", "task", payload) |
| Schedule (interval) | await this.scheduleEvery(30, "poll") |
| RPC method | @callable() myMethod() { ... } |
| Streaming RPC | @callable({ streaming: true }) stream(res) { ... } |
| Start workflow | await this.runWorkflow("ProcessingWorkflow", params) |
React Client
import { useAgent } from "agents/react";
function App() {
const [state, setLocalState] = useState({ count: 0 });
const agent = useAgent({
agent: "Counter",
name: "my-instance",
onStateUpdate: (newState) => setLocalState(newState),
onIdentity: (name, agentType) => console.log(`Connected to ${name}`)
});
return (
<button onClick={() => agent.setState({ count: state.count + 1 })}>
Count: {state.count}
</button>
);
}References
references/workflows.md - Durable Workflows integration
references/callable.md - RPC methods, streaming, timeouts
references/state-scheduling.md - State persistence, scheduling
references/streaming-chat.md - AIChatAgent, resumable streams
references/mcp.md - MCP server integration
references/email.md - Email routing and handling
references/codemode.md - Code Mode (experimental)
Files
- ATTRIBUTION.mdAdded by AutoGineer906 B
- LICENSE.txt10.5 KiB
- SKILL.md5.5 KiB
- agents/openai.yaml342 B
- assets/cloudflare-small.svg1.2 KiB
- assets/cloudflare.png1.2 KiB
- references/callable.md2.1 KiB
- references/codemode.md5.3 KiB
- references/email.md3.5 KiB
- references/mcp.md3.5 KiB
- references/state-scheduling.md3.7 KiB
- references/streaming-chat.md4.1 KiB
- references/workflows.md3.8 KiB
references/codemode.md
Code Mode (Experimental)
Code Mode generates executable JavaScript instead of making individual tool calls. This significantly reduces token usage and enables complex multi-tool workflows.
Why Code Mode?
Traditional tool calling:
One tool call per LLM request
Multiple round-trips for chained operations
High token usage for complex workflows
Code Mode:
LLM generates code that orchestrates multiple tools
Single execution for complex workflows
Self-debugging and error recovery
Ideal for MCP server orchestration
Setup
1. Wrangler Config
{
"name": "my-agent-worker",
"compatibility_flags": ["experimental", "enable_ctx_exports"],
"durable_objects": {
// "class_name" must match your Agent class name exactly
"bindings": [{ "name": "MyAgent", "class_name": "MyAgent" }]
},
"migrations": [
// Required: list all Agent classes for SQLite storage
{ "tag": "v1", "new_sqlite_classes": ["MyAgent"] }
],
"services": [
{
"binding": "globalOutbound",
// "service" must match "name" above
"service": "my-agent-worker",
"entrypoint": "globalOutbound"
},
{
"binding": "CodeModeProxy",
"service": "my-agent-worker",
"entrypoint": "CodeModeProxy"
}
],
"worker_loaders": [{ "binding": "LOADER" }]
}2. Export Required Classes
// Export the proxy for tool execution (required for codemode)
export { CodeModeProxy } from "@cloudflare/codemode/ai";
// Define outbound fetch handler for security filtering
export const globalOutbound = {
fetch: async (input: string | URL | RequestInfo, init?: RequestInit) => {
const url = new URL(
typeof input === "string"
? input
: typeof input === "object" && "url" in input
? input.url
: input.toString()
);
// Block certain domains if needed
if (url.hostname === "blocked.example.com") {
return new Response("Not allowed", { status: 403 });
}
return fetch(input, init);
}
};3. Install Dependencies
npm install @cloudflare/codemode ai @ai-sdk/openai zod4. Use Code Mode in Agent
import { Agent } from "agents";
import { experimental_codemode as codemode } from "@cloudflare/codemode/ai";
import { streamText, tool, convertToModelMessages } from "ai";
import { openai } from "@ai-sdk/openai";
import { env } from "cloudflare:workers";
import { z } from "zod";
const tools = {
getWeather: tool({
description: "Get weather for a location",
parameters: z.object({ location: z.string() }),
execute: async ({ location }) => `Weather: ${location} 72°F`
}),
sendEmail: tool({
description: "Send an email",
parameters: z.object({ to: z.string(), subject: z.string(), body: z.string() }),
execute: async ({ to, subject, body }) => `Email sent to ${to}`
})
};
export class MyAgent extends Agent<Env, State> {
tools = {};
// Method called by codemode proxy
callTool(functionName: string, args: unknown[]) {
return this.tools[functionName]?.execute?.(args, {
abortSignal: new AbortController().signal,
toolCallId: "codemode",
messages: []
});
}
async onChatMessage() {
this.tools = { ...tools, ...this.mcp.getAITools() };
const { prompt, tools: wrappedTools } = await codemode({
prompt: "You are a helpful assistant...",
tools: this.tools,
globalOutbound: env.globalOutbound,
loader: env.LOADER,
proxy: this.ctx.exports.CodeModeProxy({
props: {
binding: "MyAgent", // Class name
name: this.name, // Instance name
callback: "callTool" // Method to call
}
})
});
const result = streamText({
system: prompt,
model: openai("gpt-4o"),
messages: await convertToModelMessages(this.state.messages),
tools: wrappedTools // Use wrapped tools, not original
});
// ... handle stream
}
}Generated Code Example
When user asks "Check the weather in NYC and email me the forecast", codemode generates:
async function executeTask() {
const weather = await codemode.getWeather({ location: "NYC" });
await codemode.sendEmail({
to: "[email protected]",
subject: "NYC Weather Forecast",
body: `Current weather: ${weather}`
});
return { success: true, weather };
}MCP Server Orchestration
Code Mode excels at orchestrating multiple MCP servers:
async function executeTask() {
// Query file system MCP
const files = await codemode.listFiles({ path: "/projects" });
// Query database MCP
const status = await codemode.queryDatabase({
query: "SELECT * FROM projects WHERE name = ?",
params: [files[0].name]
});
// Conditional logic based on results
if (status.length === 0) {
await codemode.createTask({
title: `Review: ${files[0].name}`,
priority: "high"
});
}
return { files, status };
}When to Use
| Scenario | Use Code Mode? |
|---|---|
| Single tool call | No |
| Chained tool calls | Yes |
| Conditional logic across tools | Yes |
| MCP multi-server workflows | Yes |
| Token budget constrained | Yes |
| Simple Q&A chat | No |
Limitations
Experimental - API may change
Requires Cloudflare Workers
JavaScript execution only (Python planned)
Requires additional wrangler config
Requirements and compatibility
Written for: OpenAI Codex
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs an MCP server, Needs Node.js
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Cloudflare
- Publisher
- OpenAI (Official)
- Distributed by
- OpenAI
- Source
- openai/plugins · plugins/cloudflare/skills/agents-sdk · commit d420d13
- Licence
- Apache License 2.0 (redistribution allowed)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Cloudflare or OpenAI.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download agents-sdk.zip