Agents
Agents — 9 Specialized Workers
DLRS is not one chatbot. It's 9 narrow agents coordinated by an Orchestrator. Learn each agent's job, tools, permissions, and how to extend them — beginner-friendly with code.
Why Multi-Agent? (Beginner)
Analogy: Specialist Doctors
One general doctor (single LLM) tries to do everything and is mediocre. DLRS has 9 specialists: Inbox doctor for capture, Finance doctor for bank statements. The Orchestrator is the receptionist who routes you to the right specialist.
- Single agent problem: one prompt with 50 tools → confusion, wrong tool, high token cost, permission bleed.
- Multi-agent solution: Inbox Agent has 5 tools, Finance Agent has 4, each prompt narrow and accurate.
- Beginner win: You can test Inbox Agent alone without loading Finance code.
The 9 Agents — What Each Does
| Agent | Input Example | Output | Tools |
|---|---|---|---|
| Inbox Agent | “3 reels for GB by Friday, photos in Drive” | client=GB, 3 tasks, deadline, asset search | classify, extract_entities, link_project |
| Task Agent | All tasks for workspace | Priority scores, at-risk, nextAction | prioritize, detect_blocked, estimate |
| Project Agent | Project health request | Progress 60%, 2 tasks overdue, summary | health, milestones, summarize |
Tool Registry & Permissions
lib/agents/tools.ts
tools = [
{ name: "create_task", risk: "SAFE", input: z.object({ title, project_id, due_date }), handler },
{ name: "send_email", risk: "SENSITIVE", handler }, // needs confirm
{ name: "search_drive", risk: "SAFE" },
...
]
Catalog shown to LLM:
listTools() → [{ name, description, risk, inputSchema }]
Permission matrix:
SAFE: auto-exec (create_task, categorize_email, attach_file)
SENSITIVE: pause → modal "Send this email?" → user confirms → execute
Engine: lib/agents/orchestrator.ts → handleToolCall() checks riskKeyword: Risk vs Permission
risk="SAFE"|"SENSITIVE" in tool definition. Sensitive tool calls are not executed until user clicks Confirm. Logged to activity_log with approved_by.How to Add a New Tool (Steps)
1. Define in lib/agents/tools.ts
{
name: "create_reminder",
description: "Create reminder for task",
risk: "SAFE",
input: z.object({ task_id: z.string(), when: z.string() }),
handler: async (args, { db, ctx }) => {
// ctx.workspaceId enforced here
const reminder = await db.reminder.create({ data: { workspace_id: ctx.workspaceId, task_id: args.task_id, when: new Date(args.when) }})
return reminder
}
}2. Add to agent's allowed list
lib/agents/registry.ts
taskAgents = ["create_task", "update_task", "create_reminder"]3. Add server wrapper (optional for UI)
lib/ai/agent/server-tools.ts
export const createReminder = createReminderDef.server<AgentRuntimeContext>(...)4. Test via Assistant
Ask in /w/[workspace]/assistant: “Remind me about GB reel tomorrow 10am” → orchestrator → Inbox Agent → create_reminder tool.
Cost & Reliability Design
Why Not AI Everywhere?
AI is expensive and non-deterministic. DLRS uses heuristic first, LLM second. Dates, math, cron = TypeScript
date-fns. Only understanding uses LLM. Saves tokens and avoids “2+2=5” errors.- Model:
AGENT_MODEL=claude-3-5-sonnetfor quality,haikufor cheap - Fallback: if no API key, heuristic regex still creates tasks (lower accuracy)
- Limit: max 5 tool calls per turn, loop detection in orchestrator