Docs
Architecture Overview

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:

  1. Rate limit check against the team's plan limits (lib/utils/usage.ts)
  2. Promise.all([determineAgentRoute(), createConversation(), saveUserMessage()]) — these run in parallel
  3. executeAgent(domain, messages, team, conversationId, modelId?) dispatches to the correct agent
  4. The agent streams back a StreamTextResult via toUIMessageStreamResponse()
  5. The x-conversation-id response header is set (new conversations get a fresh ID)
  6. 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 its onFinish callback
  • This inserts the assistant message into the messages table with all tool call/result parts as JSONB
  • The Asset Interceptor (lib/ai/utils.ts) intercepts tool outputs and bulk-inserts rows into assets

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

FileRole
lib/ai/orchestrator.tsdetermineAgentRoute() + executeAgent()
lib/ai/agents/registry.tsAGENT_REGISTRY — the list of all agents and their routing descriptions
lib/ai/agents/*.tsIndividual agent implementations
lib/ai/tools/shared/*.tsAll tool definitions
lib/ai/utils.tssaveAgentResponse(), ASSET_REGISTRY, asset persistence
app/api/assistant/router/route.tsThe main chat API endpoint