# Subagent System Design **Status:** Draft **Goal:** Enable Ava (orchestrator) to spawn specialized subagents for parallel, token-intensive tasks. ## 1. Architecture Overview ``` ┌─────────────────────────────────────────────────────────────┐ │ Ava (Orchestrator) │ │ Model: claude-sonnet-4.5 (via OpenRouter) │ │ Role: Task decomposition, delegation, synthesis │ │ Memory: Read/Write access │ ├─────────────────────────────────────────────────────────────┤ │ Tools: spawn_subagent, all existing Ava tools │ └───────────────┬───────────────────────────────────────┬─────┘ │ │ ▼ ▼ ┌───────────────────────────┐ ┌───────────────────────────┐ │ Subagent: WebCrawler │ │ Subagent: CodeReviewer │ │ Model: claude-haiku │ │ Model: claude-opus │ │ Tools: web_search, │ │ Tools: read_file, │ │ http_get, │ │ search_codebase, │ │ python_exec │ │ run_bash │ │ Memory: Read-only │ │ Memory: Read-only │ │ Limits: 600s, $0.50 │ │ Limits: 300s, $1.00 │ └───────────────────────────┘ └───────────────────────────┘ ``` ## 2. Key Design Decisions ### 2.1 Hierarchical (No Sub-Subagents) - Subagents cannot spawn their own subagents - Prevents runaway token consumption - Keeps orchestrator in control ### 2.2 Memory Access - **Orchestrator (Ava):** Full read/write to Memory system - **Subagents:** Read-only access to memories - Prevents conflicting memory writes from parallel agents ### 2.3 Model Selection by Role | Role | Model | Rationale | |------|-------|-----------| | Orchestrator | claude-sonnet-4.5 | Balance of capability/cost | | Deep reasoning | claude-opus | Complex analysis, architecture | | Quick tasks | claude-haiku | Fast, cheap for simple lookups | | Code tasks | claude-sonnet | Good code understanding | ### 2.4 Resource Limits (Guardrails) Each subagent has strict limits: - **Timeout:** Max wall-clock time (default: 600s) - **Cost cap:** Max spend in cents (default: 50c) - **Token cap:** Max total tokens (default: 100k) - **Iteration cap:** Max agent loop iterations (default: 20) ### 2.5 Extended Thinking - Configurable per-subagent - Enabled for deep research tasks - Disabled for quick lookups ## 3. Data Types ```haskell -- | Subagent role determines toolset and model data SubagentRole = WebCrawler -- Deep web research | CodeReviewer -- Code analysis, PR review | DataExtractor -- Structured data extraction | Researcher -- General research with web+docs | CustomRole Text -- User-defined role deriving (Show, Eq, Generic) -- | Configuration for spawning a subagent data SubagentConfig = SubagentConfig { subagentRole :: SubagentRole , subagentTask :: Text -- What to accomplish , subagentModel :: Maybe Text -- Override default model , subagentTimeout :: Int -- Seconds (default: 600) , subagentMaxCost :: Double -- Cents (default: 50.0) , subagentMaxTokens :: Int -- Default: 100000 , subagentMaxIterations :: Int -- Default: 20 , subagentExtendedThinking :: Bool , subagentContext :: Maybe Text -- Additional context from orchestrator } deriving (Show, Eq, Generic) -- | Result returned by subagent to orchestrator data SubagentResult = SubagentResult { subagentOutput :: Aeson.Value -- Structured result , subagentSummary :: Text -- Human-readable summary , subagentConfidence :: Double -- 0.0-1.0 confidence score , subagentTokensUsed :: Int , subagentCostCents :: Double , subagentDuration :: Int -- Seconds , subagentIterations :: Int , subagentStatus :: SubagentStatus } deriving (Show, Eq, Generic) data SubagentStatus = SubagentSuccess | SubagentTimeout | SubagentCostExceeded | SubagentError Text deriving (Show, Eq, Generic) ``` ## 4. Tool: spawn_subagent This is the main interface for the orchestrator to spawn subagents. ```haskell spawnSubagentTool :: Engine.Tool spawnSubagentTool = Engine.Tool { toolName = "spawn_subagent" , toolDescription = "Spawn a specialized subagent for a focused task. " <> "Use for tasks that benefit from deep exploration, parallel execution, " <> "or specialized tools. The subagent will iterate until task completion " <> "or resource limits are reached." , toolJsonSchema = ... , toolExecute = executeSpawnSubagent } ``` **Parameters:** ```json { "role": "web_crawler | code_reviewer | data_extractor | researcher | custom", "task": "Research competitor pricing for podcast transcription services", "context": "We're building a pricing page and need market data", "model": "claude-haiku", "timeout": 600, "max_cost_cents": 50, "extended_thinking": false } ``` **Response:** ```json { "status": "success", "summary": "Found 5 competitors with pricing ranging from $0.10-$0.25/min", "output": { "competitors": [ {"name": "Otter.ai", "pricing": "$0.12/min", "features": ["..."]}, ... ] }, "confidence": 0.85, "tokens_used": 45000, "cost_cents": 23.5, "duration_seconds": 180, "iterations": 8 } ``` ## 5. Role-Specific Tool Sets ### 5.1 WebCrawler ```haskell webCrawlerTools :: [Engine.Tool] webCrawlerTools = [ webSearchTool -- Search the web , webReaderTool -- Fetch and parse web pages , pythonExecTool -- Execute Python for data processing ] ``` **Use case:** Deep market research, competitive analysis, documentation gathering ### 5.2 CodeReviewer ```haskell codeReviewerTools :: [Engine.Tool] codeReviewerTools = [ readFileTool , searchCodebaseTool , searchAndReadTool , runBashTool -- For running tests, linters ] ``` **Use case:** PR review, architecture analysis, test verification ### 5.3 DataExtractor ```haskell dataExtractorTools :: [Engine.Tool] dataExtractorTools = [ webReaderTool , pythonExecTool ] ``` **Use case:** Scraping structured data, parsing PDFs, extracting metrics ### 5.4 Researcher ```haskell researcherTools :: [Engine.Tool] researcherTools = [ webSearchTool , webReaderTool , readFileTool , searchCodebaseTool ] ``` **Use case:** General research combining web and local codebase ## 6. Subagent System Prompt Template ``` You are a specialized {ROLE} subagent working on a focused task. ## Your Task {TASK} ## Context from Orchestrator {CONTEXT} ## Your Capabilities {TOOL_DESCRIPTIONS} ## Guidelines 1. Work iteratively: search → evaluate → refine → verify 2. Return structured data when possible (JSON objects) 3. Include confidence scores for your findings 4. If stuck, explain what you tried and what didn't work 5. Stop when you have sufficient information OR hit resource limits ## Output Format When complete, provide: 1. A structured result (JSON) with the requested data 2. A brief summary of findings 3. Confidence score (0.0-1.0) indicating reliability 4. Any caveats or limitations ``` ## 7. Orchestrator Delegation Logic The orchestrator (Ava) should spawn subagents when: 1. **Deep research needed:** "Research all competitors in X market" 2. **Parallel tasks:** Multiple independent subtasks that can run concurrently 3. **Specialized tools:** Task requires tools the orchestrator shouldn't use directly 4. **Token-intensive:** Task would consume excessive tokens in main context The orchestrator should NOT spawn subagents for: 1. **Simple queries:** Quick lookups, single tool calls 2. **Conversation continuation:** Multi-turn dialogue with user 3. **Memory writes:** Tasks that need to update Ava's memory ## 8. Execution Flow ``` 1. Orchestrator calls spawn_subagent tool 2. Subagent module: a. Creates fresh agent config from SubagentConfig b. Selects model based on role (or override) c. Builds tool list for role d. Constructs system prompt e. Calls Engine.runAgentWithProvider f. Monitors resource usage g. Returns SubagentResult 3. Orchestrator receives structured result 4. Orchestrator synthesizes into response ``` ## 9. Concurrency Model Initial implementation: **Sequential** (one subagent at a time) Future enhancement: **Parallel** spawning with: - `async` library for concurrent execution - Aggregate cost tracking across all subagents - Combined timeout for parallel group ```haskell -- Future: Parallel spawning spawnParallel :: [SubagentConfig] -> IO [SubagentResult] spawnParallel configs = mapConcurrently runSubagent configs ``` ## 10. Status Reporting Subagents report status back to the orchestrator via callbacks: ```haskell data SubagentCallbacks = SubagentCallbacks { onSubagentStart :: Text -> IO () -- "Starting web research..." , onSubagentActivity :: Text -> IO () -- "Searching for X..." , onSubagentToolCall :: Text -> Text -> IO () -- Tool name, args , onSubagentComplete :: SubagentResult -> IO () } ``` For Telegram, this appears as: ``` 🔍 Subagent [WebCrawler]: Starting research... 🔍 Subagent [WebCrawler]: Searching "podcast transcription pricing"... 🔍 Subagent [WebCrawler]: Reading otter.ai/pricing... ✅ Subagent [WebCrawler]: Complete (180s, $0.24) ``` ## 11. Implementation Plan ### Phase 1: Core Infrastructure 1. Create `Omni/Agent/Subagent.hs` with data types 2. Implement `runSubagent` function using existing Engine 3. Add `spawn_subagent` tool 4. Basic WebCrawler role with existing web tools ### Phase 2: Role Expansion 1. Add CodeReviewer role 2. Add DataExtractor role 3. Add Researcher role 4. Custom role support ### Phase 3: Advanced Features 1. Parallel subagent execution 2. Extended thinking integration 3. Cross-subagent context sharing 4. Cost aggregation and budgeting ## 12. Testing Strategy ```haskell test :: Test.Tree test = Test.group "Omni.Agent.Subagent" [ Test.unit "SubagentConfig JSON roundtrip" <| ... , Test.unit "role selects correct tools" <| ... , Test.unit "timeout terminates subagent" <| ... , Test.unit "cost limit stops execution" <| ... , Test.unit "WebCrawler role has web tools" <| ... ] ``` ## 13. Cost Analysis Based on Anthropic's research findings: - Subagents use ~15× more tokens than single-agent - But provide better results for complex tasks - 80% of performance variance from token budget **Budget recommendations:** | Task Type | Subagent Budget | Expected Tokens | |-----------|-----------------|-----------------| | Quick lookup | $0.10 | ~10k | | Standard research | $0.50 | ~50k | | Deep analysis | $2.00 | ~200k | ## 14. References - [Claude Agent SDK - Subagents](https://platform.claude.com/docs/en/agent-sdk/subagents) - [Multi-Agent Research System](https://www.anthropic.com/engineering/multi-agent-research-system) - [OpenAI Agents Python](https://openai.github.io/openai-agents-python/agents/) - Existing: `Omni/Agent/Engine.hs`, `Omni/Agent/Provider.hs`, `Omni/Agent/Tools.hs`