Project 6: Personal AI Command Center
The Synthesis Project - Everything you have learned comes together here
Learning Objectives
By completing this project, you will master:
- Multi-agent orchestration - Design and implement a system where multiple specialized agents collaborate to complete complex tasks, understanding when to use sequential vs. parallel execution patterns
- Agent-to-agent communication - Build shared context stores and message passing mechanisms that allow agents to exchange information, results, and delegate subtasks
- Task decomposition and planning - Implement an orchestration layer that breaks natural language requests into executable plans, selecting appropriate agents and managing dependencies
- Concurrent streaming in web UIs - Create React components that stream responses from multiple agents simultaneously while maintaining UI responsiveness
- Provider abstraction at scale - Route different agents to optimal models based on task requirements, cost constraints, and performance characteristics
- Production cost management - Implement rate limiting, usage tracking, and budget controls across multiple agents and providers
- Full-stack AI application architecture - Integrate CLI, web dashboard, and API interfaces into a cohesive system with proper error handling and observability
Deep Theoretical Foundation
Before building a multi-agent system, you must deeply understand the patterns that make them work. This section explores the theory behind each major component.
Multi-Agent Orchestration Patterns
Multi-agent systems come in several architectural patterns, each with distinct tradeoffs:
┌────────────────────────────────────────────────────────────────────────────┐
│ MULTI-AGENT ORCHESTRATION PATTERNS │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ PATTERN 1: CENTRALIZED ORCHESTRATOR │
│ ───────────────────────────────────── │
│ │
│ ┌─────────────────┐ │
│ │ Orchestrator │ ◄─── Single brain │
│ │ (Planner) │ controls all │
│ └────────┬────────┘ │
│ │ │
│ ┌─────────────────┼─────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Agent A │ │ Agent B │ │ Agent C │ │
│ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ Pros: Simple to reason about, clear control flow │
│ Cons: Single point of failure, orchestrator bottleneck │
│ Use when: Tasks have clear decomposition, agents don't need to negotiate │
│ │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ PATTERN 2: HIERARCHICAL DELEGATION │
│ ───────────────────────────────── │
│ │
│ ┌─────────────────┐ │
│ │ Supervisor │ ◄─── High-level planning │
│ └────────┬────────┘ │
│ │ │
│ ┌─────────────────┴─────────────────┐ │
│ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ │
│ │ Manager │ │ Manager │ ◄─── Domain managers │
│ │ A │ │ B │ │
│ └────┬────┘ └────┬────┘ │
│ │ │ │
│ ┌────┴────┐ ┌────┴────┐ │
│ ▼ ▼ ▼ ▼ │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │Worker│ │Worker│ │Worker│ │Worker│ ◄─── Task executors │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
│ │
│ Pros: Scales well, domain expertise isolation │
│ Cons: Complex communication, latency accumulates │
│ Use when: Large systems, clear domain boundaries │
│ │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ PATTERN 3: PEER-TO-PEER COLLABORATION │
│ ───────────────────────────────────── │
│ │
│ ┌─────────┐ ┌─────────┐ │
│ │ Agent A │◄───────►│ Agent B │ │
│ └────┬────┘ └────┬────┘ │
│ │ │ │
│ │ ┌─────────┐ │ │
│ └───►│ Agent C │◄───┘ │
│ └─────────┘ │
│ │
│ Pros: Flexible, resilient to failures, emergent behavior │
│ Cons: Hard to debug, unpredictable execution │
│ Use when: Creative tasks, exploration, research │
│ │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ PATTERN 4: PIPELINE (Sequential Chain) │
│ ───────────────────────────────────── │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Agent A │────►│ Agent B │────►│ Agent C │────►│ Agent D │ │
│ │ (Input) │ │(Process)│ │(Process)│ │(Output) │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
│ │
│ Pros: Predictable, easy to test, clear data flow │
│ Cons: Slow (serial), no parallelism │
│ Use when: Data transformation, document processing │
│ │
└────────────────────────────────────────────────────────────────────────────┘
For the Personal AI Command Center, we use Pattern 1 (Centralized Orchestrator) because:
- Tasks have clear decomposition (“research X, then email Y”)
- Agents have distinct responsibilities that rarely overlap
- We need predictable execution for cost tracking
- Debugging requires clear visibility into control flow
Agent-to-Agent Communication Strategies
Agents need to share information. There are three primary strategies:
┌────────────────────────────────────────────────────────────────────────────┐
│ AGENT COMMUNICATION STRATEGIES │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ STRATEGY 1: SHARED CONTEXT STORE (Blackboard Pattern) │
│ ───────────────────────────────────────────────────── │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Agent A │ │ Agent B │ │ Agent C │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ write │ read │ │
│ ▼ ▼ ▼ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ SHARED CONTEXT STORE │ │
│ │ ┌──────────────────────────────────────────────────┐ │ │
│ │ │ research_results: { facts: [...], sources: [...] }│ │ │
│ │ │ user_preferences: { tone: "formal", ... } │ │ │
│ │ │ task_context: { goal: "summarize research", ... } │ │ │
│ │ │ conversation_history: [ ... ] │ │ │
│ │ └──────────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ Implementation: In-memory Map, Redis, or database │
│ Pros: Simple, decoupled agents │
│ Cons: Requires coordination on data format │
│ │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ STRATEGY 2: MESSAGE PASSING │
│ ────────────────────────── │
│ │
│ ┌─────────┐ ┌─────────┐ │
│ │ Agent A │───message()───►│ Agent B │ │
│ └────┬────┘ └────┬────┘ │
│ │ │ │
│ │◄────response()───────────┘ │
│ │
│ Messages: { type: 'task', payload: {...}, from: 'research', to: 'email' }│
│ │
│ Implementation: Event emitters, message queues │
│ Pros: Explicit communication, traceable │
│ Cons: Tighter coupling between agents │
│ │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ STRATEGY 3: ORCHESTRATOR MEDIATION │
│ ────────────────────────────────── │
│ │
│ ┌─────────┐ ┌─────────┐ │
│ │ Agent A │◄─────────────────────────────────►│ Agent B │ │
│ └────┬────┘ └────┬────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ ORCHESTRATOR │ │
│ │ • Receives output from Agent A │ │
│ │ • Transforms/filters as needed │ │
│ │ • Passes to Agent B as input │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ Implementation: Orchestrator manages all data flow │
│ Pros: Full control, easy to modify handoffs │
│ Cons: Orchestrator becomes complex │
│ │
└────────────────────────────────────────────────────────────────────────────┘
We use a hybrid approach: Shared Context Store + Orchestrator Mediation. The orchestrator controls execution flow while agents read/write to a shared context for accumulated knowledge.
Task Decomposition and Planning
The orchestrator’s core job is to transform natural language into an executable plan:
┌────────────────────────────────────────────────────────────────────────────┐
│ TASK DECOMPOSITION PIPELINE │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ User Input: "Research quantum computing, then draft an email to │
│ my team summarizing the key points" │
│ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ STEP 1: INTENT EXTRACTION (generateObject) │ │
│ │ │ │
│ │ Schema: { │ │
│ │ primaryIntent: "compose_email" | "research" | "schedule" | ..., │ │
│ │ secondaryIntents: [...], │ │
│ │ entities: { topic: string, recipient: string, ... }, │ │
│ │ constraints: { deadline?: Date, tone?: string, ... } │ │
│ │ } │ │
│ │ │ │
│ │ Output: { │ │
│ │ primaryIntent: "compose_email", │ │
│ │ secondaryIntents: ["research"], │ │
│ │ entities: { topic: "quantum computing", recipient: "team" }, │ │
│ │ constraints: { tone: "professional" } │ │
│ │ } │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ STEP 2: AGENT SELECTION │ │
│ │ │ │
│ │ Agent Registry: │ │
│ │ ┌─────────────┬────────────────────────────────────────────────┐ │ │
│ │ │ Agent │ Capabilities │ │ │
│ │ ├─────────────┼────────────────────────────────────────────────┤ │ │
│ │ │ research │ search, read, extract, summarize │ │ │
│ │ │ email │ compose, send, list, search_inbox │ │ │
│ │ │ calendar │ schedule, check_availability, invite │ │ │
│ │ │ code │ review, explain, refactor, test │ │ │
│ │ └─────────────┴────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ Matching: "research" → research agent, "compose_email" → email │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ STEP 3: DEPENDENCY ANALYSIS │ │
│ │ │ │
│ │ "Research THEN email" → research must complete before email │ │
│ │ │ │
│ │ Dependency Graph: │ │
│ │ │ │
│ │ ┌──────────────┐ │ │
│ │ │ research │ │ │
│ │ │ agent │ │ │
│ │ └──────┬───────┘ │ │
│ │ │ output: research_results │ │
│ │ ▼ │ │
│ │ ┌──────────────┐ │ │
│ │ │ email │ ◄── input: research_results │ │
│ │ │ agent │ │ │
│ │ └──────────────┘ │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ STEP 4: EXECUTION PLAN GENERATION │ │
│ │ │ │
│ │ { │ │
│ │ steps: [ │ │
│ │ { │ │
│ │ id: "step_1", │ │
│ │ agent: "research", │ │
│ │ action: "research_topic", │ │
│ │ input: { topic: "quantum computing" }, │ │
│ │ outputKey: "research_results" │ │
│ │ }, │ │
│ │ { │ │
│ │ id: "step_2", │ │
│ │ agent: "email", │ │
│ │ action: "compose_email", │ │
│ │ input: { │ │
│ │ content: "{{research_results}}", │ │
│ │ recipient: "team", │ │
│ │ tone: "professional" │ │
│ │ }, │ │
│ │ dependsOn: ["step_1"] │ │
│ │ } │ │
│ │ ] │ │
│ │ } │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────────┘
The key insight from “Artificial Intelligence: A Modern Approach” (Russell & Norvig, Ch. 2): agents are defined by their percepts (what they sense) and actions (what they can do). The orchestrator’s job is to match user intent to agent capabilities.
Shared Context Stores and Memory
Effective multi-agent systems require persistent memory that survives across agent invocations:
┌────────────────────────────────────────────────────────────────────────────┐
│ CONTEXT STORE ARCHITECTURE │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ CONTEXT STORE LAYERS │ │
│ ├─────────────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ LAYER 1: SESSION CONTEXT (volatile, per-request) │ │
│ │ ────────────────────────────────────────────── │ │
│ │ • Current task plan │ │
│ │ • Intermediate results from agents │ │
│ │ • Error states and retries │ │
│ │ │ │
│ │ Storage: In-memory Map │ │
│ │ Lifetime: Single multi-agent execution │ │
│ │ │ │
│ ├─────────────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ LAYER 2: CONVERSATION CONTEXT (short-term) │ │
│ │ ────────────────────────────────────────── │ │
│ │ • Recent messages (last N turns) │ │
│ │ • Current user goal │ │
│ │ • Active agent states │ │
│ │ │ │
│ │ Storage: In-memory with optional Redis backup │ │
│ │ Lifetime: User session (minutes to hours) │ │
│ │ │ │
│ ├─────────────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ LAYER 3: USER CONTEXT (long-term) │ │
│ │ ───────────────────────────────── │ │
│ │ • User preferences (communication tone, email signature) │ │
│ │ • Learned patterns (frequently used agents, common requests) │ │
│ │ • Contact information, calendars │ │
│ │ │ │
│ │ Storage: Database (SQLite, Postgres) │ │
│ │ Lifetime: Persistent across sessions │ │
│ │ │ │
│ ├─────────────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ LAYER 4: KNOWLEDGE BASE (accumulated knowledge) │ │
│ │ ───────────────────────────────────────────── │ │
│ │ • Research results indexed by topic │ │
│ │ • Code snippets and explanations │ │
│ │ • Email templates and drafts │ │
│ │ │ │
│ │ Storage: Vector database (for semantic search) │ │
│ │ Lifetime: Permanent, grows over time │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ CONTEXT FLOW DURING EXECUTION: │
│ │
│ User Request │
│ │ │
│ ▼ │
│ ┌──────────────┐ Load user prefs ┌──────────────┐ │
│ │ Orchestrator │ ◄────────────────────── │ User Context │ │
│ └──────┬───────┘ └──────────────┘ │
│ │ │
│ │ Create session context │
│ ▼ │
│ ┌──────────────┐ │
│ │ Session │ │
│ │ Context │◄───── Intermediate results written here │
│ └──────┬───────┘ │
│ │ │
│ │ Agent reads context, executes, writes results │
│ ▼ │
│ ┌──────────────┐ Save knowledge ┌──────────────┐ │
│ │ Agent │────────────────────────►│ Knowledge │ │
│ │ Output │ │ Base │ │
│ └──────────────┘ └──────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────────┘
This layered approach is inspired by “Designing Data-Intensive Applications” (Kleppmann, Ch. 11), which discusses event sourcing and state management in distributed systems.
Concurrent Streaming in Web UIs
Streaming multiple agent responses simultaneously requires careful React architecture:
┌────────────────────────────────────────────────────────────────────────────┐
│ CONCURRENT STREAMING ARCHITECTURE │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ BROWSER SERVER │
│ ─────── ────── │
│ │
│ ┌──────────────────────────────────────┐ ┌────────────────────────┐ │
│ │ React Dashboard │ │ Next.js API Route │ │
│ │ │ │ │ │
│ │ ┌─────────────────────────────────┐ │ │ Orchestrator creates │ │
│ │ │ AgentStreamManager │ │ │ execution plan: │ │
│ │ │ │ │ │ │ │
│ │ │ activeStreams: Map<string, │ │ │ Step 1: Research │ │
│ │ │ ReadableStream> │ │ │ Step 2: Email │ │
│ │ │ │ │ │ │ │
│ │ │ ┌───────────────────────────┐ │ │ │ For parallel steps, │ │
│ │ │ │ useAgentStream('research')│ │ │ │ multiple SSE streams │ │
│ │ │ │ - text: "Searching..." │ │◄├─────┤ are created │ │
│ │ │ │ - status: "streaming" │ │ │ │ │ │
│ │ │ └───────────────────────────┘ │ │ └────────────────────────┘ │
│ │ │ │ │ │
│ │ │ ┌───────────────────────────┐ │ │ SSE Stream Format: │
│ │ │ │ useAgentStream('email') │ │ │ ───────────────── │
│ │ │ │ - text: "" │ │ │ event: agent_start │
│ │ │ │ - status: "pending" │ │ │ data: {"agent":"research"} │
│ │ │ └───────────────────────────┘ │ │ │
│ │ │ │ │ event: agent_token │
│ │ └─────────────────────────────────┘ │ data: {"agent":"research", │
│ │ │ "token":"Quantum"} │
│ │ ┌─────────────────────────────────┐ │ │
│ │ │ Render Components │ │ event: agent_complete │
│ │ │ │ │ data: {"agent":"research", │
│ │ │ <ResearchAgentCard │ │ "result":{...}} │
│ │ │ stream={researchStream} │ │ │
│ │ │ status="streaming" /> │ │ event: agent_start │
│ │ │ │ │ data: {"agent":"email"} │
│ │ │ <EmailAgentCard │ │ │
│ │ │ stream={emailStream} │ │ ... │
│ │ │ status="pending" /> │ │ │
│ │ │ │ │ │
│ │ └─────────────────────────────────┘ │ │
│ │ │ │
│ └──────────────────────────────────────┘ │
│ │
│ KEY REACT PATTERNS (from "Learning React" Ch. 8, 12): │
│ │
│ 1. useReducer for complex stream state │
│ 2. useSyncExternalStore for SSE subscription │
│ 3. Suspense boundaries for loading states │
│ 4. Error boundaries for agent failures │
│ 5. React.memo for preventing unnecessary re-renders │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Cost Management and Rate Limiting
Production AI systems must control costs across multiple agents and providers:
┌────────────────────────────────────────────────────────────────────────────┐
│ COST MANAGEMENT ARCHITECTURE │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ COST TRACKING LAYERS │ │
│ ├─────────────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ LAYER 1: REQUEST LEVEL │ │
│ │ ───────────────────── │ │
│ │ │ │
│ │ Each LLM call records: │ │
│ │ { │ │
│ │ requestId: "req_abc123", │ │
│ │ agentId: "research", │ │
│ │ provider: "anthropic", │ │
│ │ model: "claude-opus-4", │ │
│ │ inputTokens: 1500, │ │
│ │ outputTokens: 800, │ │
│ │ cost: 0.0234, // calculated from token counts │ │
│ │ latency: 2340, // ms │ │
│ │ timestamp: "2025-12-26T10:34:00Z" │ │
│ │ } │ │
│ │ │ │
│ ├─────────────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ LAYER 2: AGENT LEVEL │ │
│ │ ──────────────────── │ │
│ │ │ │
│ │ Aggregated per agent: │ │
│ │ ┌────────────┬──────────┬──────────┬─────────┬───────────────┐ │ │
│ │ │ Agent │ Requests │ Tokens │ Cost │ Avg Latency │ │ │
│ │ ├────────────┼──────────┼──────────┼─────────┼───────────────┤ │ │
│ │ │ research │ 145 │ 892,400 │ $12.30 │ 3.2s │ │ │
│ │ │ email │ 89 │ 234,500 │ $5.20 │ 1.8s │ │ │
│ │ │ calendar │ 67 │ 98,200 │ $2.15 │ 0.9s │ │ │
│ │ │ code │ 34 │ 456,700 │ $3.80 │ 4.1s │ │ │
│ │ └────────────┴──────────┴──────────┴─────────┴───────────────┘ │ │
│ │ │ │
│ ├─────────────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ LAYER 3: BUDGET CONTROLS │ │
│ │ ──────────────────────── │ │
│ │ │ │
│ │ Per-Agent Budgets: Global Budgets: │ │
│ │ ┌────────────┬──────────┐ ┌────────────────────────────────┐ │ │
│ │ │ Agent │ Daily $ │ │ Daily limit: $50.00 │ │ │
│ │ ├────────────┼──────────┤ │ Monthly limit: $500.00 │ │ │
│ │ │ research │ $10.00 │ │ Alert at: 80% threshold │ │ │
│ │ │ email │ $5.00 │ │ Action: Notify + degrade│ │ │
│ │ │ calendar │ $3.00 │ └────────────────────────────────┘ │ │
│ │ │ code │ $8.00 │ │ │
│ │ └────────────┴──────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ RATE LIMITING STRATEGY: │
│ │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Token Bucket Algorithm (per provider): │ │
│ │ │ │
│ │ ┌──────────────┐ │ │
│ │ │ Bucket │ capacity: 100 requests │ │
│ │ │ ●●●●●●●●●● │ refill: 10 requests/second │ │
│ │ │ ●●●●●●● │ current: 17 tokens │ │
│ │ └──────────────┘ │ │
│ │ │ │
│ │ When bucket empty: Queue requests OR fallback to cheaper model │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ │
│ GRACEFUL DEGRADATION: │
│ │
│ Budget exceeded? │
│ ├── Option 1: Switch to cheaper model (gpt-4o → gpt-4o-mini) │
│ ├── Option 2: Reduce max tokens │
│ ├── Option 3: Queue non-urgent requests │
│ └── Option 4: Notify user and pause │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Event-Driven Architecture for Agents
The AI SDK’s telemetry and event system enables powerful observability:
┌────────────────────────────────────────────────────────────────────────────┐
│ EVENT-DRIVEN AGENT ARCHITECTURE │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ "Designing Data-Intensive Applications" (Kleppmann, Ch. 11) teaches: │
│ • Events as first-class citizens │
│ • Event sourcing for auditability │
│ • Stream processing for real-time analytics │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ EVENT FLOW │ │
│ ├─────────────────────────────────────────────────────────────────────┤ │
│ │ │ │
│ │ User Request │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────┐ │ │
│ │ │ Orchestrator│──────► EVENT: task_started │ │
│ │ └──────┬──────┘ { task_id, user_input, timestamp } │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────┐ │ │
│ │ │ Planner │──────► EVENT: plan_created │ │
│ │ └──────┬──────┘ { task_id, steps: [...], agents: [...] } │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────┐ │ │
│ │ │ Agent │──────► EVENT: agent_started │ │
│ │ │ Executor │ { task_id, agent_id, step_id } │ │
│ │ │ │ │ │
│ │ │ │──────► EVENT: llm_request │ │
│ │ │ │ { agent_id, provider, model, prompt } │ │
│ │ │ │ │ │
│ │ │ │──────► EVENT: llm_token (streaming) │ │
│ │ │ │ { agent_id, token } │ │
│ │ │ │ │ │
│ │ │ │──────► EVENT: tool_called │ │
│ │ │ │ { agent_id, tool_name, args } │ │
│ │ │ │ │ │
│ │ │ │──────► EVENT: agent_completed │ │
│ │ └──────┬──────┘ { agent_id, result, tokens, cost } │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────┐ │ │
│ │ │ Aggregator │──────► EVENT: task_completed │ │
│ │ └─────────────┘ { task_id, total_cost, latency } │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ EVENT CONSUMERS: │
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Dashboard │ │ Cost Tracker │ │ Log Storage │ │
│ │ (Real-time) │ │ (Aggregation) │ │ (Audit) │ │
│ │ │ │ │ │ │ │
│ │ Subscribes to: │ │ Subscribes to: │ │ Subscribes to: │ │
│ │ • agent_started │ │ • llm_request │ │ • ALL events │ │
│ │ • llm_token │ │ • agent_complete│ │ │ │
│ │ • agent_complete│ │ │ │ Storage: S3, │ │
│ │ │ │ Computes: │ │ ClickHouse │ │
│ │ Updates: │ │ • Running total │ │ │ │
│ │ • Live streams │ │ • Budget alerts │ │ │ │
│ │ • Agent status │ │ • Usage reports │ │ │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Complete Project Specification
Web Dashboard Requirements
The web dashboard is the primary interface for monitoring and interacting with your AI Command Center.
Functional Requirements:
- Agent Status Panel
- Display all registered agents with real-time status (idle, processing, error)
- Show current task for active agents
- Indicate which model/provider each agent uses
- Conversation Interface
- Natural language input field
- Display orchestrator’s execution plan before running
- Stream agent responses in real-time
- Show handoffs between agents visually
- Activity Feed
- Chronological log of all agent actions
- Filter by agent, date, task type
- Click to expand full details
- Cost Dashboard
- Real-time cost tracking per agent
- Daily/weekly/monthly views
- Budget progress bars with alerts
- Cost breakdown by provider and model
- Settings Panel
- Configure agent preferences (models, system prompts)
- Set budget limits
- Manage API keys (securely)
- User preferences (tone, email signature)
CLI Interface Requirements
The CLI provides power-user access to all Command Center functionality.
Commands:
# Natural language interaction
ai "Research quantum computing and email summary to team"
# Direct agent invocation
ai research "quantum computing"
ai email draft --to "team" --subject "Research Summary"
ai calendar schedule "Team meeting" --time "tomorrow 2pm"
ai code review PR#123
# System management
ai status # Show all agents and their status
ai logs --agent research # View agent logs
ai cost --period month # Show cost breakdown
ai config set research.model claude-opus-4 # Configure agents
# Interactive mode
ai interactive # REPL for multi-turn conversations
API Endpoints
RESTful API following best practices from “Design and Build Great Web APIs” (Amundsen, Ch. 3-5).
┌────────────────────────────────────────────────────────────────────────────┐
│ API ENDPOINT DESIGN │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ BASE: /api/v1 │
│ │
│ TASKS (Orchestrated multi-agent workflows) │
│ ──────────────────────────────────────────── │
│ POST /tasks Create new task (natural language input) │
│ GET /tasks List all tasks (with filters) │
│ GET /tasks/:id Get task status and results │
│ DELETE /tasks/:id Cancel running task │
│ GET /tasks/:id/stream SSE stream for real-time updates │
│ │
│ AGENTS (Direct agent access) │
│ ──────────────────────────── │
│ GET /agents List all agents with capabilities │
│ GET /agents/:id Get agent details and status │
│ POST /agents/:id/invoke Invoke agent directly │
│ GET /agents/:id/stream SSE stream for agent output │
│ │
│ CONTEXT (Shared context management) │
│ ──────────────────────────────────── │
│ GET /context Get current context store │
│ PUT /context Update context │
│ DELETE /context/:key Remove context entry │
│ │
│ ANALYTICS (Cost and usage tracking) │
│ ──────────────────────────────────── │
│ GET /analytics/costs Cost breakdown (by agent, provider, time) │
│ GET /analytics/usage Usage statistics │
│ GET /analytics/logs Event logs │
│ │
│ EXAMPLE REQUEST/RESPONSE: │
│ ───────────────────────── │
│ │
│ POST /api/v1/tasks │
│ Content-Type: application/json │
│ │
│ { │
│ "input": "Research quantum computing, then email summary to team", │
│ "options": { │
│ "stream": true, │
│ "maxCost": 1.00, │
│ "priority": "normal" │
│ } │
│ } │
│ │
│ Response (202 Accepted): │
│ { │
│ "taskId": "task_abc123", │
│ "status": "planning", │
│ "streamUrl": "/api/v1/tasks/task_abc123/stream", │
│ "plan": { │
│ "steps": [ │
│ { "agent": "research", "action": "research_topic" }, │
│ { "agent": "email", "action": "compose_email" } │
│ ], │
│ "estimatedCost": 0.45, │
│ "estimatedTime": "30s" │
│ } │
│ } │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Agent Registry
Each agent must be registered with its capabilities, tools, and configuration:
interface AgentDefinition {
id: string; // e.g., "research", "email"
name: string; // Human-readable name
description: string; // What this agent does
// Capabilities for orchestrator matching
capabilities: string[]; // e.g., ["search", "summarize", "extract"]
// Tools available to this agent
tools: Tool[]; // AI SDK tool definitions
// Model configuration
defaultModel: string; // e.g., "claude-opus-4"
fallbackModel?: string; // Cheaper alternative for budget limits
// System prompt
systemPrompt: string;
// Cost controls
maxTokensPerRequest?: number;
budgetLimit?: {
daily: number;
monthly: number;
};
}
Real World Outcome
Web Dashboard in Action
┌─────────────────────────────────────────────────────────────────────────────┐
│ Personal AI Command Center [Dashboard] │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ACTIVE AGENTS RECENT ACTIVITY │
│ ───────────── ─────────────── │
│ Research Agent [Idle] 10:34 Drafted email to team │
│ Email Agent [Processing...] 10:32 Research completed │
│ Calendar Agent [Idle] 10:28 Scheduled meeting │
│ Code Helper [Idle] 10:15 Reviewed PR #234 │
│ │
│ ───────────────────────────────────────────────────────────────────────── │
│ │
│ CURRENT TASK: Drafting email summary of quantum research │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Email Agent streaming... │ │
│ │ │ │
│ │ Subject: Quantum Computing Research Summary │ │
│ │ │ │
│ │ Hi Team, │ │
│ │ │ │
│ │ I wanted to share some exciting findings from my research on_ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ───────────────────────────────────────────────────────────────────────── │
│ │
│ COST TRACKING (This Month) │
│ ─────────────────────────── │
│ Total: $23.45 │
│ |-- Research Agent: $12.30 (Claude Opus) │
│ |-- Email Agent: $5.20 (GPT-4) │
│ |-- Calendar Agent: $2.15 (GPT-3.5) │
│ +-- Code Helper: $3.80 (Claude Sonnet) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
CLI Interaction
$ ai "Research quantum computing, then draft an email to my team summarizing it"
Orchestrator analyzing task...
Execution plan:
1. Research Agent -> gather quantum computing info
2. Email Agent -> draft summary email
[Research Agent] Starting research...
[Research Agent] Completed (12 facts gathered)
[Email Agent] Drafting email...
[Email Agent] Draft ready
Would you like me to send this email? [y/N]
API Integration Example
# Create a task via API
curl -X POST http://localhost:3000/api/v1/tasks \
-H "Content-Type: application/json" \
-d '{"input": "Research quantum computing and email summary to team"}'
# Stream results
curl -N http://localhost:3000/api/v1/tasks/task_abc123/stream
Solution Architecture
Full System Architecture
┌─────────────────────────────────────────────────────────────────────────────┐
│ AI COMMAND CENTER ARCHITECTURE │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ USER INTERFACES │
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Web Dashboard │ │ CLI │ │ REST API │ │
│ │ (Next.js) │ │ (Node.js) │ │ (Next.js) │ │
│ └────────┬─────────┘ └────────┬─────────┘ └────────┬─────────┘ │
│ │ │ │ │
│ └─────────────────────┼─────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ ORCHESTRATION LAYER │ │
│ │ │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ │
│ │ │ Task Planner │ │ Agent Selector │ │ Execution Engine │ │ │
│ │ │ │ │ │ │ │ │ │
│ │ │ • Parse intent │ │ • Match caps │ │ • Run agents │ │ │
│ │ │ • Extract deps │ │ • Check budgets │ │ • Handle errors │ │ │
│ │ │ • Build plan │ │ • Route models │ │ • Aggregate │ │ │
│ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │
│ │ │ │
│ └───────────────────────────────┬──────────────────────────────────────┘ │
│ │ │
│ ┌────────────────────────┼────────────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Research │ │ Email │ │ Calendar │ │
│ │ Agent │ │ Agent │ │ Agent │ │
│ │ │ │ │ │ │ │
│ │ Tools: │ │ Tools: │ │ Tools: │ │
│ │ • search │ │ • compose │ │ • schedule │ │
│ │ • read_page │ │ • send │ │ • check │ │
│ │ • extract │ │ • list │ │ • invite │ │
│ │ • summarize │ │ • search │ │ • cancel │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ │ ┌─────────────┐ │ │
│ │ │ Code │ │ │
│ │ │ Helper │ │ │
│ │ │ │ │ │
│ │ │ Tools: │ │ │
│ │ │ • review │ │ │
│ │ │ • explain │ │ │
│ │ │ • refactor │ │ │
│ │ │ • test │ │ │
│ │ └──────┬──────┘ │ │
│ │ │ │ │
│ └────────────────────────┴────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ SHARED CONTEXT STORE │ │
│ │ │ │
│ │ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ │
│ │ │ Session │ │ Conversation │ │ User │ │ │
│ │ │ Context │ │ History │ │ Preferences │ │ │
│ │ └───────────────┘ └───────────────┘ └───────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ PROVIDER ABSTRACTION LAYER │ │
│ │ │ │
│ │ ┌─────────┐ ┌───────────┐ ┌──────────┐ ┌──────────────────┐ │ │
│ │ │ OpenAI │ │ Anthropic │ │ Google │ │ Local (Ollama) │ │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ │ GPT-4 │ │ Claude │ │ Gemini │ │ Llama, Mistral │ │ │
│ │ │ GPT-4o │ │ Opus/ │ │ Pro/ │ │ │ │ │
│ │ │ │ │ Sonnet │ │ Flash │ │ │ │ │
│ │ └─────────┘ └───────────┘ └──────────┘ └──────────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ OBSERVABILITY & ANALYTICS │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Event │ │ Cost │ │ Log │ │ │
│ │ │ Stream │ │ Tracker │ │ Storage │ │ │
│ │ │ (SSE) │ │ │ │ │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Orchestration Layer Design
┌────────────────────────────────────────────────────────────────────────────┐
│ ORCHESTRATION LAYER DETAIL │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ INPUT: "Research quantum computing, then email summary to team" │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ STEP 1: TASK PLANNER │ │
│ │ │ │
│ │ Uses generateObject with planning schema: │ │
│ │ │ │
│ │ const planSchema = z.object({ │ │
│ │ intent: z.string(), │ │
│ │ steps: z.array(z.object({ │ │
│ │ action: z.string(), │ │
│ │ agentHint: z.string().optional(), │ │
│ │ dependsOn: z.array(z.string()).optional(), │ │
│ │ input: z.record(z.unknown()) │ │
│ │ })) │ │
│ │ }); │ │
│ │ │ │
│ │ OUTPUT: │ │
│ │ { │ │
│ │ intent: "research_and_email", │ │
│ │ steps: [ │ │
│ │ { action: "research", input: { topic: "quantum computing" } }, │ │
│ │ { action: "email", input: { content: "{{step_1}}" }, │ │
│ │ dependsOn: ["step_1"] } │ │
│ │ ] │ │
│ │ } │ │
│ └────────────────────────────────────┬────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ STEP 2: AGENT SELECTOR │ │
│ │ │ │
│ │ Agent Registry: │ │
│ │ ┌──────────────┬────────────────────────────────────────────────┐ │ │
│ │ │ ID │ Capabilities │ │ │
│ │ ├──────────────┼────────────────────────────────────────────────┤ │ │
│ │ │ research │ research, search, summarize, extract │ │ │
│ │ │ email │ email, compose, send, draft │ │ │
│ │ │ calendar │ schedule, meeting, availability, invite │ │ │
│ │ │ code │ review, explain, refactor, test, debug │ │ │
│ │ └──────────────┴────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ Matching: "research" action → research agent │ │
│ │ "email" action → email agent │ │
│ │ │ │
│ │ Model Selection (based on budget + task complexity): │ │
│ │ • Research (complex reasoning) → Claude Opus │ │
│ │ • Email (straightforward) → GPT-4o-mini │ │
│ │ │ │
│ └────────────────────────────────────┬────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ STEP 3: EXECUTION ENGINE │ │
│ │ │ │
│ │ Execution Plan: │ │
│ │ │ │
│ │ ┌───────────────────────┐ │ │
│ │ │ Step 1: Research │ │ │
│ │ │ Agent: research │ │ │
│ │ │ Model: claude-opus-4 │ │ │
│ │ │ Input: {topic} │ │ │
│ │ │ Output → context.step1│ │ │
│ │ └───────────┬───────────┘ │ │
│ │ │ depends on │ │
│ │ ▼ │ │
│ │ ┌───────────────────────┐ │ │
│ │ │ Step 2: Email │ │ │
│ │ │ Agent: email │ │ │
│ │ │ Model: gpt-4o-mini │ │ │
│ │ │ Input: {context.step1}│ │ │
│ │ │ Output → result │ │ │
│ │ └───────────────────────┘ │ │
│ │ │ │
│ │ For each step: │ │
│ │ 1. Check budget (abort if exceeded) │ │
│ │ 2. Resolve input variables from context │ │
│ │ 3. Invoke agent with streamText │ │
│ │ 4. Emit events for UI/logging │ │
│ │ 5. Write output to context │ │
│ │ 6. Handle errors (retry or abort) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Agent Registry and Discovery
┌────────────────────────────────────────────────────────────────────────────┐
│ AGENT REGISTRY DESIGN │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ // agents/registry.ts │
│ │
│ const agentRegistry = new Map<string, AgentDefinition>(); │
│ │
│ // Registration │
│ registerAgent({ │
│ id: 'research', │
│ name: 'Research Agent', │
│ description: 'Searches the web and extracts information', │
│ capabilities: ['search', 'research', 'summarize', 'extract'], │
│ tools: [searchTool, readPageTool, extractTool], │
│ defaultModel: 'claude-opus-4', │
│ fallbackModel: 'gpt-4o-mini', │
│ systemPrompt: `You are a research assistant...`, │
│ budgetLimit: { daily: 10.00 } │
│ }); │
│ │
│ // Discovery │
│ function findAgentForCapability(capability: string): AgentDefinition { │
│ for (const agent of agentRegistry.values()) { │
│ if (agent.capabilities.includes(capability)) { │
│ return agent; │
│ } │
│ } │
│ throw new Error(`No agent found for capability: ${capability}`); │
│ } │
│ │
│ // Capability matching for orchestrator │
│ function matchAgents(actions: string[]): Map<string, AgentDefinition> { │
│ const matches = new Map(); │
│ for (const action of actions) { │
│ matches.set(action, findAgentForCapability(action)); │
│ } │
│ return matches; │
│ } │
│ │
└────────────────────────────────────────────────────────────────────────────┘
File Structure Recommendation (Monorepo)
ai-command-center/
├── package.json # Workspace root
├── turbo.json # Turborepo config
├── pnpm-workspace.yaml
│
├── apps/
│ ├── web/ # Next.js dashboard
│ │ ├── app/
│ │ │ ├── page.tsx # Main dashboard
│ │ │ ├── layout.tsx
│ │ │ ├── api/
│ │ │ │ ├── tasks/
│ │ │ │ │ ├── route.ts # POST /tasks
│ │ │ │ │ └── [id]/
│ │ │ │ │ ├── route.ts
│ │ │ │ │ └── stream/route.ts
│ │ │ │ ├── agents/
│ │ │ │ │ ├── route.ts
│ │ │ │ │ └── [id]/route.ts
│ │ │ │ └── analytics/
│ │ │ │ └── route.ts
│ │ │ └── settings/
│ │ │ └── page.tsx
│ │ ├── components/
│ │ │ ├── AgentCard.tsx
│ │ │ ├── AgentStream.tsx
│ │ │ ├── CostDashboard.tsx
│ │ │ ├── TaskInput.tsx
│ │ │ └── ActivityFeed.tsx
│ │ └── lib/
│ │ └── hooks/
│ │ ├── useAgentStream.ts
│ │ └── useTaskExecution.ts
│ │
│ └── cli/ # CLI application
│ ├── package.json
│ ├── src/
│ │ ├── index.ts # Main entry
│ │ ├── commands/
│ │ │ ├── task.ts # ai "prompt"
│ │ │ ├── research.ts # ai research
│ │ │ ├── email.ts # ai email
│ │ │ ├── calendar.ts # ai calendar
│ │ │ ├── code.ts # ai code
│ │ │ ├── status.ts # ai status
│ │ │ └── config.ts # ai config
│ │ └── lib/
│ │ ├── api-client.ts # HTTP client to API
│ │ └── stream.ts # SSE handling
│ └── bin/
│ └── ai # Executable
│
├── packages/
│ ├── core/ # Shared core logic
│ │ ├── package.json
│ │ └── src/
│ │ ├── orchestrator/
│ │ │ ├── index.ts
│ │ │ ├── planner.ts
│ │ │ ├── executor.ts
│ │ │ └── types.ts
│ │ ├── agents/
│ │ │ ├── registry.ts
│ │ │ ├── base-agent.ts
│ │ │ ├── research-agent.ts
│ │ │ ├── email-agent.ts
│ │ │ ├── calendar-agent.ts
│ │ │ └── code-agent.ts
│ │ ├── context/
│ │ │ ├── store.ts
│ │ │ └── types.ts
│ │ ├── providers/
│ │ │ ├── index.ts
│ │ │ └── model-router.ts
│ │ └── analytics/
│ │ ├── cost-tracker.ts
│ │ └── event-emitter.ts
│ │
│ ├── tools/ # Shared tool definitions
│ │ ├── package.json
│ │ └── src/
│ │ ├── search.ts
│ │ ├── email.ts
│ │ ├── calendar.ts
│ │ └── code.ts
│ │
│ └── schemas/ # Shared Zod schemas
│ ├── package.json
│ └── src/
│ ├── task.ts
│ ├── agent.ts
│ ├── plan.ts
│ └── analytics.ts
│
├── .env.example
└── README.md
Phased Implementation Guide
Phase 1: Single Agent End-to-End (Week 1)
Goal: Get one agent (Research) working completely, from CLI input to streaming output.
┌────────────────────────────────────────────────────────────────────────────┐
│ PHASE 1: SINGLE AGENT │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ DELIVERABLES: │
│ • Research agent with search and summarize tools │
│ • Simple CLI: ai research "topic" │
│ • Basic streaming output │
│ │
│ ARCHITECTURE: │
│ │
│ CLI Input │
│ │ │
│ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Research Agent │────►│ AI SDK Tools │ │
│ │ │ │ • search │ │
│ │ streamText() │ │ • read_page │ │
│ │ maxSteps: 10 │ └─────────────────┘ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ Terminal Output (streaming) │
│ │
│ IMPLEMENTATION STEPS: │
│ 1. Set up monorepo with pnpm workspaces │
│ 2. Create packages/core with base agent class │
│ 3. Implement research agent with 2 tools │
│ 4. Create CLI with single command │
│ 5. Add basic error handling │
│ │
│ SUCCESS CRITERIA: │
│ $ ai research "quantum computing" │
│ > Searching for quantum computing... │
│ > Found 5 sources... │
│ > Quantum computing uses quantum mechanics... │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Key Code: Base Agent Class
// packages/core/src/agents/base-agent.ts
import { streamText, CoreTool } from 'ai';
export abstract class BaseAgent {
abstract id: string;
abstract name: string;
abstract systemPrompt: string;
abstract tools: Record<string, CoreTool>;
protected model: LanguageModelV1;
constructor(model: LanguageModelV1) {
this.model = model;
}
async *execute(input: string): AsyncGenerator<string> {
const { textStream } = await streamText({
model: this.model,
system: this.systemPrompt,
prompt: input,
tools: this.tools,
maxSteps: 10,
});
for await (const chunk of textStream) {
yield chunk;
}
}
}
Phase 2: Orchestration Layer (Week 2)
Goal: Add the orchestrator that can decompose tasks and select agents.
┌────────────────────────────────────────────────────────────────────────────┐
│ PHASE 2: ORCHESTRATION │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ DELIVERABLES: │
│ • Task planner using generateObject │
│ • Agent registry with capability matching │
│ • Execution engine for sequential steps │
│ • Second agent (Email) to test multi-agent flow │
│ │
│ ARCHITECTURE: │
│ │
│ "Research X, then email Y" │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Task Planner │ ─── generateObject(planSchema) │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Agent Selector │ ─── Match capabilities to agents │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Executor │────►│ Research Agent │ ─── Step 1 │
│ │ │ └────────┬────────┘ │
│ │ │ │ result │
│ │ │ ▼ │
│ │ │ ┌─────────────────┐ │
│ │ │────►│ Email Agent │ ─── Step 2 (uses step 1) │
│ └─────────────────┘ └─────────────────┘ │
│ │
│ IMPLEMENTATION STEPS: │
│ 1. Create orchestrator with generateObject planner │
│ 2. Build agent registry with registration/discovery │
│ 3. Implement sequential executor │
│ 4. Create email agent with compose tool │
│ 5. Wire up CLI to orchestrator │
│ │
│ SUCCESS CRITERIA: │
│ $ ai "Research AI safety, then draft email to team" │
│ > Planning task... │
│ > Step 1: Research Agent - researching AI safety │
│ > Step 2: Email Agent - drafting email │
│ > Done! Email draft ready. │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Key Code: Orchestrator
// packages/core/src/orchestrator/index.ts
export class Orchestrator {
private planner: TaskPlanner;
private registry: AgentRegistry;
private executor: ExecutionEngine;
async execute(input: string): AsyncGenerator<OrchestratorEvent> {
// Step 1: Plan
const plan = await this.planner.plan(input);
yield { type: 'plan_created', plan };
// Step 2: Select agents
const agentMap = this.registry.matchCapabilities(plan.steps);
// Step 3: Execute
for (const step of plan.steps) {
const agent = agentMap.get(step.action);
yield { type: 'agent_started', agentId: agent.id };
for await (const token of agent.execute(step.input)) {
yield { type: 'agent_token', agentId: agent.id, token };
}
yield { type: 'agent_completed', agentId: agent.id };
}
}
}
Phase 3: Shared Context (Week 3)
Goal: Implement context store so agents can share information.
┌────────────────────────────────────────────────────────────────────────────┐
│ PHASE 3: SHARED CONTEXT │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ DELIVERABLES: │
│ • Multi-layer context store (session, conversation, user) │
│ • Context injection into agent prompts │
│ • Result passing between agents │
│ • Context persistence (file-based initially) │
│ │
│ ARCHITECTURE: │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ CONTEXT STORE │ │
│ │ │ │
│ │ Session Layer (Map) │ │
│ │ ├── task_plan: {...} │ │
│ │ ├── step_1_result: "Research found..." │ │
│ │ └── current_step: 2 │ │
│ │ │ │
│ │ Conversation Layer (Array) │ │
│ │ ├── { role: "user", content: "Research..." } │ │
│ │ └── { role: "assistant", content: "Found..." } │ │
│ │ │ │
│ │ User Layer (Persistent) │ │
│ │ ├── preferences: { tone: "formal" } │ │
│ │ └── email_signature: "Best, John" │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ AGENT CONTEXT INJECTION: │
│ │
│ Research Agent Email Agent │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ System Prompt + │ │ System Prompt + │ │
│ │ User Preferences│ │ User Preferences│ │
│ │ │ │ + Step 1 Result │ │
│ │ Input: "topic" │ │ │ │
│ │ │ │ Input: "draft" │ │
│ │ Output ─────────┼──────────────┼►Context │ │
│ └─────────────────┘ └─────────────────┘ │
│ │
│ IMPLEMENTATION STEPS: │
│ 1. Create context store interface │
│ 2. Implement session context (in-memory) │
│ 3. Add context to agent base class │
│ 4. Modify executor to pass results via context │
│ 5. Add user preferences layer with file persistence │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Phase 4: Web Dashboard (Week 4)
Goal: Build the Next.js dashboard with real-time streaming.
┌────────────────────────────────────────────────────────────────────────────┐
│ PHASE 4: WEB DASHBOARD │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ DELIVERABLES: │
│ • Next.js app with agent status panel │
│ • SSE streaming for real-time updates │
│ • Task input and execution UI │
│ • Activity feed │
│ │
│ COMPONENT HIERARCHY: │
│ │
│ <Dashboard> │
│ ├── <AgentStatusPanel> │
│ │ └── <AgentCard agent={...} status={...} /> │
│ ├── <TaskInterface> │
│ │ ├── <TaskInput onSubmit={...} /> │
│ │ ├── <ExecutionPlan plan={...} /> │
│ │ └── <AgentStreamPanel> │
│ │ └── <AgentStream agentId={...} stream={...} /> │
│ ├── <ActivityFeed events={...} /> │
│ └── <CostDashboard costs={...} /> │
│ │
│ SSE STREAMING PATTERN: │
│ │
│ // app/api/tasks/[id]/stream/route.ts │
│ export async function GET(req, { params }) { │
│ const stream = new ReadableStream({ │
│ async start(controller) { │
│ for await (const event of orchestrator.execute()) { │
│ controller.enqueue( │
│ `event: ${event.type}\ndata: ${JSON.stringify(event)}\n\n` │
│ ); │
│ } │
│ controller.close(); │
│ } │
│ }); │
│ return new Response(stream, { │
│ headers: { 'Content-Type': 'text/event-stream' } │
│ }); │
│ } │
│ │
│ // hooks/useAgentStream.ts │
│ function useAgentStream(taskId: string) { │
│ const [streams, setStreams] = useState({}); │
│ useEffect(() => { │
│ const eventSource = new EventSource(`/api/tasks/${taskId}/stream`); │
│ eventSource.onmessage = (e) => { ... }; │
│ return () => eventSource.close(); │
│ }, [taskId]); │
│ return streams; │
│ } │
│ │
│ IMPLEMENTATION STEPS: │
│ 1. Set up Next.js app with Tailwind │
│ 2. Create API routes for tasks │
│ 3. Implement SSE streaming endpoint │
│ 4. Build React components with streaming hooks │
│ 5. Style dashboard │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Phase 5: CLI Interface (Week 5)
Goal: Polish CLI with all commands and interactive mode.
┌────────────────────────────────────────────────────────────────────────────┐
│ PHASE 5: CLI INTERFACE │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ DELIVERABLES: │
│ • Full CLI with all agent commands │
│ • Interactive REPL mode │
│ • Configuration management │
│ • Status and logs commands │
│ │
│ COMMAND STRUCTURE: │
│ │
│ ai │
│ ├── <prompt> Natural language task │
│ ├── research <topic> Direct research agent │
│ ├── email │
│ │ ├── draft Draft an email │
│ │ ├── send Send drafted email │
│ │ └── list List recent emails │
│ ├── calendar │
│ │ ├── schedule Schedule event │
│ │ ├── check Check availability │
│ │ └── list List upcoming events │
│ ├── code │
│ │ ├── review Review code/PR │
│ │ └── explain Explain code │
│ ├── status Show agent status │
│ ├── logs [--agent] View logs │
│ ├── cost [--period] View costs │
│ ├── config │
│ │ ├── get <key> Get config value │
│ │ ├── set <key> <val> Set config value │
│ │ └── list List all config │
│ └── interactive Start REPL │
│ │
│ CLI IMPLEMENTATION (using Commander.js): │
│ │
│ // apps/cli/src/index.ts │
│ import { Command } from 'commander'; │
│ import { createApiClient } from './lib/api-client'; │
│ │
│ const program = new Command(); │
│ const api = createApiClient('http://localhost:3000/api/v1'); │
│ │
│ program │
│ .name('ai') │
│ .description('Personal AI Command Center') │
│ .argument('[prompt]', 'Natural language task') │
│ .action(async (prompt) => { │
│ if (prompt) { │
│ const stream = await api.createTask(prompt); │
│ for await (const event of stream) { │
│ renderEvent(event); │
│ } │
│ } │
│ }); │
│ │
│ program │
│ .command('research <topic>') │
│ .description('Research a topic') │
│ .action(async (topic) => { ... }); │
│ │
│ INTERACTIVE MODE: │
│ │
│ $ ai interactive │
│ AI Command Center v1.0.0 │
│ Type 'help' for commands, 'exit' to quit │
│ │
│ > Research AI safety │
│ [Research Agent] Searching... │
│ ... │
│ > Now email that to the team │
│ [Email Agent] Drafting email with research context... │
│ ... │
│ > exit │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Phase 6: Cost Tracking and Polish (Week 6+)
Goal: Add production-ready cost management, testing, and polish.
┌────────────────────────────────────────────────────────────────────────────┐
│ PHASE 6: PRODUCTION POLISH │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ DELIVERABLES: │
│ • Cost tracking with budget alerts │
│ • Rate limiting per provider │
│ • Graceful degradation │
│ • Comprehensive error handling │
│ • Telemetry and logging │
│ • Documentation │
│ │
│ COST TRACKING IMPLEMENTATION: │
│ │
│ // packages/core/src/analytics/cost-tracker.ts │
│ export class CostTracker { │
│ private costs: Map<string, AgentCosts> = new Map(); │
│ private limits: BudgetLimits; │
│ │
│ recordUsage(event: LLMUsageEvent) { │
│ const cost = this.calculateCost(event); │
│ this.updateAgentCosts(event.agentId, cost); │
│ this.checkBudgetLimits(); │
│ this.emit('cost_recorded', { agentId, cost }); │
│ } │
│ │
│ private calculateCost(event: LLMUsageEvent): number { │
│ const rates = PROVIDER_RATES[event.provider][event.model]; │
│ return (event.inputTokens * rates.input / 1000) + │
│ (event.outputTokens * rates.output / 1000); │
│ } │
│ │
│ private checkBudgetLimits() { │
│ const today = this.getTodayCosts(); │
│ if (today > this.limits.daily * 0.8) { │
│ this.emit('budget_warning', { percent: 80 }); │
│ } │
│ if (today >= this.limits.daily) { │
│ this.emit('budget_exceeded', { type: 'daily' }); │
│ } │
│ } │
│ } │
│ │
│ GRACEFUL DEGRADATION: │
│ │
│ orchestrator.on('budget_warning', async () => { │
│ // Switch expensive agents to fallback models │
│ agentRegistry.get('research').useModel = 'fallback'; │
│ }); │
│ │
│ orchestrator.on('budget_exceeded', async () => { │
│ // Notify user, pause non-critical tasks │
│ await notifyUser('Daily budget exceeded'); │
│ orchestrator.pause(); │
│ }); │
│ │
│ TELEMETRY (using AI SDK built-in): │
│ │
│ const { text } = await generateText({ │
│ model, │
│ prompt, │
│ experimental_telemetry: { │
│ isEnabled: true, │
│ functionId: 'research-agent', │
│ metadata: { agentId: 'research', taskId } │
│ } │
│ }); │
│ │
│ FINAL CHECKLIST: │
│ [ ] All agents working with tools │
│ [ ] Orchestration handles complex multi-agent tasks │
│ [ ] Context persists across conversation │
│ [ ] Web dashboard streams in real-time │
│ [ ] CLI provides full functionality │
│ [ ] Cost tracking accurate and alerts work │
│ [ ] Errors handled gracefully │
│ [ ] Tests pass │
│ [ ] Documentation complete │
│ │
└────────────────────────────────────────────────────────────────────────────┘
Testing Strategy
Agent Isolation Testing
Test each agent independently before integration:
// __tests__/agents/research-agent.test.ts
describe('ResearchAgent', () => {
let agent: ResearchAgent;
let mockModel: MockLanguageModel;
beforeEach(() => {
mockModel = createMockModel();
agent = new ResearchAgent(mockModel);
});
test('should search and summarize a topic', async () => {
mockModel.setResponses([
{ toolCalls: [{ name: 'search', args: { query: 'quantum' } }] },
{ text: 'Quantum computing uses quantum mechanics...' }
]);
const result = await collectStream(agent.execute('Research quantum computing'));
expect(result).toContain('quantum');
expect(mockModel.toolCalls).toHaveLength(1);
});
test('should handle search failures gracefully', async () => {
mockModel.setToolError('search', new Error('Network error'));
const result = await collectStream(agent.execute('Research X'));
expect(result).toContain('Unable to search');
});
});
Orchestration Testing
Test the planning and execution flow:
// __tests__/orchestrator/planner.test.ts
describe('TaskPlanner', () => {
test('should decompose multi-step task', async () => {
const planner = new TaskPlanner(mockModel);
const plan = await planner.plan(
'Research quantum computing, then email summary to team'
);
expect(plan.steps).toHaveLength(2);
expect(plan.steps[0].action).toBe('research');
expect(plan.steps[1].action).toBe('email');
expect(plan.steps[1].dependsOn).toContain('step_1');
});
});
// __tests__/orchestrator/executor.test.ts
describe('ExecutionEngine', () => {
test('should execute steps in dependency order', async () => {
const executor = new ExecutionEngine(registry, contextStore);
const executionOrder: string[] = [];
for await (const event of executor.execute(plan)) {
if (event.type === 'agent_started') {
executionOrder.push(event.agentId);
}
}
expect(executionOrder).toEqual(['research', 'email']);
});
test('should pass context between agents', async () => {
const events = await collectEvents(executor.execute(plan));
const emailStartEvent = events.find(
e => e.type === 'agent_started' && e.agentId === 'email'
);
expect(emailStartEvent.context.step_1_result).toBeDefined();
});
});
End-to-End Multi-Agent Testing
Test complete workflows:
// __tests__/e2e/multi-agent-flow.test.ts
describe('Multi-Agent E2E', () => {
let orchestrator: Orchestrator;
let server: TestServer;
beforeAll(async () => {
server = await startTestServer();
orchestrator = new Orchestrator(realProviders);
});
test('research then email workflow', async () => {
const events: OrchestratorEvent[] = [];
for await (const event of orchestrator.execute(
'Research TypeScript best practices, then email summary to me'
)) {
events.push(event);
}
// Verify plan was created
const planEvent = events.find(e => e.type === 'plan_created');
expect(planEvent.plan.steps).toHaveLength(2);
// Verify research completed
const researchComplete = events.find(
e => e.type === 'agent_completed' && e.agentId === 'research'
);
expect(researchComplete.result).toBeDefined();
// Verify email used research context
const emailComplete = events.find(
e => e.type === 'agent_completed' && e.agentId === 'email'
);
expect(emailComplete.result.draft).toContain('TypeScript');
}, 60000); // Long timeout for real API calls
});
Common Pitfalls and Debugging
Pitfall 1: Context Explosion
Problem: Context grows unbounded as agents accumulate results.
Session starts: 1KB
After 5 tasks: 50KB
After 20 tasks: 500KB → Exceeds model context limit!
Solution: Implement context compression and eviction:
class ContextStore {
private maxSize = 50000; // tokens
addResult(key: string, value: string) {
if (this.getTokenCount() > this.maxSize * 0.8) {
this.compressOldestEntries();
}
this.store.set(key, value);
}
private compressOldestEntries() {
// Summarize old results instead of keeping full text
const oldest = this.getOldestEntries(5);
for (const entry of oldest) {
const summary = await summarize(entry.value);
this.store.set(entry.key, `[Summary] ${summary}`);
}
}
}
Pitfall 2: Agent Loops
Problem: Agent gets stuck calling the same tool repeatedly.
Solution: Implement loop detection:
class AgentExecutor {
async execute(agent: Agent, input: string) {
const toolCallHistory: string[] = [];
for await (const step of agent.run(input)) {
if (step.type === 'tool_call') {
const signature = `${step.name}:${JSON.stringify(step.args)}`;
if (toolCallHistory.filter(h => h === signature).length >= 3) {
throw new AgentLoopError(`Agent stuck calling ${step.name}`);
}
toolCallHistory.push(signature);
}
}
}
}
Pitfall 3: Race Conditions in Parallel Execution
Problem: Multiple agents writing to shared context simultaneously.
Solution: Use proper synchronization:
class ContextStore {
private lock = new AsyncLock();
async write(key: string, value: any) {
await this.lock.acquire('context', async () => {
this.store.set(key, value);
});
}
}
Pitfall 4: Streaming Backpressure
Problem: Web client cannot consume tokens as fast as server sends them.
Solution: Implement flow control:
// Server-side
const stream = new ReadableStream({
async pull(controller) {
// Only send when client is ready
const event = await eventQueue.dequeue();
controller.enqueue(formatSSE(event));
}
});
// Client-side
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
// Process at client's pace
await processChunk(decoder.decode(value));
}
Pitfall 5: Cost Estimation Inaccuracy
Problem: Estimated costs differ significantly from actual.
Solution: Track and calibrate:
class CostEstimator {
private calibrationFactor = new Map<string, number>();
estimate(agentId: string, input: string): number {
const baseEstimate = this.calculateBaseEstimate(input);
const factor = this.calibrationFactor.get(agentId) || 1.0;
return baseEstimate * factor;
}
recordActual(agentId: string, estimated: number, actual: number) {
const ratio = actual / estimated;
const current = this.calibrationFactor.get(agentId) || 1.0;
// Exponential moving average
this.calibrationFactor.set(agentId, current * 0.9 + ratio * 0.1);
}
}
Pitfall 6: Tool Argument Validation
Problem: LLM generates invalid tool arguments that pass Zod but fail at runtime.
Solution: Runtime validation layer:
const searchTool = tool({
description: 'Search the web',
parameters: z.object({
query: z.string().min(1).max(200),
}),
execute: async ({ query }) => {
// Additional runtime checks
if (query.includes('..') || query.includes('<script>')) {
throw new InvalidToolArgumentError('Query contains invalid characters');
}
return await search(query);
}
});
Pitfall 7: Memory Leaks in Long-Running Sessions
Problem: Event listeners and streams accumulate over time.
Solution: Proper cleanup:
class TaskExecution {
private cleanupFns: Array<() => void> = [];
async run() {
const eventSource = new EventSource(url);
this.cleanupFns.push(() => eventSource.close());
const interval = setInterval(heartbeat, 30000);
this.cleanupFns.push(() => clearInterval(interval));
// ... execution
}
cleanup() {
for (const fn of this.cleanupFns) {
fn();
}
this.cleanupFns = [];
}
}
Extensions and Challenges
Extension 1: Plugin System for Custom Agents
Create a plugin architecture so users can add their own agents:
// Plugin interface
interface AgentPlugin {
id: string;
name: string;
description: string;
capabilities: string[];
createAgent: (config: AgentConfig) => BaseAgent;
}
// Plugin loader
class PluginLoader {
async loadFromDirectory(dir: string) {
const files = await glob(`${dir}/*.plugin.js`);
for (const file of files) {
const plugin = await import(file);
this.registry.registerPlugin(plugin.default);
}
}
}
// Example plugin: Slack Agent
export default {
id: 'slack',
name: 'Slack Agent',
capabilities: ['message', 'notify', 'channel_summary'],
createAgent: (config) => new SlackAgent(config)
} satisfies AgentPlugin;
Extension 2: Voice Interface
Add voice input/output using Web Speech API:
// Voice input
const recognition = new webkitSpeechRecognition();
recognition.onresult = async (event) => {
const transcript = event.results[0][0].transcript;
await orchestrator.execute(transcript);
};
// Voice output (stream TTS)
async function speakStream(textStream: AsyncIterable<string>) {
const utterance = new SpeechSynthesisUtterance();
let buffer = '';
for await (const chunk of textStream) {
buffer += chunk;
if (buffer.match(/[.!?]\s/)) {
utterance.text = buffer;
speechSynthesis.speak(utterance);
buffer = '';
}
}
}
Extension 3: Multi-User Support
Transform from personal to team command center:
// User context isolation
class MultiTenantOrchestrator {
private userContexts = new Map<string, ContextStore>();
async execute(userId: string, input: string) {
const context = this.getOrCreateContext(userId);
const orchestrator = new Orchestrator({ context });
return orchestrator.execute(input);
}
}
// Shared knowledge base with access control
class SharedKnowledgeBase {
async query(userId: string, query: string) {
const accessibleDocs = await this.getAccessibleDocuments(userId);
return this.vectorSearch(query, { filter: accessibleDocs });
}
}
Extension 4: Workflow Templates
Create reusable multi-agent workflows:
# workflows/weekly-report.yaml
name: Weekly Report
description: Generate weekly status report and email to team
triggers:
- schedule: "0 9 * * FRI"
- command: "generate weekly report"
steps:
- id: gather_tasks
agent: calendar
action: list_events
input:
period: last_week
- id: gather_code
agent: code
action: summarize_commits
input:
period: last_week
- id: draft_report
agent: research
action: synthesize
input:
calendar: "{{gather_tasks.result}}"
code: "{{gather_code.result}}"
template: weekly_report
- id: send_email
agent: email
action: send
input:
to: team
subject: "Weekly Report - {{current_date}}"
body: "{{draft_report.result}}"
Resources
Books
| Topic | Book | Relevant Chapters |
|---|---|---|
| Event-Driven Architecture | “Designing Data-Intensive Applications” by Martin Kleppmann | Ch. 11 (Stream Processing) - for event sourcing and agent communication |
| Multi-Agent Systems | “Artificial Intelligence: A Modern Approach” by Russell & Norvig | Ch. 2 (Intelligent Agents) - agent architecture and design |
| API Design | “Design and Build Great Web APIs” by Mike Amundsen | Ch. 3-5 - RESTful design, hypermedia, versioning |
| React Patterns | “Learning React, 2nd Edition” by Eve Porcello | Ch. 8, 12 - hooks, suspense, concurrent features |
Official Documentation
- AI SDK Documentation
- AI SDK Agent Abstraction
- AI SDK Telemetry
- Next.js App Router
- Server-Sent Events (MDN)
Related Projects for Reference
- LangGraph - Graph-based agent orchestration
- AutoGPT - Autonomous agent framework
- CrewAI - Multi-agent collaboration framework
Self-Assessment Checklist
Use this checklist to verify your understanding. You should be able to answer “yes” to all questions.
Architecture Understanding
- Can you explain why we chose the Centralized Orchestrator pattern over Peer-to-Peer?
- Can you draw the data flow from user input to agent output from memory?
- Can you explain the tradeoffs between message passing and shared context stores?
- Can you describe how the provider abstraction layer enables model flexibility?
Implementation Skills
- Can you implement a new agent from scratch (e.g., a “Notes” agent)?
- Can you add a new tool to an existing agent?
- Can you modify the orchestrator to support parallel agent execution?
- Can you implement rate limiting for a specific provider?
Multi-Agent Concepts
- Can you explain how the orchestrator decomposes “Research X, then email Y”?
- Can you describe how context flows from the research agent to the email agent?
- Can you explain what happens when an agent in the middle of a chain fails?
- Can you describe how to test a multi-agent workflow?
Production Readiness
- Can you implement budget alerts that trigger graceful degradation?
- Can you explain how to debug a failing multi-agent task?
- Can you add a new agent without modifying existing code (plugin pattern)?
- Can you implement context compression to prevent context explosion?
Integration Points
- Can you explain how the CLI and Web dashboard share the same core logic?
- Can you describe the SSE event format for streaming agent output?
- Can you implement a new API endpoint following the existing patterns?
- Can you add telemetry to track agent performance?
Synthesis Questions
- How does this project use concepts from Project 1 (Expense Tracker)?
- Answer: Schema-based structured output for task planning
- How does this project use concepts from Project 2 (Document Summarizer)?
- Answer: Real-time streaming for agent output display
- How does this project use concepts from Project 3 (Code Review Agent)?
- Answer: Tool calling and agent loops for autonomous execution
- How does this project use concepts from Project 4 (Model Router)?
- Answer: Provider abstraction for routing agents to optimal models
- How does this project use concepts from Project 5 (Research Agent)?
- Answer: Memory and context persistence across agent interactions
Connections to Previous Projects
This synthesis project ties together everything you have learned:
┌────────────────────────────────────────────────────────────────────────────┐
│ PROJECT KNOWLEDGE SYNTHESIS │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ PROJECT 1: Expense Tracker CLI │
│ ───────────────────────────── │
│ • generateObject for structured task planning │
│ • Zod schemas for type-safe agent definitions │
│ • CLI patterns with Commander.js │
│ │ │
│ ▼ │
│ PROJECT 2: Document Summarizer │
│ ────────────────────────────── │
│ • streamText for real-time agent output │
│ • React hooks for consuming streams │
│ • SSE patterns for web dashboard │
│ │ │
│ ▼ │
│ PROJECT 3: Code Review Agent │
│ ──────────────────────────── │
│ • Tool definitions for each agent │
│ • Agent loops (maxSteps, stopWhen) │
│ • Error handling for tool failures │
│ │ │
│ ▼ │
│ PROJECT 4: Multi-Provider Router │
│ ──────────────────────────────── │
│ • Provider abstraction layer │
│ • Model selection based on task/cost │
│ • Fallback and retry patterns │
│ │ │
│ ▼ │
│ PROJECT 5: Autonomous Research Agent │
│ ──────────────────────────────────── │
│ • Memory and context persistence │
│ • Vector storage for knowledge base │
│ • Complex multi-step agent workflows │
│ │ │
│ ▼ │
│ PROJECT 6: AI COMMAND CENTER (This Project) │
│ ─────────────────────────────────────────── │
│ All skills combined into a production multi-agent system │
│ │
└────────────────────────────────────────────────────────────────────────────┘
When you complete this project, you will have:
- Built a complete AI application from scratch
- Implemented multi-agent orchestration
- Created production-ready streaming interfaces
- Managed costs across multiple providers
- Designed for extensibility with plugins
This is the culmination of your AI SDK learning journey. The patterns and principles you learn here will transfer to any AI application you build in the future.