# Moltbot Orchestrator Feature Specification ## Overview This document specifies the implementation of an **Orchestrator Layer** for Moltbot. The orchestrator acts as an intelligent router that intercepts user messages and decides whether to handle them directly or delegate to specialized agents. ## Goals 1. **Smart Routing**: Use a fast LLM (configurable) to analyze incoming messages and route to appropriate agents 2. **OpenCode Integration**: Enable Moltbot to delegate coding tasks to OpenCode CLI 3. **Parallel Execution**: Support running multiple agents concurrently 4. **Configurable Models**: All agent models should be configurable via `moltbot.json` 5. **Extensible**: Easy to add new specialized agents ## Architecture ``` User Message │ ▼ ┌─────────────────────────────────────────────────────────────┐ │ ORCHESTRATOR (configurable model) │ │ - Default: google-gemini-cli/gemini-3-flash-preview │ │ - System prompt: knows available agents │ │ - Delegation tools: spawn specialized agents │ │ - Decision: handle directly OR delegate │ └────────┬─────────────┬──────────────┬──────────────────────┘ │ │ │ ▼ ▼ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ OpenCode │ │ Embedded Pi │ │ Research │ │ Agent │ │ Agent │ │ Agent │ │ (CLI/HTTP) │ │ (existing) │ │ (web tools) │ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ └─────────────┼──────────────┘ ▼ Result Aggregation ``` ## Configuration Schema Add to `moltbot.json`: ```json5 { "orchestrator": { "enabled": true, "model": "google-gemini-cli/gemini-3-flash-preview", "fallbacks": ["openai-codex/gpt-5.2-codex"], "agents": { "opencode": { "enabled": true, "model": "anthropic/claude-sonnet-4", "mode": "cli", // "cli" | "serve" "binary": "opencode", "timeoutMs": 300000 }, "research": { "enabled": true, "model": "google-gemini-cli/gemini-3-flash-preview" }, "embedded": { "enabled": true, "model": null // null = use agents.defaults.model } }, "parallelExecution": true, "maxParallelAgents": 3 } } ``` ## File Structure ``` src/agents/orchestrator/ ├── index.ts # Main exports ├── types.ts # Type definitions ├── config.ts # Config schema and defaults ├── orchestrator.ts # Main orchestrateUserMessage() ├── prompt.ts # System prompt builder ├── result-aggregator.ts # Combine agent results └── delegation-tools/ ├── index.ts # Tool exports ├── opencode-agent.ts # OpenCode CLI/HTTP integration ├── research-agent.ts # Web search delegation └── embedded-agent.ts # Existing Pi agent delegation ``` ## Implementation Checklist ### Phase 1: Core Infrastructure - [ ] Create feature branch `feature/orchestrator` - [ ] Create `src/agents/orchestrator/` directory structure - [ ] Implement `types.ts` - AgentResult, OrchestratorParams, OrchestratorResponse - [ ] Implement `config.ts` - Config schema with Zod/TypeBox validation - [ ] Add orchestrator config types to `src/config/types.ts` ### Phase 2: Orchestrator Core - [ ] Implement `prompt.ts` - Build orchestrator system prompt - [ ] Implement `orchestrator.ts` - Main orchestration logic - [ ] Implement `result-aggregator.ts` - Combine multiple agent outputs ### Phase 3: Delegation Tools - [ ] Implement `delegation-tools/opencode-agent.ts` - OpenCode CLI integration - [ ] Implement `delegation-tools/research-agent.ts` - Web search delegation - [ ] Implement `delegation-tools/embedded-agent.ts` - Existing agent delegation - [ ] Implement `delegation-tools/index.ts` - Export all tools ### Phase 4: Integration - [ ] Add orchestrator to tool registry in `moltbot-tools.ts` - [ ] Integrate into message handling pipeline - [ ] Add CLI flag for enabling/disabling orchestrator - [ ] Update config migration if needed ### Phase 5: Testing & Documentation - [ ] Add unit tests for orchestrator logic - [ ] Add integration tests for delegation tools - [ ] Add E2E test for full orchestration flow - [ ] Update documentation ### Phase 6: Polish - [ ] Run linter and fix issues - [ ] Run full test suite - [ ] Create PR with changelog entry ## Type Definitions ```typescript // types.ts export interface AgentResult { agentName: string; agentType: "opencode" | "research" | "embedded" | "orchestrator"; status: "success" | "error" | "partial" | "timeout"; output: string; artifacts?: unknown[]; errorMessage?: string; durationMs: number; model?: string; tokenUsage?: { input: number; output: number; }; } export interface OrchestratorParams { userMessage: string; sessionId: string; sessionKey?: string; config?: MoltbotConfig; images?: ImageContent[]; timeoutMs?: number; thinking?: ThinkLevel; } export interface OrchestratorResponse { payloads: Array<{ text: string; isError?: boolean }>; agentResults: AgentResult[]; meta: { durationMs: number; orchestratorModel: string; delegatedAgents: string[]; }; } export interface OrchestratorConfig { enabled: boolean; model: string; fallbacks?: string[]; agents: { opencode?: OpenCodeAgentConfig; research?: ResearchAgentConfig; embedded?: EmbeddedAgentConfig; }; parallelExecution?: boolean; maxParallelAgents?: number; } export interface OpenCodeAgentConfig { enabled: boolean; model?: string; mode: "cli" | "serve"; binary?: string; timeoutMs?: number; servePort?: number; } export interface ResearchAgentConfig { enabled: boolean; model?: string; } export interface EmbeddedAgentConfig { enabled: boolean; model?: string | null; } ``` ## OpenCode Integration Details ### CLI Mode (`opencode run`) ```typescript // Simple one-shot execution async function runOpenCodeCli(message: string, options: OpenCodeAgentConfig): Promise { const args = ["run", message]; if (options.model) { args.push("--model", options.model); } const result = await spawnCommand(options.binary ?? "opencode", args, { timeoutMs: options.timeoutMs ?? 300000, cwd: workspaceDir, }); return { agentName: "OpenCode", agentType: "opencode", status: result.exitCode === 0 ? "success" : "error", output: result.stdout, errorMessage: result.stderr || undefined, durationMs: result.durationMs, model: options.model, }; } ``` ### Serve Mode (Future) ```typescript // Persistent HTTP server for sessions interface OpenCodeServer { port: number; sessionId: string; prompt(message: string): Promise; close(): Promise; } async function getOrCreateOpenCodeServer(sessionId: string): Promise { // Check if server exists for this session // If not, spawn `opencode serve --port ` // Return client connected to the server } ``` ## Orchestrator System Prompt ```typescript // prompt.ts export function buildOrchestratorSystemPrompt(config: OrchestratorConfig): string { const agents = []; if (config.agents.opencode?.enabled) { agents.push(` **OpenCode Agent** (tool: delegate_to_opencode) - Use for: coding tasks, file modifications, debugging, shell commands, git operations - Capabilities: Full IDE-like agent with bash, file editing, LSP, code search - When to use: User asks to write code, modify files, run commands, debug issues`); } if (config.agents.research?.enabled) { agents.push(` **Research Agent** (tool: delegate_to_research) - Use for: web searches, information retrieval, fact-checking - Capabilities: Web search, URL fetching, documentation lookup - When to use: User needs current information, documentation, or research`); } if (config.agents.embedded?.enabled) { agents.push(` **Moltbot Agent** (tool: delegate_to_moltbot) - Use for: general queries, Moltbot-specific features, messaging, scheduling - Capabilities: All Moltbot tools (message, cron, browser, canvas, etc.) - When to use: User asks about Moltbot, messaging, or general assistance`); } return `You are Moltbot's Orchestrator. Your role is to understand user requests and route them to the most appropriate specialized agent(s). ## Available Agents ${agents.join("\n")} ## Decision Rules 1. **Analyze the request**: Understand what the user is asking for 2. **Select agent(s)**: Choose the best agent(s) for the task 3. **Parallel execution**: You can call multiple agents simultaneously if the task benefits from it 4. **Direct response**: For simple greetings or trivial questions, respond directly without delegation ## Response Format - If delegating: Call the appropriate delegation tool(s) - If handling directly: Provide a brief, helpful response - If multiple agents needed: Call multiple tools - they will run in parallel ## Examples User: "Write a Python script to parse JSON" Action: delegate_to_opencode User: "What's the weather in Tokyo?" Action: delegate_to_research User: "Send a message to John saying hello" Action: delegate_to_moltbot User: "Research React best practices and create a component" Action: delegate_to_research AND delegate_to_opencode (parallel) User: "Hello!" Action: Respond directly with a greeting`; } ``` ## Result Aggregation ```typescript // result-aggregator.ts export function aggregateResults(results: AgentResult[]): OrchestratorResponse { const payloads: Array<{ text: string; isError?: boolean }> = []; for (const result of results) { if (result.status === "error") { payloads.push({ text: `**${result.agentName} Error:**\n${result.errorMessage || result.output}`, isError: true, }); } else { payloads.push({ text: results.length > 1 ? `**${result.agentName}:**\n${result.output}` : result.output, }); } } return { payloads, agentResults: results, meta: { durationMs: Math.max(...results.map(r => r.durationMs)), orchestratorModel: "configured-model", delegatedAgents: results.map(r => r.agentType), }, }; } ``` ## Migration Notes - Orchestrator is **opt-in** via `orchestrator.enabled: true` - Default behavior (orchestrator disabled) remains unchanged - Existing `agents.defaults.model` config is preserved - Orchestrator model is separate from agent models ## Future Enhancements 1. **OpenCode serve mode**: Persistent coding sessions with state 2. **Agent chaining**: Sequential agent execution with context passing 3. **Custom agents**: Plugin system for adding new agent types 4. **Learning**: Track which delegations work best and improve routing 5. **Streaming**: Real-time output from delegated agents ## References - OpenCode CLI: https://github.com/anomalyco/opencode - Moltbot Agent Architecture: `src/agents/pi-embedded-runner/` - Existing Subagent Pattern: `src/agents/tools/sessions-spawn-tool.ts`