Multiple agents
Compose reusable agents by reference, then initialize and serve them together.
Each defineAgent call returns an independent agent with its own tools, hooks,
verification settings, and session helpers. Pass the returned object directly in
another agent's subagents array:
import { createAgentRouter, defineAgent, defineProvider } from "@trycereal/sdk"
const gateway = defineProvider({ slug: "gateway", type: "vercel-ai-gateway", secret: process.env.AI_GATEWAY_API_KEY })
const model = { provider: gateway, model: "anthropic/claude-sonnet-4.6" }
export const researcher = defineAgent({
agent: {
slug: "researcher",
description: "Find evidence and cite sources before drawing a conclusion.",
model,
system: "Research the assigned question."
}
})
export const coordinator = defineAgent({
agent: {
slug: "coordinator",
model,
system: "Delegate research, then synthesize an answer.",
subagents: [researcher]
}
})
export const agents = createAgentRouter({ agents: [coordinator] })
// Optional early startup. The session action below also initializes dependencies.
await agents.init()
const session = await coordinator.sessions.start({ message: "Compare our options." })The router discovers researcher through the reference, mounts each agent at
/api/cereal/<slug>/mcp and /api/cereal/<slug>/hooks, and initializes dependencies before
parents. Shared provider and agent references initialize once. Its agents array
uses that same dependency order. Duplicate slugs on distinct objects,
reference cycles, and empty routers are rejected.
A router owns its agents' HTTP paths: construct it before serving requests and
use one router per agent instance. agent.paths reports the active paths. Mount
agents.fetch or agents.handlers in your framework; the
framework guides include Express, Fastify, and Hono.
Name a delegation role or pin a version
const coordinator = defineAgent({
agent: {
slug: "coordinator",
model,
system: "Ask the reviewer to check claims.",
subagents: [{
agent: researcher,
name: "reviewer",
description: "Check factual claims against primary evidence.",
version: 3
}]
}
})Without a wrapper, the roster name is the referenced agent's slug and the
description comes from its definition, falling back to the slug. Set a useful
description so the model knows when to delegate. Omitting version resolves the
latest version when a child is spawned; a pin must already exist in the target
environment. Syncing an agent creates its current version, not an arbitrary
historical pin.
External and derived agents
Existing wire references still work alongside local objects:
subagents: [
researcher,
{ kind: "agent", name: "billing", agent: "billing-service", description: "Handle billing questions." },
{ kind: "derived", name: "review", extends: "parent", description: "Review the result." }
]String references are external: initialization does not register them. Use object references for agents in the same deployment. Development channel transport applies the same namespace to the registered agents and their object references.
coordinator.init() initializes its referenced agents before itself, and the parent's
handlers can serve their separate routes. Use createAgentRouter to group independent
agents. Construct routers before serving requests and use one router per agent instance.
Initialization is sequential across dependencies and is not a transaction: a server
failure can leave initialized dependencies in place. A later action retries failed work.
Call agents.close() during shutdown to stop the group's outbound channels.
Delegation itself follows the same sub-agent policies as a roster authored through the API.