| name | agents |
| description | Build Cloudflare Agents SDK applications for autonomous multi-step tool use, AIChatAgent chat agents, Durable Object-backed state, tools, scheduling, callable methods, WebSockets, SQL state, and constrained agent behavior. Use when RAG or Workflows are not enough.
|
| compatibility | Cloudflare Workers TypeScript projects using Wrangler; verify current Cloudflare APIs, limits, and pricing before production use. |
| metadata | {"source":"Architecting on Cloudflare plus official Cloudflare Developer Platform docs","generated":"2026-04-28"} |
Agents
Use this skill when building an autonomous tool-using system on Cloudflare. Do not use an agent when a deterministic Worker, RAG endpoint, Queue, or Workflow is sufficient.
When to use Agents
Use Agents for:
- Autonomous multi-step tool use.
- Chat agents with durable state and resumable interactions.
- Systems that need model reasoning plus application tools.
- Long-lived per-user or per-task agent state.
Prefer alternatives for:
- Simple chatbot over documents: RAG endpoint.
- Ordered deterministic process: Workflow.
- Deferred background task: Queue.
- Shared realtime room without AI autonomy: Durable Object.
Design rules
- Keep the agent's tools narrow, typed, and permission-checked.
- The model proposes actions; code enforces authorization and invariants.
- Store durable state intentionally. Do not rely on prompt memory alone.
- Include tenant/user boundaries in agent identity and storage.
- Add loop limits, budget limits, and stop conditions.
- Log tool calls, model decisions, and failures with a correlation ID.
Agent skeleton
import { Agent, routeAgentRequest } from "agents";
export interface Env {
AI: Ai;
}
export class SupportAgent extends Agent<Env> {
async onRequest(request: Request): Promise<Response> {
const input = await request.json<{ message: string }>();
const answer = await this.env.AI.run("@cf/meta/llama-3.1-8b-instruct", {
messages: [
{ role: "system", content: "You are a support agent. Use tools only when needed." },
{ role: "user", content: input.message }
]
});
return Response.json(answer);
}
}
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const agentResponse = await routeAgentRequest(request, env);
return agentResponse ?? new Response("Not found", { status: 404 });
}
} satisfies ExportedHandler<Env>;
Verify exact SDK imports and routing helpers against current Agents SDK docs.
Wrangler binding
Agents require Durable Object bindings and migrations. Keep the binding name and class name aligned with the exported agent class.
{
"durable_objects": {
"bindings": [
{ "name": "SupportAgent", "class_name": "SupportAgent" }
]
},
"migrations": [
{ "tag": "v1", "new_sqlite_classes": ["SupportAgent"] }
]
}
Tool contract template
Every tool should specify:
type ToolContext = {
tenantId: string;
userId: string;
requestId: string;
};
type ToolResult<T> =
| { ok: true; data: T }
| { ok: false; error: string; safeMessage: string };
Tool implementation rules:
- Validate inputs with a schema.
- Check tenant/user authorization inside the tool.
- Bound result size before returning to the model.
- Redact secrets and PII not required for the next step.
- Make mutating tools idempotent where possible.
- Require human confirmation for irreversible or expensive actions.
State and memory
- Store durable facts in SQL/D1/DO storage, not only in chat transcripts.
- Summarize long transcripts into bounded memory.
- Keep user preferences separate from operational state.
- Allow users/admins to inspect and reset agent state.
Anti-patterns
- Agent is allowed to call broad arbitrary HTTP/fetch tools.
- Tool output includes secrets or unrelated tenant data.
- The model decides authorization.
- No limit on tool-call loops or token spend.
- Using an agent for a deterministic CRUD flow.