CLOUDFLARE AGENTS PATTERNS
Implementing patterns with the Agents SDK
OVERVIEW
Cloudflare's patterns page demonstrates agent patterns using the AI SDK. Here's how to implement the same patterns using the Cloudflare Agents SDK, which provides additional capabilities like state management, scheduling, and database access.
Agents extend the Agent class, run as Durable Objects, and include
built-in state management, scheduling, and database access.
Agent class → Durable Objects
↓
State, scheduling, sqlPATTERN 1: PROMPT CHAINING
Sequential steps where each LLM call processes the previous output. With state persistence.
// Pattern 1: Prompt Chaining with Agents SDK
import { Agent } from "@cloudflare/agents";
import { generateText, generateObject } from "ai";
import { z } from "zod";
export class MarketingCopyAgent extends Agent {
async onRequest(request: Request): Promise<Response> {
const { input } = await request.json();
// Check if we have intermediate state from previous run
const state = await this.getState();
if (state.currentCopy && state.step === "generated") {
// Resume from evaluation step
return this.evaluateAndImprove(state.currentCopy);
}
// Step 1: Generate marketing copy
const { text: copy } = await generateText({
model: this.env.AI_MODEL,
prompt: `Write persuasive marketing copy for: ${input}. Focus on benefits and emotional appeal.`,
});
// Store intermediate result in database
await this.sql`
INSERT INTO agent_state (agent_id, step, data, created_at)
VALUES (${this.ctx.id.toString()}, 'generated', ${JSON.stringify({ copy })}, ${Date.now()})
`;
// Update agent state
await this.setState({ currentCopy: copy, step: "generated" });
// Step 2: Evaluate the generated copy
return this.evaluateAndImprove(copy);
}
private async evaluateAndImprove(copy: string): Promise<Response> {
const { object: qualityMetrics } = await generateObject({
model: this.env.AI_MODEL,
schema: z.object({
hasCallToAction: z.boolean(),
emotionalAppeal: z.number().min(1).max(10),
clarity: z.number().min(1).max(10),
}),
prompt: `Evaluate this marketing copy:
1. Presence of call to action (true/false)
2. Emotional appeal (1-10)
3. Clarity (1-10)
Copy: ${copy}`,
});
// Step 3: Improve if needed
if (
!qualityMetrics.hasCallToAction ||
qualityMetrics.emotionalAppeal < 7 ||
qualityMetrics.clarity < 7
) {
const { text: improvedCopy } = await generateText({
model: this.env.AI_MODEL,
prompt: `Rewrite this marketing copy with:
${!qualityMetrics.hasCallToAction ? "- A clear call to action" : ""}
${qualityMetrics.emotionalAppeal < 7 ? "- Stronger emotional appeal" : ""}
${qualityMetrics.clarity < 7 ? "- Improved clarity and directness" : ""}
Original: ${copy}`,
});
// Store final result
await this.sql`
INSERT INTO agent_results (agent_id, result, metrics, created_at)
VALUES (${this.ctx.id.toString()}, ${improvedCopy}, ${JSON.stringify(qualityMetrics)}, ${Date.now()})
`;
await this.setState({ step: "completed" });
return new Response(
JSON.stringify({ copy: improvedCopy, qualityMetrics }),
{ headers: { "Content-Type": "application/json" } }
);
}
// Store final result
await this.sql`
INSERT INTO agent_results (agent_id, result, metrics, created_at)
VALUES (${this.ctx.id.toString()}, ${copy}, ${JSON.stringify(qualityMetrics)}, ${Date.now()})
`;
await this.setState({ step: "completed" });
return new Response(
JSON.stringify({ copy, qualityMetrics }),
{ headers: { "Content-Type": "application/json" } }
);
}
}State persists between steps. If agent restarts, it can resume from last step using stored state.
PATTERN 2: ROUTING
Classify input, route to specialized agents. With agent-to-agent communication.
// Pattern 2: Routing with Agent-to-Agent Communication
import { Agent, AgentNamespace } from "@cloudflare/agents";
import { generateObject } from "ai";
import { z } from "zod";
export class RoutingAgent extends Agent {
private agents: AgentNamespace;
constructor(ctx: DurableObjectState, env: Env) {
super(ctx, env);
this.agents = env.AGENTS;
}
async onRequest(request: Request): Promise<Response> {
const { query } = await request.json();
// Step 1: Classify the query
const { object: classification } = await generateObject({
model: this.env.AI_MODEL,
schema: z.object({
reasoning: z.string(),
type: z.enum(["general", "refund", "technical"]),
complexity: z.enum(["simple", "complex"]),
}),
prompt: `Classify this customer query:
${query}
Determine:
1. Query type (general, refund, or technical)
2. Complexity (simple or complex)
3. Brief reasoning`,
});
// Log routing decision
await this.sql`
INSERT INTO routing_log (query, type, complexity, reasoning, timestamp)
VALUES (${query}, ${classification.type}, ${classification.complexity}, ${classification.reasoning}, ${Date.now()})
`;
// Step 2: Route to specialized agent
const agentId = this.agents.idFromName(`${classification.type}-agent`);
const specializedAgent = this.agents.get(agentId);
const response = await specializedAgent.fetch(
new Request("https://agent/run", {
method: "POST",
body: JSON.stringify({ query, classification }),
})
);
return response;
}
}
export class SupportAgent extends Agent {
async onRequest(request: Request): Promise<Response> {
const { query } = await request.json();
const response = await this.generateText({
model: this.env.AI_MODEL,
system: "You are an expert customer service agent handling general inquiries.",
prompt: query,
});
return new Response(
JSON.stringify({ type: "support", response: response.text }),
{ headers: { "Content-Type": "application/json" } }
);
}
}
export class RefundAgent extends Agent {
async onRequest(request: Request): Promise<Response> {
const { query } = await request.json();
const response = await this.generateText({
model: this.env.AI_MODEL,
system: "You are a customer service agent specializing in refund requests. Follow company policy and collect necessary information.",
prompt: query,
});
return new Response(
JSON.stringify({ type: "refund", response: response.text }),
{ headers: { "Content-Type": "application/json" } }
);
}
}
export class TechnicalAgent extends Agent {
async onRequest(request: Request): Promise<Response> {
const { query } = await request.json();
const response = await this.generateText({
model: this.env.AI_MODEL,
system: "You are a technical support specialist with deep product knowledge. Focus on clear step-by-step troubleshooting.",
prompt: query,
});
// Store technical queries for analytics
await this.sql`
INSERT INTO technical_queries (query, response, timestamp)
VALUES (${query}, ${response.text}, ${Date.now()})
`;
return new Response(
JSON.stringify({ type: "technical", response: response.text }),
{ headers: { "Content-Type": "application/json" } }
);
}
}Agents can call other agents. Each agent is a Durable Object instance. Routing decisions logged to database for analytics.
PATTERN 3: PARALLELIZATION
Run multiple tasks concurrently. With result aggregation and database logging.
// Pattern 3: Parallelization with Result Aggregation
import { Agent } from "@cloudflare/agents";
import { generateObject } from "ai";
import { z } from "zod";
export class CodeReviewAgent extends Agent {
async onRequest(request: Request): Promise<Response> {
const { code } = await request.json();
// Track parallel execution state
await this.setState({
status: "processing",
startTime: Date.now(),
tasks: ["security", "performance", "maintainability"]
});
// Step 1: Run parallel reviews
const [securityReview, performanceReview, maintainabilityReview] =
await Promise.all([
this.reviewSecurity(code),
this.reviewPerformance(code),
this.reviewMaintainability(code),
]);
const reviews = [
{ ...securityReview, type: "security" },
{ ...performanceReview, type: "performance" },
{ ...maintainabilityReview, type: "maintainability" },
];
// Step 2: Store results in database
await this.sql`
INSERT INTO code_reviews (code_hash, reviews, created_at)
VALUES (${this.hashCode(code)}, ${JSON.stringify(reviews)}, ${Date.now()})
`;
// Step 3: Aggregate results
const summary = await this.generateText({
model: this.env.AI_MODEL,
system: "You are a technical lead summarizing multiple code reviews.",
prompt: `Synthesize these code review results into a concise summary with key actions:
${JSON.stringify(reviews, null, 2)}`,
});
await this.setState({
status: "completed",
endTime: Date.now(),
summary: summary.text
});
return new Response(
JSON.stringify({ reviews, summary: summary.text }),
{ headers: { "Content-Type": "application/json" } }
);
}
private async reviewSecurity(code: string) {
const { object } = await generateObject({
model: this.env.AI_MODEL,
system: "You are an expert in code security. Focus on identifying security vulnerabilities, injection risks, and authentication issues.",
schema: z.object({
vulnerabilities: z.array(z.string()),
riskLevel: z.enum(["low", "medium", "high"]),
suggestions: z.array(z.string()),
}),
prompt: `Review this code for security issues:
${code}`,
});
return object;
}
private async reviewPerformance(code: string) {
const { object } = await generateObject({
model: this.env.AI_MODEL,
system: "You are an expert in code performance. Focus on identifying performance bottlenecks, memory leaks, and optimization opportunities.",
schema: z.object({
issues: z.array(z.string()),
impact: z.enum(["low", "medium", "high"]),
optimizations: z.array(z.string()),
}),
prompt: `Review this code for performance issues:
${code}`,
});
return object;
}
private async reviewMaintainability(code: string) {
const { object } = await generateObject({
model: this.env.AI_MODEL,
system: "You are an expert in code quality. Focus on code structure, readability, and adherence to best practices.",
schema: z.object({
concerns: z.array(z.string()),
qualityScore: z.number().min(1).max(10),
recommendations: z.array(z.string()),
}),
prompt: `Review this code for maintainability:
${code}`,
});
return object;
}
private hashCode(code: string): string {
// Simple hash for tracking
return Buffer.from(code).toString("base64").slice(0, 16);
}
}Results stored in database automatically. Agent state tracks parallel execution. Can resume if partial completion.
PATTERN 4: ORCHESTRATOR-WORKERS
Central agent delegates to worker agents. With proper agent namespace communication.
// Pattern 4: Orchestrator-Workers with Agent Namespace
import { Agent, AgentNamespace } from "@cloudflare/agents";
import { generateObject } from "ai";
import { z } from "zod";
export class OrchestratorAgent extends Agent {
private agents: AgentNamespace;
constructor(ctx: DurableObjectState, env: Env) {
super(ctx, env);
this.agents = env.AGENTS;
}
async onRequest(request: Request): Promise<Response> {
const { featureRequest } = await request.json();
// Track orchestration state
await this.setState({
status: "planning",
featureRequest,
startTime: Date.now(),
});
// Step 1: Plan the implementation
const { object: implementationPlan } = await generateObject({
model: this.env.AI_MODEL,
schema: z.object({
files: z.array(
z.object({
purpose: z.string(),
filePath: z.string(),
changeType: z.enum(["create", "modify", "delete"]),
})
),
estimatedComplexity: z.enum(["low", "medium", "high"]),
}),
system: "You are a senior software architect planning feature implementations.",
prompt: `Analyze this feature request and create an implementation plan:
${featureRequest}`,
});
await this.setState({
status: "executing",
plan: implementationPlan,
});
// Step 2: Delegate to worker agents
const workerTasks = implementationPlan.files.map((file, index) =>
this.delegateToWorker(file, featureRequest, index)
);
// Step 3: Collect results
const results = await Promise.allSettled(workerTasks);
const fileChanges = results.map((result, index) => {
if (result.status === "fulfilled") {
return {
file: implementationPlan.files[index],
implementation: result.value,
};
} else {
return {
file: implementationPlan.files[index],
error: result.reason.message,
};
}
});
// Step 4: Store orchestration results
await this.sql`
INSERT INTO orchestrations (feature_request, plan, results, created_at)
VALUES (${featureRequest}, ${JSON.stringify(implementationPlan)}, ${JSON.stringify(fileChanges)}, ${Date.now()})
`;
await this.setState({
status: "completed",
endTime: Date.now(),
});
return new Response(
JSON.stringify({
plan: implementationPlan,
changes: fileChanges,
}),
{ headers: { "Content-Type": "application/json" } }
);
}
private async delegateToWorker(
file: { purpose: string; filePath: string; changeType: string },
featureRequest: string,
index: number
) {
const workerId = this.agents.idFromName(`worker-${index}`);
const worker = this.agents.get(workerId);
const workerSystemPrompt = {
create:
"You are an expert at implementing new files following best practices and project patterns.",
modify:
"You are an expert at modifying existing code while maintaining consistency and avoiding regressions.",
delete:
"You are an expert at safely removing code while ensuring no breaking changes.",
}[file.changeType];
const response = await worker.fetch(
new Request("https://agent/run", {
method: "POST",
body: JSON.stringify({
file,
featureRequest,
systemPrompt: workerSystemPrompt,
}),
})
);
return response.json();
}
}
export class WorkerAgent extends Agent {
async onRequest(request: Request): Promise<Response> {
const { file, featureRequest, systemPrompt } = await request.json();
const { object: change } = await generateObject({
model: this.env.AI_MODEL,
schema: z.object({
explanation: z.string(),
code: z.string(),
}),
system: systemPrompt,
prompt: `Implement the changes for ${file.filePath} to support:
${file.purpose}
Consider the overall feature context:
${featureRequest}`,
});
// Store worker result
await this.sql`
INSERT INTO worker_results (worker_id, file_path, result, created_at)
VALUES (${this.ctx.id.toString()}, ${file.filePath}, ${JSON.stringify(change)}, ${Date.now()})
`;
return new Response(
JSON.stringify(change),
{ headers: { "Content-Type": "application/json" } }
);
}
}Orchestrator uses AgentNamespace to communicate with workers. Each worker is isolated Durable Object. Results aggregated with state tracking.
PATTERN 5: EVALUATOR-OPTIMIZER
Evaluation loop with scheduled optimization. Using built-in scheduling.
// Pattern 5: Evaluator-Optimizer with Scheduling
import { Agent, AgentNamespace } from "@cloudflare/agents";
import { generateText, generateObject } from "ai";
import { z } from "zod";
export class EvaluatorAgent extends Agent {
async onStart() {
// Schedule daily evaluation
await this.schedule({
name: "daily-evaluation",
cron: "0 2 * * *", // 2 AM daily
action: async () => {
await this.evaluateSystem();
},
});
}
async onRequest(request: Request): Promise<Response> {
const { systemOutput, context } = await request.json();
const evaluation = await this.evaluateOutput(systemOutput, context);
return new Response(
JSON.stringify(evaluation),
{ headers: { "Content-Type": "application/json" } }
);
}
private async evaluateSystem() {
// Get recent system outputs
const recentOutputs = await this.sql`
SELECT output, context FROM system_outputs
WHERE created_at > ${Date.now() - 24 * 60 * 60 * 1000}
ORDER BY created_at DESC
LIMIT 10
`;
for (const row of recentOutputs) {
await this.evaluateOutput(row.output, row.context);
}
}
private async evaluateOutput(
systemOutput: string,
context?: Record<string, any>
) {
const { object: evaluation } = await generateObject({
model: this.env.AI_MODEL,
schema: z.object({
accuracy: z.number().min(0).max(10),
relevance: z.number().min(0).max(10),
completeness: z.number().min(0).max(10),
overallScore: z.number().min(0).max(10),
strengths: z.array(z.string()),
weaknesses: z.array(z.string()),
recommendations: z.array(z.string()),
}),
system: "You are an expert in evaluating system performance.",
prompt: `Evaluate this system output:
Output: ${systemOutput}
Context: ${JSON.stringify(context || {})}
Consider:
1. Overall quality (0-10)
2. Accuracy (0-10)
3. Relevance (0-10)
4. Completeness (0-10)
5. Strengths and weaknesses
6. Improvement recommendations`,
});
// Store evaluation history
await this.sql`
INSERT INTO evaluations (output_hash, overall_score, evaluation_data, created_at)
VALUES (${this.hashOutput(systemOutput)}, ${evaluation.overallScore}, ${JSON.stringify(evaluation)}, ${Date.now()})
`;
// Trigger optimizer if score is low
if (evaluation.overallScore < 7) {
await this.triggerOptimizer(evaluation);
}
return evaluation;
}
private async triggerOptimizer(evaluation: any) {
const agents = this.env.AGENTS as AgentNamespace;
const optimizerId = agents.idFromName("optimizer");
const optimizer = agents.get(optimizerId);
await optimizer.fetch(
new Request("https://agent/run", {
method: "POST",
body: JSON.stringify({ evaluation }),
})
);
}
private hashOutput(output: string): string {
return Buffer.from(output).toString("base64").slice(0, 16);
}
}
export class OptimizerAgent extends Agent {
private agents: AgentNamespace;
constructor(ctx: DurableObjectState, env: Env) {
super(ctx, env);
this.agents = env.AGENTS;
}
async onRequest(request: Request): Promise<Response> {
const { evaluation } = await request.json();
// Step 1: Determine optimization strategy
const { object: strategy } = await generateObject({
model: this.env.AI_MODEL,
schema: z.object({
priority: z.enum(["high", "medium", "low"]),
strategies: z.array(z.string()),
expectedImprovement: z.number().min(0).max(10),
implementationSteps: z.array(z.string()),
}),
system: "You are an expert in system optimization.",
prompt: `Based on this evaluation, suggest specific optimization strategies:
Evaluation: ${JSON.stringify(evaluation)}
Provide:
1. Priority level (high/medium/low)
2. Specific strategies
3. Expected improvement (0-10)
4. Implementation steps`,
});
// Step 2: Apply optimization if priority is high
if (strategy.priority === "high") {
const { text: implementation } = await generateText({
model: this.env.AI_MODEL,
system: "You are an expert at implementing optimizations.",
prompt: `Implement the following optimization strategies:
${strategy.strategies.join("\n")}
Provide a detailed implementation plan.`,
});
// Store optimization history
await this.sql`
INSERT INTO optimizations (evaluation_id, strategy, result, created_at)
VALUES (${evaluation.overallScore}, ${JSON.stringify(strategy)}, ${implementation}, ${Date.now()})
`;
// Schedule follow-up evaluation
await this.schedule({
name: "post-optimization-evaluation",
cron: "0 */6 * * *", // Every 6 hours
action: async () => {
const evaluatorId = this.agents.idFromName("evaluator");
const evaluator = this.agents.get(evaluatorId);
await evaluator.fetch(
new Request("https://agent/run", {
method: "POST",
body: JSON.stringify({
systemOutput: implementation,
context: { optimized: true },
}),
})
);
},
});
return new Response(
JSON.stringify({
optimized: true,
strategy,
implementation,
}),
{ headers: { "Content-Type": "application/json" } }
);
}
return new Response(
JSON.stringify({
optimized: false,
strategy,
reason: "Priority not high enough for immediate optimization",
}),
{ headers: { "Content-Type": "application/json" } }
);
}
}Uses schedule() for recurring evaluations. Optimization history
in database. Can trigger other agents on conditions.
WRANGLER CONFIG
// wrangler.jsonc
{
"name": "agents-patterns",
"main": "src/index.ts",
"compatibility_date": "2024-01-01",
"agents": {
"binding": "AGENTS",
"agents": [
{ "name": "MarketingCopyAgent", "class": "MarketingCopyAgent" },
{ "name": "RoutingAgent", "class": "RoutingAgent" },
{ "name": "SupportAgent", "class": "SupportAgent" },
{ "name": "RefundAgent", "class": "RefundAgent" },
{ "name": "TechnicalAgent", "class": "TechnicalAgent" },
{ "name": "CodeReviewAgent", "class": "CodeReviewAgent" },
{ "name": "OrchestratorAgent", "class": "OrchestratorAgent" },
{ "name": "WorkerAgent", "class": "WorkerAgent" },
{ "name": "EvaluatorAgent", "class": "EvaluatorAgent" },
{ "name": "OptimizerAgent", "class": "OptimizerAgent" }
]
},
"d1_databases": [
{
"binding": "DB",
"database_name": "agents_db",
"database_id": "your-database-id"
}
],
"ai": {
"binding": "AI_MODEL",
"model": "@cf/meta/llama-3-8b-instruct"
}
}AGENTS SDK FEATURES
- State persistence: Agents survive restarts with state management.
- Database access: Built-in
sqltemplate tag for database operations. - Scheduling:
schedule()for recurring tasks and workflows. - Agent communication: AgentNamespace for agent-to-agent calls with proper isolation.
- Durable Objects: Each agent runs as a Durable Object instance with automatic scaling and persistence.
AGENTS SDK CAPABILITIES
- • Agent class extends DurableObject
- • Built-in state management with
setState()andgetState() - •
schedule()for recurring tasks and workflows - • AgentNamespace for agent-to-agent communication
- •
sqltemplate tag for database operations - • State persistence across restarts
- • Automatic scaling with Durable Objects
REFERENCE
Original patterns: Cloudflare Agents Patterns
Agents SDK docs: Cloudflare Agents Documentation