Multi-Agent Routing
Route multiple specialized agents within a single Cloudflare Worker. The SDK's createHandler() accepts multiple agent classes and handles WebSocket routing automatically.
How it works
┌──────────────────┐
Request ──────────────► │ createHandler │
│ routeAgentRequest│
└────┬──┬──┬───────┘
│ │ │
┌─────────┘ │ └─────────┐
▼ ▼ ▼
/agents/ /agents/ /agents/
support sales billing
│ │ │
▼ ▼ ▼
SupportAgent SalesAgent BillingAgent
Each agent is a separate Durable Object with its own SQLite storage, state, and tools. All agents share the same Worker deployment.
Example: Support, Sales, and Billing
import { createChatAgent, defineTool, createHandler } from "@agentdeploy/edge-sdk";
import { z } from "zod";
// ── Support Agent ──────────────────────────────────────────
const searchKnowledgeBase = defineTool({
description: "Search the knowledge base for help articles",
inputSchema: z.object({ query: z.string() }),
execute: async ({ query }) => {
// Your KB search logic
return { articles: [{ title: "Reset password", url: "..." }] };
},
});
export const SupportAgent = createChatAgent({
name: "support",
systemPrompt: `You are a customer support agent.
Use searchKnowledgeBase to find help articles for customers.`,
tools: { searchKnowledgeBase },
maxSteps: 8,
});
// ── Sales Agent ────────────────────────────────────────────
const checkInventory = defineTool({
description: "Check product availability",
inputSchema: z.object({ sku: z.string() }),
execute: async ({ sku }) => {
return { sku, inStock: true, quantity: 42 };
},
});
const getPriceQuote = defineTool({
description: "Get a price quote including discounts",
inputSchema: z.object({
items: z.array(z.object({ sku: z.string(), qty: z.number() })),
}),
execute: async ({ items }) => {
const subtotal = items.reduce((sum, i) => sum + i.qty * 99, 0);
const discount = subtotal > 500 ? 0.1 : 0;
return { subtotal, discount, total: subtotal * (1 - discount) };
},
});
export const SalesAgent = createChatAgent({
name: "sales",
systemPrompt: `You are a sales assistant. Help customers check inventory and get pricing.`,
tools: { checkInventory, getPriceQuote },
maxSteps: 10,
});
// ── Billing Agent ──────────────────────────────────────────
const viewInvoices = defineTool({
description: "View customer invoices",
inputSchema: z.object({ customerId: z.string() }),
execute: async ({ customerId }, ctx) => {
const res = await fetch(`https://api.billing.com/invoices?customer=${customerId}`, {
headers: { Authorization: `Bearer ${ctx.env.BILLING_API_KEY}` },
});
return await res.json();
},
});
export const BillingAgent = createChatAgent({
name: "billing",
systemPrompt: `You are a billing specialist. Help customers with invoices and payments.`,
tools: { viewInvoices },
maxSteps: 8,
});
// ── Export handler with all three agents ───────────────────
export default createHandler(SupportAgent, SalesAgent, BillingAgent);
Accessing agents
Each agent is accessible at its own WebSocket endpoint:
ws://your-worker.workers.dev/agents/support/{instance-id}
ws://your-worker.workers.dev/agents/sales/{instance-id}
ws://your-worker.workers.dev/agents/billing/{instance-id}
The createHandler() function:
- Calls
routeAgentRequest()from the Cloudflare Agents SDK - Routes to the correct Durable Object based on the URL path
- Falls back to
/healthand/infoendpoints for platform checks
Auto-detection of Durable Object classes
When you deploy with ad deploy, the platform automatically:
- Scans the bundled script for exported classes extending
AgentorAIChatAgent - Creates
durable_object_namespacebindings for each class - Generates
new_sqlite_classesmigrations for SQLite-backed Durable Objects - Injects
nodejs_compatcompatibility flag when Agents SDK imports are detected
You don't need to manually configure bindings — the platform handles it.
When to use multiple agents
| Scenario | Recommendation |
|---|---|
| Single persona, multiple tools | One agent with many tools |
| Multiple specialized domains | Multiple agents (support/sales/billing) |
| Pipeline (research → analysis → writing) | Multiple agents or multi-step tools |
| User-specific isolation | Multiple instances of the same agent |
Each agent class gets its own Durable Object namespace, so state is isolated between agents. Within an agent class, instances are isolated by instance ID.