Orchestrator & Routing
How determineAgentRoute() classifies intent and routes to the right agent.
How the Router Works
The orchestrator makes a single generateText call with structured output (Output.object) to classify the user's intent:
// lib/ai/orchestrator.ts
const result = await generateText({
model: openai("gpt-4o-mini"),
temperature: 0,
messages: await convertToModelMessages(messages),
system: `
You are the core Orchestrator Router. Your ONLY job is to analyze the user's message and determine the domain.
Today's date is ${today}.
Domains:
${Object.entries(AGENT_REGISTRY)
.map(([key, meta]) => `- ${key}: ${meta.description}`)
.join("\n")}
Return the chosen domain.
`,
output: Output.object({
schema: z.object({
domain: z.enum(routingKeys),
}),
}),
});temperature: 0 makes routing deterministic. The model receives only a list of domain keys and their descriptions — nothing else.
The Fast-Path Bypass
If the frontend passes a valid agentId (other than "general"), the LLM routing step is skipped entirely:
if (
requestedAgentId &&
requestedAgentId !== "general" &&
Object.values(AGENT_REGISTRY).some((agent) => agent.id === requestedAgentId)
) {
return { domain: requestedAgentId as AgentId, usage: null };
}This is the correct approach for dedicated agent pages — zero routing latency, zero token cost.
The AGENT_REGISTRY
All routing is driven by the description field in AGENT_REGISTRY:
// lib/ai/agents/registry.ts
export const AGENT_REGISTRY = {
"content-creation": {
id: "content-creation",
name: "Content Strategist",
description: "Expert at writing copy, SEO, and generating social assets.",
icon: "PenTool",
},
"reel-generator": {
id: "reel-generator",
name: "Reel Generator",
description:
"Creates complete short-form video content packages for Instagram Reels, TikTok, and YouTube Shorts.",
icon: "Video",
},
// ...
} as const;
export type AgentId = keyof typeof AGENT_REGISTRY;The description is used verbatim in the routing system prompt. It is the only thing the router sees about each agent — write it carefully.
Function Signatures
// Determines which agent should handle the request
async function determineAgentRoute(
messages: UIMessage[],
requestedAgentId?: string,
): Promise<{ domain: AgentId; usage: any }>
// Dispatches to the correct agent implementation
async function executeAgent(
domain: AgentId,
messages: UIMessage[],
team: any,
conversationId: string,
modelId?: string,
): Promise<StreamTextResult<any, any>>usage is null on the fast path (no LLM call made).
Date Injection
Today's date is injected into the routing prompt (Today's date is ${today}) to prevent the model from making date-sensitive routing errors (e.g., misidentifying a time-sensitive news request).