Architecture Overview
How the three layers — Orchestrator, Agents, and Tools — work together.
The Three-Layer Model
Every user message travels through three layers before a response is streamed back:
Layer 1 — Orchestrator (lib/ai/orchestrator.ts)
A single gpt-4o-mini call at temperature: 0 that classifies intent and returns a domain string (e.g., "reel-generator"). Zero business logic — routing only.
Layer 2 — Agents (lib/ai/agents/)
A ToolLoopAgent (or plain streamText for the general agent) that autonomously calls tools in a loop until it decides to respond with text. Each agent is a self-contained workflow with its own model, tools, and system prompt.
Layer 3 — Tools (lib/ai/tools/shared/)
Pure async functions with a strict Zod inputSchema. Tools cannot call other agents. They return typed outputs that are automatically intercepted and saved by the Asset Interceptor.
Request Lifecycle
Here is the full flow for a single chat request to POST /api/assistant/router:
- Rate limit check against the team's plan limits (
lib/utils/usage.ts) Promise.all([determineAgentRoute(), createConversation(), saveUserMessage()])— these run in parallelexecuteAgent(domain, messages, team, conversationId, modelId?)dispatches to the correct agent- The agent streams back a
StreamTextResultviatoUIMessageStreamResponse() - The
x-conversation-idresponse header is set (new conversations get a fresh ID) - Fire-and-forget:
updateUsage()records token consumption for the team
Database as the Source of Truth
Agents never manually write to the database. Instead:
- Every agent calls
saveAgentResponse(response, context)inside itsonFinishcallback - This inserts the assistant message into the
messagestable with all tool call/result parts as JSONB - The Asset Interceptor (
lib/ai/utils.ts) intercepts tool outputs and bulk-inserts rows intoassets
This means adding a new tool never requires writing any database code — only an entry in ASSET_REGISTRY in lib/ai/utils.ts.
Don't use generateObject anywhere in this codebase. Use generateText with
output: Output.object({schema}) from the Vercel AI SDK. This is the stable
API — generateObject is obsolete.
Key Files
| File | Role |
|---|---|
lib/ai/orchestrator.ts | determineAgentRoute() + executeAgent() |
lib/ai/agents/registry.ts | AGENT_REGISTRY — the list of all agents and their routing descriptions |
lib/ai/agents/*.ts | Individual agent implementations |
lib/ai/tools/shared/*.ts | All tool definitions |
lib/ai/utils.ts | saveAgentResponse(), ASSET_REGISTRY, asset persistence |
app/api/assistant/router/route.ts | The main chat API endpoint |