Generated banner for Agents SDK
Generated logo for Agents SDK

Agents SDK

OpenAIOfficialCreated by CloudflareDistributed by OpenAI

  • Skill
  • Tool integration
  • Cloud and DevOps
  • Apache-2.0
  • No issues found

From the author

Build AI agents on Cloudflare Workers using the Agents SDK. Load when creating stateful agents, durable workflows, real-time WebSocket apps, scheduled tasks, MCP servers, or chat applications. Covers Agent class, state management, callable RPC, Workflows integration, and React hooks. Biases towards retrieval from Cloudflare docs over pre-trained knowledge.
— the description by Cloudflare

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

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/openai/agents-sdk/download
  2. Unzip 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.

TopicDocUse for
Getting starteddocs/getting-started.mdFirst agent, project setup
Statedocs/state.mdsetState, validateStateChange, persistence
Routingdocs/routing.mdURL patterns, routeAgentRequest, basePath
Callable methodsdocs/callable-methods.md@callable, RPC, streaming, timeouts
Schedulingdocs/scheduling.mdschedule(), scheduleEvery(), cron
Workflowsdocs/workflows.mdAgentWorkflow, durable multi-step tasks
HTTP/WebSocketsdocs/http-websockets.mdLifecycle hooks, hibernation
Emaildocs/email.mdEmail routing, secure reply resolver
MCP clientdocs/mcp-client.mdConnecting to MCP servers
MCP serverdocs/mcp-servers.mdBuilding MCP servers with McpAgent
Client SDKdocs/client-sdk.mduseAgent, useAgentChat, React hooks
Human-in-the-loopdocs/human-in-the-loop.mdApproval flows, pausing workflows
Resumable streamingdocs/resumable-streaming.mdStream 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 WebSocket

  • Scheduling - One-time, recurring (scheduleEvery), and cron tasks

  • Workflows - Durable multi-step background processing via AgentWorkflow

  • MCP integration - Connect to MCP servers or build your own with McpAgent

  • Email handling - Receive and reply to emails with secure routing

  • Streaming chat - AIChatAgent with resumable streams

  • React hooks - useAgent, useAgentChat for client apps

FIRST: Verify Installation

npm ls agents  # Should show agents package

If not installed:

npm install agents

Wrangler 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}:

ClassURL
Counter/agents/counter/user-123
ChatRoom/agents/chat-room/lobby

Client: useAgent({ agent: "Counter", name: "user-123" })

Core APIs

TaskAPI
Read statethis.state.count
Write statethis.setState({ count: 1 })
SQL querythis.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 workflowawait 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

Files

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 zod
4. 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

ScenarioUse Code Mode?
Single tool callNo
Chained tool callsYes
Conditional logic across toolsYes
MCP multi-server workflowsYes
Token budget constrainedYes
Simple Q&A chatNo

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