DLRSDLRS
Agents

Orchestrator — The Manager Agent

The brain that routes “What should I do now?” to the right specialist, builds context packs, and ensures workspace isolation. Beginner to advanced.

What Orchestrator Does

Beginner: One Brain, Many Hands

You talk to one assistant (/w/[workspace]/assistant), but behind it the Orchestrator picks which of 9 agents acts, what tools they can use, and when to ask you for confirmation.

Located: lib/agents/orchestrator.ts. Single entry: runOrchestrator(workspaceId, userInput).

Flow — Intent to Tools

User: "What should I do now?" or Gmail webhook
        │
        ▼
Orchestrator (Step 1: Intent Detection)
  "Is this: create_task? query? set_reminder? finance?"
        │
        ▼
Select Agent(s) — e.g., Task Agent + Calendar Agent
        │
        ▼
Gather Context (Step 2)
  SELECT * FROM tasks WHERE workspace_id = 'my-studio' AND due_date = today
  SELECT * FROM calendar_events WHERE starts_at = today
        │
        ▼
Rank & Propose (Step 3)
  Task scoring 0–100 + available time → "Do GB Reel now (score 88)"
        │
        ▼
Execute Safe Tools (Step 4)
  create_task, search_drive → auto
        │
        ▼
Pause for Sensitive (Step 5)
  send_email → modal: "Send this?" → user confirms → execute
        │
        ▼
Audit & Notify (Step 6)
  Write activity_log, push via Redis → UI badge

Prompt & Context Pack

Each agent gets workspace-scoped context, not full DB dump:

Prompt for Task Agent:
"You are Task Agent for workspace my-studio.
Context Pack for task GB-reel-123:
- client: GB Banquet, project: Social Media, deadline: 2025-12-06, priority: High 84
- checklist: [x] Download [ ] Select [ ] Edit
- related emails: 2, files: GB-logo.png
- user recently asked: 'What should I do now?'
Available tools: create_task, update_task, prioritize
Do not use finance tools."

Token saving: only GB task, not all 200 tasks.

Keyword: Context Pack = Token Efficient

Narrow context → cheaper, more accurate. The orchestrator builds a mini-pack per request, not “send entire DB to LLM”.

Multi-Agent Coordination

User: "Make 3 reels for GB before Saturday"

Orchestrator → Inbox Agent (tools: extract_entities)
  → Returns: 3 tasks JSON

Orchestrator → Task Agent (tools: create_task x3)
  → Creates tasks, returns IDs

Orchestrator → Notification Agent (tool: create_reminder)
  → Schedules 7d/3d/1d reminders

Final: "Created 3 tasks for GB Banquet, due Saturday. Reminders set."

Code Walkthrough

Entry: lib/agents/orchestrator.ts

export async function runOrchestrator(ctx: AgentRuntimeContext, input: string) {
  const intent = await detectIntent(input) // LLM or heuristic
  const agents = selectAgents(intent) // e.g., ["task", "calendar"]
  const contextPack = await buildContextPack(ctx.workspaceId, agents)
  const plan = await planActions(intent, contextPack, agents)
  for (const action of plan) {
    if (action.risk === "SENSITIVE") await askConfirmation(action)
    else await executeTool(action)
  }
}

Tool Execution: lib/agents/tools.ts

tools = registry of { name, risk, input: Zod, handler: (args, { db, ctx }) => result }
// ctx: { workspaceId, userId } — enforced tenancy
handler always does: db.task.findMany({ where: { workspaceId: ctx.workspaceId } })

Tenancy & Safety

// Every DB call in handler:
await db.task.create({ data: { workspace_id: ctx.workspaceId, title: args.title } })

// Check: npm run check:tenancy
// Scans lib/** for `db.*.findMany(` without workspace_id → fails CI

🔒 Design Rule: No Global Queries

If you add a new query, always include workspace_id. The isolation script is the gate. This is why beginners should copy existing handler patterns.

On this page