titan-agent 5.5.22 → 5.5.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -276,6 +276,31 @@ MUST rules:
276
276
  Return: architectural analysis, proposed changes with rationale, implementation summary with file paths.`,
277
277
  maxRounds: 15,
278
278
  tier: "cloud"
279
+ },
280
+ // v5.5.23: 'writer' template moved here from agent_handoff.ts ROLE_MAP.
281
+ // Mirrors the Writer specialist defined in specialists.ts so the spawn_agent
282
+ // tool, agent_delegate tool, and agent_team/chain tools all share one
283
+ // canonical writer prompt. Tools chosen by what specialists.ts gives Writer.
284
+ writer: {
285
+ name: "Writer",
286
+ persona: "voice-clone",
287
+ tools: ["read_file", "write_file", "memory", "web_search", "web_fetch"],
288
+ systemPrompt: `You are the Writer sub-agent. Your job is to draft publication-quality content \u2014 social posts, emails, announcements, short-form copy \u2014 in the requested voice.
289
+
290
+ Available tools and when to use them:
291
+ - web_search / web_fetch: gather context or prior posts when matching a voice
292
+ - read_file / write_file: read briefs, save drafts to files when asked
293
+ - memory: pull stored stylistic preferences and past phrasing
294
+
295
+ MUST rules:
296
+ - MUST match the voice the operator uses in prior posts/messages when one is provided
297
+ - NEVER post publicly \u2014 draft only, return the draft for approval
298
+ - For social posts (Facebook/X), keep under 280 chars unless explicitly asked for long-form. Hook in the first line.
299
+ - Be concise. Cut filler. Strong verbs.
300
+
301
+ Return the final draft as the response. If you saved it to a file, also return the file path.`,
302
+ maxRounds: 6,
303
+ tier: "smart"
279
304
  }
280
305
  };
281
306
  async function spawnSubAgent(config) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/agent/subAgent.ts"],"sourcesContent":["/**\n * TITAN — Universal Sub-Agent\n * Spawns isolated sub-agents that reuse processMessage() with constrained toolsets.\n * Generalizes the swarm.ts pattern into a universal delegation system.\n *\n * Key constraints:\n * - Max depth: 1 (sub-agents cannot spawn sub-sub-agents)\n * - Inherits parent's autonomy mode (can't escalate)\n * - Own stall/loop counters (isolated from parent)\n * - Cost counts toward parent session budget\n */\nimport { chat } from '../providers/router.js';\nimport { executeTools, getToolDefinitions, type ToolResult } from './toolRunner.js';\nimport { loadConfig } from '../config/config.js';\nimport type { ChatMessage, ToolDefinition } from '../providers/base.js';\nimport logger from '../utils/logger.js';\nimport { resolveToolsFromCategories, type ToolCategory } from './toolCategories.js';\nimport { registerMailbox, unregisterMailbox, drainMessages, formatMessagesForContext } from './messageBus.js';\nimport { acquireAgent, releaseAgent, createPooledAgent, type PooledAgent } from './agentPool.js';\nimport { getActivePersonaContent } from '../personas/manager.js';\nimport { assembleSystemPrompt } from './systemPromptParts.js';\n\nconst COMPONENT = 'SubAgent';\n\n/** Currently running sub-agent IDs (Set for accurate tracking, prevents counter desync) */\nconst activeSubAgentIds = new Set<string>();\n\nexport interface SubAgentConfig {\n name: string;\n task: string;\n /** Whitelist of tool names this sub-agent can use. Empty = all tools */\n tools?: string[];\n /** Tool categories — resolved to tool names at runtime */\n toolCategories?: ToolCategory[];\n /** Create a git worktree for filesystem isolation */\n useWorktree?: boolean;\n /** Model override (defaults to fast alias) */\n model?: string;\n /** Model tier — resolved via modelAliases (cloud/smart/fast/local) */\n tier?: ModelTier;\n /** System prompt override */\n systemPrompt?: string;\n /** Persona ID to apply (from assets/personas/). Appended to system prompt. */\n persona?: string;\n /** Max tool rounds for this sub-agent (default: 10) */\n maxRounds?: number;\n /** Max tokens per LLM call for this sub-agent (default: from config) */\n maxTokens?: number;\n /** Whether this is being called from within a sub-agent already */\n isNested?: boolean;\n /** Current nesting depth (0 = top-level sub-agent) */\n depth?: number;\n /** Progress callback: called each round with progress info */\n onProgress?: (round: number, totalRounds: number, agentName: string) => void;\n /** Opt-in to agent pool reuse — warm agents preserve context between tasks */\n reusePool?: boolean;\n /** Working directory for filesystem operations (future: scope file tools) */\n workspaceDir?: string;\n /** Tags for observability / filtering */\n tags?: string[];\n /** Stream callbacks for Agent Watcher — tool_call, tool_end, round events */\n streamCallbacks?: {\n onToolCall?: (name: string, args: Record<string, unknown>) => void;\n onToolResult?: (name: string, result: string, durationMs: number, success: boolean) => void;\n onThinking?: () => void;\n onRound?: (round: number, maxRounds: number) => void;\n };\n}\n\nexport interface SubAgentResult {\n content: string;\n toolsUsed: string[];\n success: boolean;\n durationMs: number;\n rounds: number;\n /** Whether the output passed validation checks */\n validated: boolean;\n}\n\n/**\n * Model tier for each sub-agent template.\n * - 'cloud': Heavy reasoning tasks → uses modelAliases.cloud (big cloud model)\n * - 'smart': Complex tasks → uses modelAliases.smart\n * - 'fast': Quick/simple tasks → uses modelAliases.fast (local)\n * - 'local': Must run locally → uses modelAliases.local\n */\nexport type ModelTier = 'cloud' | 'smart' | 'fast' | 'local';\n\n/** Built-in sub-agent templates with mapped personas */\nexport const SUB_AGENT_TEMPLATES: Record<string, Partial<SubAgentConfig> & { tier?: ModelTier }> = {\n explorer: {\n name: 'Explorer',\n persona: 'context-engineer',\n tools: ['web_search', 'web_fetch', 'browse_url', 'web_read', 'web_act'],\n systemPrompt: `You are the Explorer sub-agent. Your job is to research and gather information from the web using your tools.\n\nAvailable tools and when to use them:\n- web_search: MUST use this first — search for any topic, question, or keyword\n- web_fetch: MUST use after web_search — fetch full page content from the most relevant URLs\n- browse_url: Navigate to a specific URL for interactive content\n- web_read: Extract clean readable text from a URL\n- web_act: Click, scroll, or interact with page elements\n\nMUST rules:\n- MUST call web_search before attempting to answer from memory\n- MUST call web_fetch on at least 2 of the top search result URLs to get full content\n- MUST cross-verify key facts across multiple sources\n\nReturn a structured summary with: key findings, sources (with URLs), and confidence level for main claims.`,\n tier: 'smart',\n },\n coder: {\n name: 'Coder',\n persona: 'incremental-builder',\n tools: ['shell', 'read_file', 'write_file', 'edit_file', 'append_file', 'list_dir', 'code_exec'],\n systemPrompt: `You are the Coder sub-agent. Your job is to WRITE CODE using your tools. Lead with action, not exploration.\n\nCRITICAL RULES:\n- Your FIRST tool call should be write_file (for new files) or read_file (if modifying existing files)\n- Do NOT start with list_dir unless you genuinely don't know the project structure\n- NEVER output code as text — always use write_file or edit_file\n- NEVER describe what you would do — DO IT immediately\n- One sentence of planning max, then CALL THE TOOL\n- After writing files, verify with shell (npm run build, etc.)\n- Keep each edit under 30 lines. For large changes, use multiple edit_file calls\n- Prefer editing existing files over creating new ones\n- No unnecessary comments, error handling, or features beyond scope\n\nTool priority:\n1. write_file — create new files with complete working code\n2. edit_file — modify existing files (read first)\n3. shell — run commands, install packages, verify builds\n4. read_file — only when you need to understand existing code before editing\n5. list_dir — only when you don't know the structure at all\n\nReturn a summary of what was created/modified with exact file paths.`,\n tier: 'smart',\n },\n browser: {\n name: 'Browser',\n persona: 'browser-tester',\n tools: ['browse_url', 'browser_auto_nav', 'browser_search', 'web_read', 'web_act', 'browser_screenshot'],\n systemPrompt: `You are the Browser sub-agent. Your job is to interact with web pages — navigate, extract content, fill forms, and click buttons.\n\nAvailable tools and when to use them:\n- browse_url: MUST use to navigate to a URL before interacting with it\n- browser_screenshot: Take a screenshot to understand the current page state\n- web_read: Extract clean text content from the current page\n- web_act: Click buttons, fill inputs, scroll — use for interactive actions\n- browser_auto_nav: Auto-navigate complex flows (login, multi-step forms)\n- browser_search: Search within a page or site\n\nMUST rules:\n- MUST call browse_url first to open the page\n- MUST call web_read or browser_screenshot to understand page contents before acting\n- MUST report what you found, extracted, or accomplished with exact details\n\nReturn a clear report of what was found/done on the page.`,\n tier: 'fast',\n },\n analyst: {\n name: 'Analyst',\n persona: 'code-reviewer',\n tools: ['web_search', 'web_fetch', 'memory', 'graph_search', 'graph_remember'],\n systemPrompt: `You are the Analyst sub-agent. Your job is to analyze information, identify patterns, and produce structured analytical reports.\n\nAvailable tools and when to use them:\n- web_search: Search for data, statistics, reports, or comparisons\n- web_fetch: Fetch full content from specific URLs for deeper analysis\n- graph_search: Search the knowledge graph for previously stored context\n- graph_remember: Store important findings in the knowledge graph for future reference\n- memory: Store/retrieve key-value data points\n\nMUST rules:\n- MUST call web_search to gather current data before analyzing\n- MUST call graph_search to check for existing relevant context\n- MUST call graph_remember to store key findings after analysis\n- MUST base conclusions on data from tools — not assumptions\n\nReturn a structured analytical report with: executive summary, data findings, patterns identified, confidence levels, and recommendations.`,\n tier: 'cloud',\n },\n researcher: {\n name: 'Researcher',\n persona: 'trend-researcher',\n tools: ['web_search', 'web_read', 'web_fetch', 'rag_search', 'rag_ingest'],\n systemPrompt: `You are the Deep Researcher sub-agent. Your job is to systematically research a question using multiple sources and tools.\n\nAvailable tools and when to use them:\n- web_search: MUST call 2-4 times with different targeted queries to get broad coverage\n- web_fetch: MUST call on the top 3-5 URLs from search results to get full content\n- web_read: Extract clean text from a URL\n- rag_search: Search the local knowledge base for existing research on this topic\n- rag_ingest: Store important findings in the local knowledge base\n\nMethodology — follow in order:\n1. Call rag_search to check for existing research on this topic\n2. Break the question into 2-4 targeted search queries\n3. Call web_search for each query\n4. Call web_fetch on the most relevant URLs (at least 3 total)\n5. Cross-verify key claims across at least 2 independent sources\n6. Call rag_ingest to store important findings\n\nMUST rules:\n- MUST call web_search — never answer research questions from memory\n- MUST call web_fetch to read full content, not just search snippets\n- MUST cite all sources with URLs\n\nOutput format: executive summary → sections with headers → numbered citations [1], [2] → Sources list with URLs.`,\n maxRounds: 15,\n tier: 'cloud',\n },\n // ── Pipeline agents (DeerFlow-inspired) ────────────────────\n reporter: {\n name: 'Reporter',\n persona: 'documentation-writer',\n tools: ['read_file', 'write_file', 'web_fetch'],\n systemPrompt: `You are the Reporter sub-agent. Your job is to synthesize research findings into structured, publication-quality documents saved to disk.\n\nAvailable tools and when to use them:\n- read_file: Read any existing research notes or source files\n- write_file: MUST use to save the final report to disk — NEVER output report content as text\n- web_fetch: Fetch additional content from URLs if needed for a specific section\n\nMUST rules:\n- MUST call write_file to save the report — the output is a file on disk, not inline text\n- MUST call read_file if source material files are referenced in the task\n- If given a file path for the output, MUST save to exactly that path\n\nReport structure: executive summary → sections with markdown headers → confidence levels (High/Medium/Low) per claim → numbered citations → actionable conclusions.`,\n maxRounds: 10,\n tier: 'cloud',\n },\n fact_checker: {\n name: 'Fact Checker',\n persona: 'context-engineer',\n tools: ['web_search', 'web_fetch'],\n systemPrompt: `You are the Fact Checker sub-agent. Your job is to verify specific claims against multiple independent sources.\n\nAvailable tools and when to use them:\n- web_search: MUST call for each claim to find sources that confirm or refute it\n- web_fetch: MUST call to read the full source content — search snippets are not enough\n\nFor each claim:\n1. Call web_search with 2 different queries targeting this claim\n2. Call web_fetch on the top 2 sources for full content\n3. Compare the claim against what each source actually says\n4. Assign: Verified (3+ sources agree) / Likely (2 sources) / Unverified (1 source) / Disputed (sources conflict) / False (sources contradict)\n\nMUST rules:\n- MUST call web_search for every claim — never verify from memory\n- MUST call web_fetch to read full source content\n\nReturn a structured report: claim → status → evidence → sources used.`,\n maxRounds: 10,\n tier: 'smart',\n },\n // ── Dev agents (TITAN_DEV only) ──────────────────────────\n dev_debugger: {\n name: 'Dev Debugger',\n persona: 'debugger',\n tools: ['shell', 'read_file', 'write_file', 'debug_analyze', 'code_analyze'],\n systemPrompt: `You are the Dev Debugger sub-agent for the TITAN framework. Your job is to find and fix bugs by reading actual code and running diagnostic commands.\n\nAvailable tools and when to use them:\n- read_file: MUST use to read the source file containing the error before diagnosing\n- code_analyze: Analyze code structure, find potential issues, check for bugs\n- debug_analyze: Deep analysis of error messages, stack traces, and runtime issues\n- shell: Run the failing code, check logs, reproduce the error, verify the fix\n- write_file: Save the fixed code\n\nMUST rules:\n- MUST call read_file to read the actual source code — never diagnose from assumptions\n- MUST call code_analyze or debug_analyze to systematically identify the root cause\n- MUST call shell to reproduce the error before attempting a fix\n- MUST call shell again after the fix to verify it works\n- MUST call write_file to apply the fix — never describe the fix without implementing it\n\nReturn: root cause analysis, fix applied (with file path), verification result.`,\n maxRounds: 15,\n tier: 'smart',\n },\n dev_tester: {\n name: 'Dev Tester',\n persona: 'tdd-engineer',\n tools: ['shell', 'read_file', 'write_file', 'test_generate', 'code_exec'],\n systemPrompt: `You are the Dev Tester sub-agent for the TITAN framework. Your job is to generate, run, and fix tests using vitest.\n\nAvailable tools and when to use them:\n- read_file: MUST use to read the source code being tested before writing tests\n- test_generate: Generate comprehensive test cases from source code\n- write_file: MUST use to save the test file — never output tests as text\n- shell: Run vitest to execute tests and see results\n- code_exec: Quick isolated code execution for testing snippets\n\nMUST rules:\n- MUST call read_file to understand the code structure before writing tests\n- MUST call write_file to save test files — never output tests inline\n- MUST call shell to run the tests after writing them\n- MUST fix any test failures — don't stop at writing tests\n\nReturn: test file path, number of tests written, test results (pass/fail counts).`,\n maxRounds: 20,\n tier: 'fast',\n },\n dev_reviewer: {\n name: 'Dev Reviewer',\n persona: 'code-reviewer',\n tools: ['shell', 'read_file', 'code_review', 'code_analyze', 'deps_audit'],\n systemPrompt: `You are the Dev Reviewer sub-agent for the TITAN framework. Your job is to perform thorough multi-pass code review.\n\nAvailable tools and when to use them:\n- read_file: MUST use to read each file being reviewed — never review from memory\n- code_analyze: Structural analysis — complexity, patterns, architecture\n- code_review: Deep review — security, logic errors, performance issues\n- deps_audit: Check dependencies for vulnerabilities or outdated packages\n- shell: Run the code, check for type errors, run linter\n\nReview passes (do all):\n1. Security pass: call code_review with security focus\n2. Logic pass: call code_analyze for correctness and edge cases\n3. Performance pass: check for inefficiencies\n4. Dependencies pass: call deps_audit\n\nMUST rules:\n- MUST call read_file for each file reviewed\n- MUST run at least 2 review passes with different focuses\n- Flag real issues only — not style preferences\n\nReturn: structured findings by severity (Critical/Major/Minor), with file + line references.`,\n maxRounds: 10,\n tier: 'cloud',\n },\n dev_architect: {\n name: 'Dev Architect',\n persona: 'backend-architect',\n tools: ['shell', 'read_file', 'write_file', 'code_analyze', 'refactor_suggest', 'doc_generate'],\n systemPrompt: `You are the Dev Architect sub-agent for the TITAN framework. Your job is to analyze system architecture and implement structural improvements.\n\nAvailable tools and when to use them:\n- read_file: MUST use to read source files before proposing architectural changes\n- code_analyze: Analyze codebase structure, dependencies, coupling, and patterns\n- refactor_suggest: Get suggestions for structural improvements and refactoring\n- shell: Run the codebase to understand runtime behavior, check imports, count lines\n- write_file: MUST use to implement changes or create documentation\n- doc_generate: Generate architectural documentation\n\nMUST rules:\n- MUST call read_file and code_analyze before proposing any changes — never guess at structure\n- MUST call shell to understand actual file/folder organization\n- MUST call write_file to implement changes or save documentation — never describe changes inline\n- Think in systems and dependencies, not individual files\n\nReturn: architectural analysis, proposed changes with rationale, implementation summary with file paths.`,\n maxRounds: 15,\n tier: 'cloud',\n },\n};\n\n/**\n * Spawn a sub-agent that runs an isolated agent loop with constrained tools.\n * Returns when the sub-agent completes its task.\n */\nexport async function spawnSubAgent(config: SubAgentConfig): Promise<SubAgentResult> {\n const titanConfig = loadConfig();\n const startTime = Date.now();\n const currentDepth = config.depth ?? 0;\n const subAgentsCfg = (titanConfig as Record<string, unknown>).subAgents as Record<string, unknown> | undefined;\n const maxDepth = (subAgentsCfg?.maxDepth as number) ?? 4; // Increased from 2 → 4 for multi-level task decomposition\n\n // Check depth limit (configurable, default 2)\n if (currentDepth >= maxDepth || config.isNested) {\n return {\n content: `Error: Sub-agent nesting depth limit reached (depth ${currentDepth}/${maxDepth}).`,\n toolsUsed: [],\n success: false,\n durationMs: 0,\n rounds: 0,\n validated: false,\n };\n }\n\n // Check concurrency limit\n const maxConcurrent = (titanConfig as Record<string, unknown>).subAgents\n ? ((titanConfig as Record<string, unknown>).subAgents as Record<string, unknown>).maxConcurrent as number || 3\n : 3;\n\n if (activeSubAgentIds.size >= maxConcurrent) {\n return {\n content: `Error: Maximum concurrent sub-agents (${maxConcurrent}) reached. Wait for one to finish.`,\n toolsUsed: [],\n success: false,\n durationMs: 0,\n rounds: 0,\n validated: false,\n };\n }\n\n const agentName = config.name || 'SubAgent';\n const agentTrackingId = `${agentName}-${Date.now()}`;\n activeSubAgentIds.add(agentTrackingId);\n\n // Phase 8: log agent spawn\n try {\n const { logActivity } = await import('../telemetry/activityLog.js');\n logActivity({ event: 'agent_spawn', agent: agentName, task: config.task.slice(0, 200) });\n } catch { /* non-critical */ }\n // Reduce max rounds by 30% per depth level to prevent runaway nesting\n const baseMaxRounds = config.maxRounds || 10;\n const depthReduction = Math.pow(0.7, currentDepth);\n const maxRounds = Math.max(3, Math.ceil(baseMaxRounds * depthReduction));\n // Model resolution priority:\n // 1. Explicit model passed in config (full model ID like 'ollama/qwen3.5:397b-cloud')\n // 2. Tier from config/template → resolve via modelAliases (cloud/smart/fast/local)\n // 3. subAgents.defaultModel config → resolve as alias name\n // 4. modelAliases.fast fallback\n const aliases = titanConfig.agent.modelAliases || {};\n const subDefaultAlias = (subAgentsCfg?.defaultModel as string) || 'fast';\n const tier = config.tier;\n const model = config.model\n || (tier ? aliases[tier] : undefined)\n || aliases[subDefaultAlias]\n || aliases.fast\n || 'ollama/qwen3.5:cloud';\n\n logger.info(COMPONENT, `Spawning ${agentName}: \"${config.task.slice(0, 80)}...\" (model: ${model}, maxRounds: ${maxRounds})`);\n\n // ── Message Bus: register mailbox for inter-agent communication ──\n registerMailbox(agentName);\n\n // Build tool whitelist\n let availableTools: ToolDefinition[];\n const allTools = getToolDefinitions();\n\n const canNest = currentDepth + 1 < maxDepth; // Allow spawn_agent only if depth allows\n\n // v4.7.0: Hermes-style blocked-for-children tool list. Regardless of\n // template, children never get: spawn_agent, memory_store/write,\n // send_message variants, outbound-publisher tools, or code_exec.\n // Protects against prompt-injection → memory corruption +\n // child-posts-as-Tony side channels.\n let blockedForChildren: Set<string> = new Set();\n try {\n const safety = await import('./subagentSafety.js');\n blockedForChildren = safety.BLOCKED_CHILD_TOOLS;\n } catch { /* optional */ }\n const isChild = currentDepth > 0; // top-level sub-agent = depth 0, but this is the sub-agent itself\n\n if (config.tools && config.tools.length > 0) {\n const toolSet = new Set(config.tools);\n if (!canNest) toolSet.delete('spawn_agent');\n // Ensure send_agent_message is always available for inter-agent comms\n toolSet.add('send_agent_message');\n availableTools = allTools.filter(t => toolSet.has(t.function.name));\n } else {\n availableTools = allTools.filter(t => canNest || t.function.name !== 'spawn_agent');\n }\n\n // v4.7.0: apply blocklist to whatever tools survived template filtering.\n // Primary agent (not a sub-agent) is never filtered. This is the last\n // line of defense — even if a template accidentally includes a\n // dangerous tool, children won't get it.\n if (isChild && blockedForChildren.size > 0) {\n availableTools = availableTools.filter(t => !blockedForChildren.has(t.function.name));\n }\n\n // Build system prompt: TITAN core (minimal) + role template + persona.\n //\n // v4.13 (plan-this-logical-ocean step 4): specialists used to get ONLY\n // the role template, with no TITAN identity / tool-use rules / per-model\n // overlay. On gemma4:31b-cloud this led to specialists hallucinating\n // `<|tool>call:...<|tool|>` markup as text because nothing told them\n // \"use the native tool_calls field, not Gemini's proxy artifact\".\n //\n // Minimal mode gives them: identity, ReAct loop + 3 core rules, tool\n // preference, runtime note, safety, truthfulness, and a per-model\n // overlay. No Delegation block (they don't re-delegate), no Continuous\n // Learning / Memory Tools walls — specialists get a focused task.\n const roleTemplate = config.systemPrompt || `You are the ${agentName} sub-agent of TITAN. Execute the task below using available tools. Be efficient and return a clear summary when done.`;\n const titanCore = assembleSystemPrompt({\n modelId: model,\n persona: config.persona || 'default',\n mode: 'minimal',\n });\n let systemPrompt = `${titanCore}\\n\\n## Role\\n${roleTemplate}`;\n\n // ── Persona: inject persona content from assets/personas/ ──\n const personaId = config.persona;\n if (personaId && personaId !== 'default') {\n try {\n const personaContent = getActivePersonaContent(personaId);\n if (personaContent) {\n systemPrompt += `\\n\\n## Persona: ${personaId}\\n${personaContent}`;\n logger.debug(COMPONENT, `[${agentName}] Applied persona: ${personaId}`);\n }\n } catch {\n logger.debug(COMPONENT, `[${agentName}] Persona \"${personaId}\" not found, using base prompt`);\n }\n }\n\n // ── Agent Pool: try to reuse a warm agent if pool enabled ──\n let pooledAgent: PooledAgent | null = null;\n let messages: ChatMessage[];\n\n if (config.reusePool) {\n const templateName = Object.entries(SUB_AGENT_TEMPLATES).find(\n ([, t]) => t.name === agentName || t.systemPrompt === config.systemPrompt,\n )?.[0] || agentName;\n\n pooledAgent = acquireAgent(templateName, model);\n if (pooledAgent) {\n // Reuse warm agent's conversation history + append new task\n messages = [\n ...pooledAgent.messages,\n { role: 'user', content: config.task },\n ];\n logger.info(COMPONENT, `Reusing pooled agent ${pooledAgent.id} for ${agentName} (${pooledAgent.messages.length} prior messages)`);\n } else {\n // No pooled agent — create fresh and register for later reuse\n pooledAgent = createPooledAgent(templateName, model);\n messages = [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: config.task },\n ];\n }\n } else {\n messages = [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: config.task },\n ];\n }\n\n const toolsUsed: string[] = [];\n let finalContent = '';\n let rounds = 0;\n\n // Phase 9: safety state tracking\n const toolHistory: Array<{ name: string; args: string; round: number }> = [];\n let lastContent = '';\n let stallCount = 0;\n const STALL_THRESHOLD = 3;\n const LOOP_THRESHOLD = 2;\n\n try {\n for (let round = 0; round < maxRounds; round++) {\n rounds = round + 1;\n logger.debug(COMPONENT, `[${agentName}] Round ${rounds}/${maxRounds}`);\n config.onProgress?.(rounds, maxRounds, agentName);\n\n // ── Message Bus: drain incoming messages at start of each round ──\n const incoming = drainMessages(agentName);\n const incomingContext = formatMessagesForContext(incoming);\n if (incomingContext) {\n messages.push({ role: 'system', content: incomingContext });\n logger.debug(COMPONENT, `[${agentName}] Injected ${incoming.length} inter-agent messages`);\n }\n\n // B7: Abort if no tools available — prevents toolless agent from looping uselessly\n if (availableTools.length === 0 && round === 0) {\n logger.warn(COMPONENT, `[${agentName}] No tools available after filtering — aborting`);\n finalContent = `Error: No tools available for sub-agent \"${agentName}\". Check tool permissions and skill configuration.`;\n break;\n }\n\n const response = await chat({\n model,\n messages,\n tools: availableTools.length > 0 ? availableTools : undefined,\n maxTokens: config.maxTokens ?? titanConfig.agent.maxTokens ?? 4096,\n temperature: 0.2,\n });\n\n // No tool calls = done\n if (!response.toolCalls || response.toolCalls.length === 0) {\n finalContent = response.content || 'Task completed.';\n break;\n }\n\n // Process tool calls\n messages.push({\n role: 'assistant',\n content: response.content || '',\n toolCalls: response.toolCalls,\n });\n\n // Emit tool_call events for Agent Watcher\n if (config.streamCallbacks?.onToolCall) {\n for (const tc of response.toolCalls!) { config.streamCallbacks.onToolCall(tc.function.name, JSON.parse(tc.function.arguments || \"{}\")); }\n }\n // Phase 9: per-tool error handling — one failing tool must not kill the session\n const toolResults: ToolResult[] = [];\n let allToolsFailed = true;\n for (const tc of response.toolCalls!) {\n let result: ToolResult;\n try {\n const singleResult = await executeTools([tc]);\n result = singleResult[0];\n if (result.success !== false) allToolsFailed = false;\n } catch (toolErr) {\n result = {\n toolCallId: tc.id,\n name: tc.function.name,\n content: `Error executing ${tc.function.name}: ${(toolErr as Error).message}`,\n success: false,\n durationMs: 0,\n };\n logger.warn(COMPONENT, `[${agentName}] Tool ${tc.function.name} failed: ${(toolErr as Error).message}`);\n }\n // Phase 9: Summarize tool outputs >10K chars to prevent context bloat\n const MAX_TOOL_OUTPUT = 10_000;\n if (result.content && result.content.length > MAX_TOOL_OUTPUT) {\n const originalLen = result.content.length;\n const marker = `\\n\\n[…output truncated from ${originalLen} to ${MAX_TOOL_OUTPUT} chars — full result available via tool re-execution with narrower scope]`;\n result.content = result.content.slice(0, MAX_TOOL_OUTPUT - marker.length) + marker;\n }\n toolResults.push(result);\n toolHistory.push({ name: result.name, args: tc.function.arguments || '{}', round });\n }\n\n // Phase 9: Graceful degradation — if every tool in a round fails, bail early\n if (allToolsFailed && toolResults.length > 0) {\n const failures = toolResults.map(r => `${r.name}: ${r.content.slice(0, 120)}`).join('; ');\n finalContent = `Error: All ${toolResults.length} tool(s) failed in round ${rounds}. ${failures}`;\n logger.warn(COMPONENT, `[${agentName}] All tools failed — aborting after ${rounds} rounds`);\n break;\n }\n\n // Emit tool_end events for Agent Watcher\n if (config.streamCallbacks?.onToolResult) {\n for (const tr of toolResults) { config.streamCallbacks.onToolResult(tr.name, tr.content, tr.durationMs || 0, tr.success !== false); }\n }\n\n for (const result of toolResults) {\n toolsUsed.push(result.name);\n messages.push({\n role: 'tool',\n content: result.content,\n toolCallId: result.toolCallId,\n name: result.name,\n });\n }\n\n // Phase 9: Stall detection — if content hasn't changed meaningfully, count it\n const currentContent = response.content || '';\n if (currentContent && currentContent === lastContent) {\n stallCount++;\n logger.warn(COMPONENT, `[${agentName}] Stall detected (${stallCount}/${STALL_THRESHOLD}) — identical content in round ${rounds}`);\n if (stallCount >= STALL_THRESHOLD) {\n finalContent = `Task stalled after ${rounds} rounds — the agent repeated the same reasoning without progress.`;\n logger.warn(COMPONENT, `[${agentName}] Aborting due to stall`);\n break;\n }\n } else {\n stallCount = 0;\n lastContent = currentContent;\n }\n\n // Phase 9: Loop detection — same tool+args repeated\n if (toolHistory.length >= 2) {\n const last = toolHistory[toolHistory.length - 1];\n const prev = toolHistory[toolHistory.length - 2];\n if (last.name === prev.name && last.args === prev.args) {\n logger.warn(COMPONENT, `[${agentName}] Loop detected — ${last.name} called with identical args in consecutive rounds`);\n finalContent = `Task looped after ${rounds} rounds — the agent called ${last.name} repeatedly with the same arguments.`;\n break;\n }\n }\n\n // Last round fallback\n if (round === maxRounds - 1) {\n finalContent = response.content || 'Max rounds reached. Partial results returned.';\n }\n }\n\n const durationMs = Date.now() - startTime;\n logger.info(COMPONENT, `${agentName} completed in ${durationMs}ms (${rounds} rounds, ${toolsUsed.length} tool calls)`);\n\n // Output validation: check for empty, too-short, or error-like responses\n const validated = validateSubAgentOutput(finalContent);\n if (!validated) {\n logger.warn(COMPONENT, `[${agentName}] Output failed validation: \"${finalContent.slice(0, 80)}...\"`);\n }\n\n // Phase 8: log agent completion\n try {\n const { logActivity } = await import('../telemetry/activityLog.js');\n logActivity({ event: 'agent_complete', agent: agentName, task: config.task.slice(0, 200), rounds, success: !finalContent.toLowerCase().startsWith('error') && validated });\n } catch { /* non-critical */ }\n\n return {\n content: finalContent,\n toolsUsed: [...new Set(toolsUsed)],\n success: !finalContent.toLowerCase().startsWith('error') && validated,\n durationMs,\n rounds,\n validated,\n };\n } catch (err) {\n const durationMs = Date.now() - startTime;\n logger.error(COMPONENT, `${agentName} failed: ${(err as Error).message}`);\n // Phase 8: log agent error\n try {\n const { logActivity } = await import('../telemetry/activityLog.js');\n logActivity({ event: 'agent_complete', agent: agentName, task: config.task.slice(0, 200), rounds, success: false, error: (err as Error).message });\n } catch { /* non-critical */ }\n return {\n content: `Sub-agent error: ${(err as Error).message}`,\n toolsUsed: [...new Set(toolsUsed)],\n success: false,\n durationMs,\n rounds,\n validated: false,\n };\n } finally {\n activeSubAgentIds.delete(agentTrackingId);\n\n // ── Message Bus: unregister mailbox on completion ──\n unregisterMailbox(agentName);\n\n // ── Agent Pool: release back to pool for future reuse ──\n if (config.reusePool && pooledAgent) {\n releaseAgent(pooledAgent.id, messages, toolsUsed, rounds);\n }\n }\n}\n\n/** Validate sub-agent output for quality */\nfunction validateSubAgentOutput(content: string): boolean {\n if (!content || content.trim().length < 20) return false;\n const lower = content.toLowerCase();\n if (lower.startsWith('i cannot') || lower.startsWith('i\\'m unable') || lower.startsWith('i am unable')) return false;\n if (lower.startsWith('error:') || lower.startsWith('sub-agent error:')) return false;\n if (lower === 'task completed.' && content.length < 20) return false;\n return true;\n}\n\n/** Get count of currently active sub-agents */\nexport function getActiveSubAgentCount(): number {\n return activeSubAgentIds.size;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/agent/subAgent.ts"],"sourcesContent":["/**\n * TITAN — Universal Sub-Agent\n * Spawns isolated sub-agents that reuse processMessage() with constrained toolsets.\n * Generalizes the swarm.ts pattern into a universal delegation system.\n *\n * Key constraints:\n * - Max depth: 1 (sub-agents cannot spawn sub-sub-agents)\n * - Inherits parent's autonomy mode (can't escalate)\n * - Own stall/loop counters (isolated from parent)\n * - Cost counts toward parent session budget\n */\nimport { chat } from '../providers/router.js';\nimport { executeTools, getToolDefinitions, type ToolResult } from './toolRunner.js';\nimport { loadConfig } from '../config/config.js';\nimport type { ChatMessage, ToolDefinition } from '../providers/base.js';\nimport logger from '../utils/logger.js';\nimport { resolveToolsFromCategories, type ToolCategory } from './toolCategories.js';\nimport { registerMailbox, unregisterMailbox, drainMessages, formatMessagesForContext } from './messageBus.js';\nimport { acquireAgent, releaseAgent, createPooledAgent, type PooledAgent } from './agentPool.js';\nimport { getActivePersonaContent } from '../personas/manager.js';\nimport { assembleSystemPrompt } from './systemPromptParts.js';\n\nconst COMPONENT = 'SubAgent';\n\n/** Currently running sub-agent IDs (Set for accurate tracking, prevents counter desync) */\nconst activeSubAgentIds = new Set<string>();\n\nexport interface SubAgentConfig {\n name: string;\n task: string;\n /** Whitelist of tool names this sub-agent can use. Empty = all tools */\n tools?: string[];\n /** Tool categories — resolved to tool names at runtime */\n toolCategories?: ToolCategory[];\n /** Create a git worktree for filesystem isolation */\n useWorktree?: boolean;\n /** Model override (defaults to fast alias) */\n model?: string;\n /** Model tier — resolved via modelAliases (cloud/smart/fast/local) */\n tier?: ModelTier;\n /** System prompt override */\n systemPrompt?: string;\n /** Persona ID to apply (from assets/personas/). Appended to system prompt. */\n persona?: string;\n /** Max tool rounds for this sub-agent (default: 10) */\n maxRounds?: number;\n /** Max tokens per LLM call for this sub-agent (default: from config) */\n maxTokens?: number;\n /** Whether this is being called from within a sub-agent already */\n isNested?: boolean;\n /** Current nesting depth (0 = top-level sub-agent) */\n depth?: number;\n /** Progress callback: called each round with progress info */\n onProgress?: (round: number, totalRounds: number, agentName: string) => void;\n /** Opt-in to agent pool reuse — warm agents preserve context between tasks */\n reusePool?: boolean;\n /** Working directory for filesystem operations (future: scope file tools) */\n workspaceDir?: string;\n /** Tags for observability / filtering */\n tags?: string[];\n /** Stream callbacks for Agent Watcher — tool_call, tool_end, round events */\n streamCallbacks?: {\n onToolCall?: (name: string, args: Record<string, unknown>) => void;\n onToolResult?: (name: string, result: string, durationMs: number, success: boolean) => void;\n onThinking?: () => void;\n onRound?: (round: number, maxRounds: number) => void;\n };\n}\n\nexport interface SubAgentResult {\n content: string;\n toolsUsed: string[];\n success: boolean;\n durationMs: number;\n rounds: number;\n /** Whether the output passed validation checks */\n validated: boolean;\n}\n\n/**\n * Model tier for each sub-agent template.\n * - 'cloud': Heavy reasoning tasks → uses modelAliases.cloud (big cloud model)\n * - 'smart': Complex tasks → uses modelAliases.smart\n * - 'fast': Quick/simple tasks → uses modelAliases.fast (local)\n * - 'local': Must run locally → uses modelAliases.local\n */\nexport type ModelTier = 'cloud' | 'smart' | 'fast' | 'local';\n\n/** Built-in sub-agent templates with mapped personas */\nexport const SUB_AGENT_TEMPLATES: Record<string, Partial<SubAgentConfig> & { tier?: ModelTier }> = {\n explorer: {\n name: 'Explorer',\n persona: 'context-engineer',\n tools: ['web_search', 'web_fetch', 'browse_url', 'web_read', 'web_act'],\n systemPrompt: `You are the Explorer sub-agent. Your job is to research and gather information from the web using your tools.\n\nAvailable tools and when to use them:\n- web_search: MUST use this first — search for any topic, question, or keyword\n- web_fetch: MUST use after web_search — fetch full page content from the most relevant URLs\n- browse_url: Navigate to a specific URL for interactive content\n- web_read: Extract clean readable text from a URL\n- web_act: Click, scroll, or interact with page elements\n\nMUST rules:\n- MUST call web_search before attempting to answer from memory\n- MUST call web_fetch on at least 2 of the top search result URLs to get full content\n- MUST cross-verify key facts across multiple sources\n\nReturn a structured summary with: key findings, sources (with URLs), and confidence level for main claims.`,\n tier: 'smart',\n },\n coder: {\n name: 'Coder',\n persona: 'incremental-builder',\n tools: ['shell', 'read_file', 'write_file', 'edit_file', 'append_file', 'list_dir', 'code_exec'],\n systemPrompt: `You are the Coder sub-agent. Your job is to WRITE CODE using your tools. Lead with action, not exploration.\n\nCRITICAL RULES:\n- Your FIRST tool call should be write_file (for new files) or read_file (if modifying existing files)\n- Do NOT start with list_dir unless you genuinely don't know the project structure\n- NEVER output code as text — always use write_file or edit_file\n- NEVER describe what you would do — DO IT immediately\n- One sentence of planning max, then CALL THE TOOL\n- After writing files, verify with shell (npm run build, etc.)\n- Keep each edit under 30 lines. For large changes, use multiple edit_file calls\n- Prefer editing existing files over creating new ones\n- No unnecessary comments, error handling, or features beyond scope\n\nTool priority:\n1. write_file — create new files with complete working code\n2. edit_file — modify existing files (read first)\n3. shell — run commands, install packages, verify builds\n4. read_file — only when you need to understand existing code before editing\n5. list_dir — only when you don't know the structure at all\n\nReturn a summary of what was created/modified with exact file paths.`,\n tier: 'smart',\n },\n browser: {\n name: 'Browser',\n persona: 'browser-tester',\n tools: ['browse_url', 'browser_auto_nav', 'browser_search', 'web_read', 'web_act', 'browser_screenshot'],\n systemPrompt: `You are the Browser sub-agent. Your job is to interact with web pages — navigate, extract content, fill forms, and click buttons.\n\nAvailable tools and when to use them:\n- browse_url: MUST use to navigate to a URL before interacting with it\n- browser_screenshot: Take a screenshot to understand the current page state\n- web_read: Extract clean text content from the current page\n- web_act: Click buttons, fill inputs, scroll — use for interactive actions\n- browser_auto_nav: Auto-navigate complex flows (login, multi-step forms)\n- browser_search: Search within a page or site\n\nMUST rules:\n- MUST call browse_url first to open the page\n- MUST call web_read or browser_screenshot to understand page contents before acting\n- MUST report what you found, extracted, or accomplished with exact details\n\nReturn a clear report of what was found/done on the page.`,\n tier: 'fast',\n },\n analyst: {\n name: 'Analyst',\n persona: 'code-reviewer',\n tools: ['web_search', 'web_fetch', 'memory', 'graph_search', 'graph_remember'],\n systemPrompt: `You are the Analyst sub-agent. Your job is to analyze information, identify patterns, and produce structured analytical reports.\n\nAvailable tools and when to use them:\n- web_search: Search for data, statistics, reports, or comparisons\n- web_fetch: Fetch full content from specific URLs for deeper analysis\n- graph_search: Search the knowledge graph for previously stored context\n- graph_remember: Store important findings in the knowledge graph for future reference\n- memory: Store/retrieve key-value data points\n\nMUST rules:\n- MUST call web_search to gather current data before analyzing\n- MUST call graph_search to check for existing relevant context\n- MUST call graph_remember to store key findings after analysis\n- MUST base conclusions on data from tools — not assumptions\n\nReturn a structured analytical report with: executive summary, data findings, patterns identified, confidence levels, and recommendations.`,\n tier: 'cloud',\n },\n researcher: {\n name: 'Researcher',\n persona: 'trend-researcher',\n tools: ['web_search', 'web_read', 'web_fetch', 'rag_search', 'rag_ingest'],\n systemPrompt: `You are the Deep Researcher sub-agent. Your job is to systematically research a question using multiple sources and tools.\n\nAvailable tools and when to use them:\n- web_search: MUST call 2-4 times with different targeted queries to get broad coverage\n- web_fetch: MUST call on the top 3-5 URLs from search results to get full content\n- web_read: Extract clean text from a URL\n- rag_search: Search the local knowledge base for existing research on this topic\n- rag_ingest: Store important findings in the local knowledge base\n\nMethodology — follow in order:\n1. Call rag_search to check for existing research on this topic\n2. Break the question into 2-4 targeted search queries\n3. Call web_search for each query\n4. Call web_fetch on the most relevant URLs (at least 3 total)\n5. Cross-verify key claims across at least 2 independent sources\n6. Call rag_ingest to store important findings\n\nMUST rules:\n- MUST call web_search — never answer research questions from memory\n- MUST call web_fetch to read full content, not just search snippets\n- MUST cite all sources with URLs\n\nOutput format: executive summary → sections with headers → numbered citations [1], [2] → Sources list with URLs.`,\n maxRounds: 15,\n tier: 'cloud',\n },\n // ── Pipeline agents (DeerFlow-inspired) ────────────────────\n reporter: {\n name: 'Reporter',\n persona: 'documentation-writer',\n tools: ['read_file', 'write_file', 'web_fetch'],\n systemPrompt: `You are the Reporter sub-agent. Your job is to synthesize research findings into structured, publication-quality documents saved to disk.\n\nAvailable tools and when to use them:\n- read_file: Read any existing research notes or source files\n- write_file: MUST use to save the final report to disk — NEVER output report content as text\n- web_fetch: Fetch additional content from URLs if needed for a specific section\n\nMUST rules:\n- MUST call write_file to save the report — the output is a file on disk, not inline text\n- MUST call read_file if source material files are referenced in the task\n- If given a file path for the output, MUST save to exactly that path\n\nReport structure: executive summary → sections with markdown headers → confidence levels (High/Medium/Low) per claim → numbered citations → actionable conclusions.`,\n maxRounds: 10,\n tier: 'cloud',\n },\n fact_checker: {\n name: 'Fact Checker',\n persona: 'context-engineer',\n tools: ['web_search', 'web_fetch'],\n systemPrompt: `You are the Fact Checker sub-agent. Your job is to verify specific claims against multiple independent sources.\n\nAvailable tools and when to use them:\n- web_search: MUST call for each claim to find sources that confirm or refute it\n- web_fetch: MUST call to read the full source content — search snippets are not enough\n\nFor each claim:\n1. Call web_search with 2 different queries targeting this claim\n2. Call web_fetch on the top 2 sources for full content\n3. Compare the claim against what each source actually says\n4. Assign: Verified (3+ sources agree) / Likely (2 sources) / Unverified (1 source) / Disputed (sources conflict) / False (sources contradict)\n\nMUST rules:\n- MUST call web_search for every claim — never verify from memory\n- MUST call web_fetch to read full source content\n\nReturn a structured report: claim → status → evidence → sources used.`,\n maxRounds: 10,\n tier: 'smart',\n },\n // ── Dev agents (TITAN_DEV only) ──────────────────────────\n dev_debugger: {\n name: 'Dev Debugger',\n persona: 'debugger',\n tools: ['shell', 'read_file', 'write_file', 'debug_analyze', 'code_analyze'],\n systemPrompt: `You are the Dev Debugger sub-agent for the TITAN framework. Your job is to find and fix bugs by reading actual code and running diagnostic commands.\n\nAvailable tools and when to use them:\n- read_file: MUST use to read the source file containing the error before diagnosing\n- code_analyze: Analyze code structure, find potential issues, check for bugs\n- debug_analyze: Deep analysis of error messages, stack traces, and runtime issues\n- shell: Run the failing code, check logs, reproduce the error, verify the fix\n- write_file: Save the fixed code\n\nMUST rules:\n- MUST call read_file to read the actual source code — never diagnose from assumptions\n- MUST call code_analyze or debug_analyze to systematically identify the root cause\n- MUST call shell to reproduce the error before attempting a fix\n- MUST call shell again after the fix to verify it works\n- MUST call write_file to apply the fix — never describe the fix without implementing it\n\nReturn: root cause analysis, fix applied (with file path), verification result.`,\n maxRounds: 15,\n tier: 'smart',\n },\n dev_tester: {\n name: 'Dev Tester',\n persona: 'tdd-engineer',\n tools: ['shell', 'read_file', 'write_file', 'test_generate', 'code_exec'],\n systemPrompt: `You are the Dev Tester sub-agent for the TITAN framework. Your job is to generate, run, and fix tests using vitest.\n\nAvailable tools and when to use them:\n- read_file: MUST use to read the source code being tested before writing tests\n- test_generate: Generate comprehensive test cases from source code\n- write_file: MUST use to save the test file — never output tests as text\n- shell: Run vitest to execute tests and see results\n- code_exec: Quick isolated code execution for testing snippets\n\nMUST rules:\n- MUST call read_file to understand the code structure before writing tests\n- MUST call write_file to save test files — never output tests inline\n- MUST call shell to run the tests after writing them\n- MUST fix any test failures — don't stop at writing tests\n\nReturn: test file path, number of tests written, test results (pass/fail counts).`,\n maxRounds: 20,\n tier: 'fast',\n },\n dev_reviewer: {\n name: 'Dev Reviewer',\n persona: 'code-reviewer',\n tools: ['shell', 'read_file', 'code_review', 'code_analyze', 'deps_audit'],\n systemPrompt: `You are the Dev Reviewer sub-agent for the TITAN framework. Your job is to perform thorough multi-pass code review.\n\nAvailable tools and when to use them:\n- read_file: MUST use to read each file being reviewed — never review from memory\n- code_analyze: Structural analysis — complexity, patterns, architecture\n- code_review: Deep review — security, logic errors, performance issues\n- deps_audit: Check dependencies for vulnerabilities or outdated packages\n- shell: Run the code, check for type errors, run linter\n\nReview passes (do all):\n1. Security pass: call code_review with security focus\n2. Logic pass: call code_analyze for correctness and edge cases\n3. Performance pass: check for inefficiencies\n4. Dependencies pass: call deps_audit\n\nMUST rules:\n- MUST call read_file for each file reviewed\n- MUST run at least 2 review passes with different focuses\n- Flag real issues only — not style preferences\n\nReturn: structured findings by severity (Critical/Major/Minor), with file + line references.`,\n maxRounds: 10,\n tier: 'cloud',\n },\n dev_architect: {\n name: 'Dev Architect',\n persona: 'backend-architect',\n tools: ['shell', 'read_file', 'write_file', 'code_analyze', 'refactor_suggest', 'doc_generate'],\n systemPrompt: `You are the Dev Architect sub-agent for the TITAN framework. Your job is to analyze system architecture and implement structural improvements.\n\nAvailable tools and when to use them:\n- read_file: MUST use to read source files before proposing architectural changes\n- code_analyze: Analyze codebase structure, dependencies, coupling, and patterns\n- refactor_suggest: Get suggestions for structural improvements and refactoring\n- shell: Run the codebase to understand runtime behavior, check imports, count lines\n- write_file: MUST use to implement changes or create documentation\n- doc_generate: Generate architectural documentation\n\nMUST rules:\n- MUST call read_file and code_analyze before proposing any changes — never guess at structure\n- MUST call shell to understand actual file/folder organization\n- MUST call write_file to implement changes or save documentation — never describe changes inline\n- Think in systems and dependencies, not individual files\n\nReturn: architectural analysis, proposed changes with rationale, implementation summary with file paths.`,\n maxRounds: 15,\n tier: 'cloud',\n },\n // v5.5.23: 'writer' template moved here from agent_handoff.ts ROLE_MAP.\n // Mirrors the Writer specialist defined in specialists.ts so the spawn_agent\n // tool, agent_delegate tool, and agent_team/chain tools all share one\n // canonical writer prompt. Tools chosen by what specialists.ts gives Writer.\n writer: {\n name: 'Writer',\n persona: 'voice-clone',\n tools: ['read_file', 'write_file', 'memory', 'web_search', 'web_fetch'],\n systemPrompt: `You are the Writer sub-agent. Your job is to draft publication-quality content — social posts, emails, announcements, short-form copy — in the requested voice.\n\nAvailable tools and when to use them:\n- web_search / web_fetch: gather context or prior posts when matching a voice\n- read_file / write_file: read briefs, save drafts to files when asked\n- memory: pull stored stylistic preferences and past phrasing\n\nMUST rules:\n- MUST match the voice the operator uses in prior posts/messages when one is provided\n- NEVER post publicly — draft only, return the draft for approval\n- For social posts (Facebook/X), keep under 280 chars unless explicitly asked for long-form. Hook in the first line.\n- Be concise. Cut filler. Strong verbs.\n\nReturn the final draft as the response. If you saved it to a file, also return the file path.`,\n maxRounds: 6,\n tier: 'smart',\n },\n};\n\n/**\n * Spawn a sub-agent that runs an isolated agent loop with constrained tools.\n * Returns when the sub-agent completes its task.\n */\nexport async function spawnSubAgent(config: SubAgentConfig): Promise<SubAgentResult> {\n const titanConfig = loadConfig();\n const startTime = Date.now();\n const currentDepth = config.depth ?? 0;\n const subAgentsCfg = (titanConfig as Record<string, unknown>).subAgents as Record<string, unknown> | undefined;\n const maxDepth = (subAgentsCfg?.maxDepth as number) ?? 4; // Increased from 2 → 4 for multi-level task decomposition\n\n // Check depth limit (configurable, default 2)\n if (currentDepth >= maxDepth || config.isNested) {\n return {\n content: `Error: Sub-agent nesting depth limit reached (depth ${currentDepth}/${maxDepth}).`,\n toolsUsed: [],\n success: false,\n durationMs: 0,\n rounds: 0,\n validated: false,\n };\n }\n\n // Check concurrency limit\n const maxConcurrent = (titanConfig as Record<string, unknown>).subAgents\n ? ((titanConfig as Record<string, unknown>).subAgents as Record<string, unknown>).maxConcurrent as number || 3\n : 3;\n\n if (activeSubAgentIds.size >= maxConcurrent) {\n return {\n content: `Error: Maximum concurrent sub-agents (${maxConcurrent}) reached. Wait for one to finish.`,\n toolsUsed: [],\n success: false,\n durationMs: 0,\n rounds: 0,\n validated: false,\n };\n }\n\n const agentName = config.name || 'SubAgent';\n const agentTrackingId = `${agentName}-${Date.now()}`;\n activeSubAgentIds.add(agentTrackingId);\n\n // Phase 8: log agent spawn\n try {\n const { logActivity } = await import('../telemetry/activityLog.js');\n logActivity({ event: 'agent_spawn', agent: agentName, task: config.task.slice(0, 200) });\n } catch { /* non-critical */ }\n // Reduce max rounds by 30% per depth level to prevent runaway nesting\n const baseMaxRounds = config.maxRounds || 10;\n const depthReduction = Math.pow(0.7, currentDepth);\n const maxRounds = Math.max(3, Math.ceil(baseMaxRounds * depthReduction));\n // Model resolution priority:\n // 1. Explicit model passed in config (full model ID like 'ollama/qwen3.5:397b-cloud')\n // 2. Tier from config/template → resolve via modelAliases (cloud/smart/fast/local)\n // 3. subAgents.defaultModel config → resolve as alias name\n // 4. modelAliases.fast fallback\n const aliases = titanConfig.agent.modelAliases || {};\n const subDefaultAlias = (subAgentsCfg?.defaultModel as string) || 'fast';\n const tier = config.tier;\n const model = config.model\n || (tier ? aliases[tier] : undefined)\n || aliases[subDefaultAlias]\n || aliases.fast\n || 'ollama/qwen3.5:cloud';\n\n logger.info(COMPONENT, `Spawning ${agentName}: \"${config.task.slice(0, 80)}...\" (model: ${model}, maxRounds: ${maxRounds})`);\n\n // ── Message Bus: register mailbox for inter-agent communication ──\n registerMailbox(agentName);\n\n // Build tool whitelist\n let availableTools: ToolDefinition[];\n const allTools = getToolDefinitions();\n\n const canNest = currentDepth + 1 < maxDepth; // Allow spawn_agent only if depth allows\n\n // v4.7.0: Hermes-style blocked-for-children tool list. Regardless of\n // template, children never get: spawn_agent, memory_store/write,\n // send_message variants, outbound-publisher tools, or code_exec.\n // Protects against prompt-injection → memory corruption +\n // child-posts-as-Tony side channels.\n let blockedForChildren: Set<string> = new Set();\n try {\n const safety = await import('./subagentSafety.js');\n blockedForChildren = safety.BLOCKED_CHILD_TOOLS;\n } catch { /* optional */ }\n const isChild = currentDepth > 0; // top-level sub-agent = depth 0, but this is the sub-agent itself\n\n if (config.tools && config.tools.length > 0) {\n const toolSet = new Set(config.tools);\n if (!canNest) toolSet.delete('spawn_agent');\n // Ensure send_agent_message is always available for inter-agent comms\n toolSet.add('send_agent_message');\n availableTools = allTools.filter(t => toolSet.has(t.function.name));\n } else {\n availableTools = allTools.filter(t => canNest || t.function.name !== 'spawn_agent');\n }\n\n // v4.7.0: apply blocklist to whatever tools survived template filtering.\n // Primary agent (not a sub-agent) is never filtered. This is the last\n // line of defense — even if a template accidentally includes a\n // dangerous tool, children won't get it.\n if (isChild && blockedForChildren.size > 0) {\n availableTools = availableTools.filter(t => !blockedForChildren.has(t.function.name));\n }\n\n // Build system prompt: TITAN core (minimal) + role template + persona.\n //\n // v4.13 (plan-this-logical-ocean step 4): specialists used to get ONLY\n // the role template, with no TITAN identity / tool-use rules / per-model\n // overlay. On gemma4:31b-cloud this led to specialists hallucinating\n // `<|tool>call:...<|tool|>` markup as text because nothing told them\n // \"use the native tool_calls field, not Gemini's proxy artifact\".\n //\n // Minimal mode gives them: identity, ReAct loop + 3 core rules, tool\n // preference, runtime note, safety, truthfulness, and a per-model\n // overlay. No Delegation block (they don't re-delegate), no Continuous\n // Learning / Memory Tools walls — specialists get a focused task.\n const roleTemplate = config.systemPrompt || `You are the ${agentName} sub-agent of TITAN. Execute the task below using available tools. Be efficient and return a clear summary when done.`;\n const titanCore = assembleSystemPrompt({\n modelId: model,\n persona: config.persona || 'default',\n mode: 'minimal',\n });\n let systemPrompt = `${titanCore}\\n\\n## Role\\n${roleTemplate}`;\n\n // ── Persona: inject persona content from assets/personas/ ──\n const personaId = config.persona;\n if (personaId && personaId !== 'default') {\n try {\n const personaContent = getActivePersonaContent(personaId);\n if (personaContent) {\n systemPrompt += `\\n\\n## Persona: ${personaId}\\n${personaContent}`;\n logger.debug(COMPONENT, `[${agentName}] Applied persona: ${personaId}`);\n }\n } catch {\n logger.debug(COMPONENT, `[${agentName}] Persona \"${personaId}\" not found, using base prompt`);\n }\n }\n\n // ── Agent Pool: try to reuse a warm agent if pool enabled ──\n let pooledAgent: PooledAgent | null = null;\n let messages: ChatMessage[];\n\n if (config.reusePool) {\n const templateName = Object.entries(SUB_AGENT_TEMPLATES).find(\n ([, t]) => t.name === agentName || t.systemPrompt === config.systemPrompt,\n )?.[0] || agentName;\n\n pooledAgent = acquireAgent(templateName, model);\n if (pooledAgent) {\n // Reuse warm agent's conversation history + append new task\n messages = [\n ...pooledAgent.messages,\n { role: 'user', content: config.task },\n ];\n logger.info(COMPONENT, `Reusing pooled agent ${pooledAgent.id} for ${agentName} (${pooledAgent.messages.length} prior messages)`);\n } else {\n // No pooled agent — create fresh and register for later reuse\n pooledAgent = createPooledAgent(templateName, model);\n messages = [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: config.task },\n ];\n }\n } else {\n messages = [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: config.task },\n ];\n }\n\n const toolsUsed: string[] = [];\n let finalContent = '';\n let rounds = 0;\n\n // Phase 9: safety state tracking\n const toolHistory: Array<{ name: string; args: string; round: number }> = [];\n let lastContent = '';\n let stallCount = 0;\n const STALL_THRESHOLD = 3;\n const LOOP_THRESHOLD = 2;\n\n try {\n for (let round = 0; round < maxRounds; round++) {\n rounds = round + 1;\n logger.debug(COMPONENT, `[${agentName}] Round ${rounds}/${maxRounds}`);\n config.onProgress?.(rounds, maxRounds, agentName);\n\n // ── Message Bus: drain incoming messages at start of each round ──\n const incoming = drainMessages(agentName);\n const incomingContext = formatMessagesForContext(incoming);\n if (incomingContext) {\n messages.push({ role: 'system', content: incomingContext });\n logger.debug(COMPONENT, `[${agentName}] Injected ${incoming.length} inter-agent messages`);\n }\n\n // B7: Abort if no tools available — prevents toolless agent from looping uselessly\n if (availableTools.length === 0 && round === 0) {\n logger.warn(COMPONENT, `[${agentName}] No tools available after filtering — aborting`);\n finalContent = `Error: No tools available for sub-agent \"${agentName}\". Check tool permissions and skill configuration.`;\n break;\n }\n\n const response = await chat({\n model,\n messages,\n tools: availableTools.length > 0 ? availableTools : undefined,\n maxTokens: config.maxTokens ?? titanConfig.agent.maxTokens ?? 4096,\n temperature: 0.2,\n });\n\n // No tool calls = done\n if (!response.toolCalls || response.toolCalls.length === 0) {\n finalContent = response.content || 'Task completed.';\n break;\n }\n\n // Process tool calls\n messages.push({\n role: 'assistant',\n content: response.content || '',\n toolCalls: response.toolCalls,\n });\n\n // Emit tool_call events for Agent Watcher\n if (config.streamCallbacks?.onToolCall) {\n for (const tc of response.toolCalls!) { config.streamCallbacks.onToolCall(tc.function.name, JSON.parse(tc.function.arguments || \"{}\")); }\n }\n // Phase 9: per-tool error handling — one failing tool must not kill the session\n const toolResults: ToolResult[] = [];\n let allToolsFailed = true;\n for (const tc of response.toolCalls!) {\n let result: ToolResult;\n try {\n const singleResult = await executeTools([tc]);\n result = singleResult[0];\n if (result.success !== false) allToolsFailed = false;\n } catch (toolErr) {\n result = {\n toolCallId: tc.id,\n name: tc.function.name,\n content: `Error executing ${tc.function.name}: ${(toolErr as Error).message}`,\n success: false,\n durationMs: 0,\n };\n logger.warn(COMPONENT, `[${agentName}] Tool ${tc.function.name} failed: ${(toolErr as Error).message}`);\n }\n // Phase 9: Summarize tool outputs >10K chars to prevent context bloat\n const MAX_TOOL_OUTPUT = 10_000;\n if (result.content && result.content.length > MAX_TOOL_OUTPUT) {\n const originalLen = result.content.length;\n const marker = `\\n\\n[…output truncated from ${originalLen} to ${MAX_TOOL_OUTPUT} chars — full result available via tool re-execution with narrower scope]`;\n result.content = result.content.slice(0, MAX_TOOL_OUTPUT - marker.length) + marker;\n }\n toolResults.push(result);\n toolHistory.push({ name: result.name, args: tc.function.arguments || '{}', round });\n }\n\n // Phase 9: Graceful degradation — if every tool in a round fails, bail early\n if (allToolsFailed && toolResults.length > 0) {\n const failures = toolResults.map(r => `${r.name}: ${r.content.slice(0, 120)}`).join('; ');\n finalContent = `Error: All ${toolResults.length} tool(s) failed in round ${rounds}. ${failures}`;\n logger.warn(COMPONENT, `[${agentName}] All tools failed — aborting after ${rounds} rounds`);\n break;\n }\n\n // Emit tool_end events for Agent Watcher\n if (config.streamCallbacks?.onToolResult) {\n for (const tr of toolResults) { config.streamCallbacks.onToolResult(tr.name, tr.content, tr.durationMs || 0, tr.success !== false); }\n }\n\n for (const result of toolResults) {\n toolsUsed.push(result.name);\n messages.push({\n role: 'tool',\n content: result.content,\n toolCallId: result.toolCallId,\n name: result.name,\n });\n }\n\n // Phase 9: Stall detection — if content hasn't changed meaningfully, count it\n const currentContent = response.content || '';\n if (currentContent && currentContent === lastContent) {\n stallCount++;\n logger.warn(COMPONENT, `[${agentName}] Stall detected (${stallCount}/${STALL_THRESHOLD}) — identical content in round ${rounds}`);\n if (stallCount >= STALL_THRESHOLD) {\n finalContent = `Task stalled after ${rounds} rounds — the agent repeated the same reasoning without progress.`;\n logger.warn(COMPONENT, `[${agentName}] Aborting due to stall`);\n break;\n }\n } else {\n stallCount = 0;\n lastContent = currentContent;\n }\n\n // Phase 9: Loop detection — same tool+args repeated\n if (toolHistory.length >= 2) {\n const last = toolHistory[toolHistory.length - 1];\n const prev = toolHistory[toolHistory.length - 2];\n if (last.name === prev.name && last.args === prev.args) {\n logger.warn(COMPONENT, `[${agentName}] Loop detected — ${last.name} called with identical args in consecutive rounds`);\n finalContent = `Task looped after ${rounds} rounds — the agent called ${last.name} repeatedly with the same arguments.`;\n break;\n }\n }\n\n // Last round fallback\n if (round === maxRounds - 1) {\n finalContent = response.content || 'Max rounds reached. Partial results returned.';\n }\n }\n\n const durationMs = Date.now() - startTime;\n logger.info(COMPONENT, `${agentName} completed in ${durationMs}ms (${rounds} rounds, ${toolsUsed.length} tool calls)`);\n\n // Output validation: check for empty, too-short, or error-like responses\n const validated = validateSubAgentOutput(finalContent);\n if (!validated) {\n logger.warn(COMPONENT, `[${agentName}] Output failed validation: \"${finalContent.slice(0, 80)}...\"`);\n }\n\n // Phase 8: log agent completion\n try {\n const { logActivity } = await import('../telemetry/activityLog.js');\n logActivity({ event: 'agent_complete', agent: agentName, task: config.task.slice(0, 200), rounds, success: !finalContent.toLowerCase().startsWith('error') && validated });\n } catch { /* non-critical */ }\n\n return {\n content: finalContent,\n toolsUsed: [...new Set(toolsUsed)],\n success: !finalContent.toLowerCase().startsWith('error') && validated,\n durationMs,\n rounds,\n validated,\n };\n } catch (err) {\n const durationMs = Date.now() - startTime;\n logger.error(COMPONENT, `${agentName} failed: ${(err as Error).message}`);\n // Phase 8: log agent error\n try {\n const { logActivity } = await import('../telemetry/activityLog.js');\n logActivity({ event: 'agent_complete', agent: agentName, task: config.task.slice(0, 200), rounds, success: false, error: (err as Error).message });\n } catch { /* non-critical */ }\n return {\n content: `Sub-agent error: ${(err as Error).message}`,\n toolsUsed: [...new Set(toolsUsed)],\n success: false,\n durationMs,\n rounds,\n validated: false,\n };\n } finally {\n activeSubAgentIds.delete(agentTrackingId);\n\n // ── Message Bus: unregister mailbox on completion ──\n unregisterMailbox(agentName);\n\n // ── Agent Pool: release back to pool for future reuse ──\n if (config.reusePool && pooledAgent) {\n releaseAgent(pooledAgent.id, messages, toolsUsed, rounds);\n }\n }\n}\n\n/** Validate sub-agent output for quality */\nfunction validateSubAgentOutput(content: string): boolean {\n if (!content || content.trim().length < 20) return false;\n const lower = content.toLowerCase();\n if (lower.startsWith('i cannot') || lower.startsWith('i\\'m unable') || lower.startsWith('i am unable')) return false;\n if (lower.startsWith('error:') || lower.startsWith('sub-agent error:')) return false;\n if (lower === 'task completed.' && content.length < 20) return false;\n return true;\n}\n\n/** Get count of currently active sub-agents */\nexport function getActiveSubAgentCount(): number {\n return activeSubAgentIds.size;\n}\n"],"mappings":";AAWA,SAAS,YAAY;AACrB,SAAS,cAAc,0BAA2C;AAClE,SAAS,kBAAkB;AAE3B,OAAO,YAAY;AAEnB,SAAS,iBAAiB,mBAAmB,eAAe,gCAAgC;AAC5F,SAAS,cAAc,cAAc,yBAA2C;AAChF,SAAS,+BAA+B;AACxC,SAAS,4BAA4B;AAErC,MAAM,YAAY;AAGlB,MAAM,oBAAoB,oBAAI,IAAY;AAgEnC,MAAM,sBAAsF;AAAA,EAC/F,UAAU;AAAA,IACN,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO,CAAC,cAAc,aAAa,cAAc,YAAY,SAAS;AAAA,IACtE,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAed,MAAM;AAAA,EACV;AAAA,EACA,OAAO;AAAA,IACH,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO,CAAC,SAAS,aAAa,cAAc,aAAa,eAAe,YAAY,WAAW;AAAA,IAC/F,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAqBd,MAAM;AAAA,EACV;AAAA,EACA,SAAS;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO,CAAC,cAAc,oBAAoB,kBAAkB,YAAY,WAAW,oBAAoB;AAAA,IACvG,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAgBd,MAAM;AAAA,EACV;AAAA,EACA,SAAS;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO,CAAC,cAAc,aAAa,UAAU,gBAAgB,gBAAgB;AAAA,IAC7E,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAgBd,MAAM;AAAA,EACV;AAAA,EACA,YAAY;AAAA,IACR,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO,CAAC,cAAc,YAAY,aAAa,cAAc,YAAY;AAAA,IACzE,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAuBd,WAAW;AAAA,IACX,MAAM;AAAA,EACV;AAAA;AAAA,EAEA,UAAU;AAAA,IACN,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO,CAAC,aAAa,cAAc,WAAW;AAAA,IAC9C,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAad,WAAW;AAAA,IACX,MAAM;AAAA,EACV;AAAA,EACA,cAAc;AAAA,IACV,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO,CAAC,cAAc,WAAW;AAAA,IACjC,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAiBd,WAAW;AAAA,IACX,MAAM;AAAA,EACV;AAAA;AAAA,EAEA,cAAc;AAAA,IACV,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO,CAAC,SAAS,aAAa,cAAc,iBAAiB,cAAc;AAAA,IAC3E,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAiBd,WAAW;AAAA,IACX,MAAM;AAAA,EACV;AAAA,EACA,YAAY;AAAA,IACR,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO,CAAC,SAAS,aAAa,cAAc,iBAAiB,WAAW;AAAA,IACxE,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAgBd,WAAW;AAAA,IACX,MAAM;AAAA,EACV;AAAA,EACA,cAAc;AAAA,IACV,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO,CAAC,SAAS,aAAa,eAAe,gBAAgB,YAAY;AAAA,IACzE,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAqBd,WAAW;AAAA,IACX,MAAM;AAAA,EACV;AAAA,EACA,eAAe;AAAA,IACX,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO,CAAC,SAAS,aAAa,cAAc,gBAAgB,oBAAoB,cAAc;AAAA,IAC9F,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAiBd,WAAW;AAAA,IACX,MAAM;AAAA,EACV;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ;AAAA,IACJ,MAAM;AAAA,IACN,SAAS;AAAA,IACT,OAAO,CAAC,aAAa,cAAc,UAAU,cAAc,WAAW;AAAA,IACtE,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAcd,WAAW;AAAA,IACX,MAAM;AAAA,EACV;AACJ;AAMA,eAAsB,cAAc,QAAiD;AACjF,QAAM,cAAc,WAAW;AAC/B,QAAM,YAAY,KAAK,IAAI;AAC3B,QAAM,eAAe,OAAO,SAAS;AACrC,QAAM,eAAgB,YAAwC;AAC9D,QAAM,WAAY,cAAc,YAAuB;AAGvD,MAAI,gBAAgB,YAAY,OAAO,UAAU;AAC7C,WAAO;AAAA,MACH,SAAS,uDAAuD,YAAY,IAAI,QAAQ;AAAA,MACxF,WAAW,CAAC;AAAA,MACZ,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,WAAW;AAAA,IACf;AAAA,EACJ;AAGA,QAAM,gBAAiB,YAAwC,YACvD,YAAwC,UAAsC,iBAA2B,IAC3G;AAEN,MAAI,kBAAkB,QAAQ,eAAe;AACzC,WAAO;AAAA,MACH,SAAS,yCAAyC,aAAa;AAAA,MAC/D,WAAW,CAAC;AAAA,MACZ,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,WAAW;AAAA,IACf;AAAA,EACJ;AAEA,QAAM,YAAY,OAAO,QAAQ;AACjC,QAAM,kBAAkB,GAAG,SAAS,IAAI,KAAK,IAAI,CAAC;AAClD,oBAAkB,IAAI,eAAe;AAGrC,MAAI;AACA,UAAM,EAAE,YAAY,IAAI,MAAM,OAAO,6BAA6B;AAClE,gBAAY,EAAE,OAAO,eAAe,OAAO,WAAW,MAAM,OAAO,KAAK,MAAM,GAAG,GAAG,EAAE,CAAC;AAAA,EAC3F,QAAQ;AAAA,EAAqB;AAE7B,QAAM,gBAAgB,OAAO,aAAa;AAC1C,QAAM,iBAAiB,KAAK,IAAI,KAAK,YAAY;AACjD,QAAM,YAAY,KAAK,IAAI,GAAG,KAAK,KAAK,gBAAgB,cAAc,CAAC;AAMvE,QAAM,UAAU,YAAY,MAAM,gBAAgB,CAAC;AACnD,QAAM,kBAAmB,cAAc,gBAA2B;AAClE,QAAM,OAAO,OAAO;AACpB,QAAM,QAAQ,OAAO,UACb,OAAO,QAAQ,IAAI,IAAI,WACxB,QAAQ,eAAe,KACvB,QAAQ,QACR;AAEP,SAAO,KAAK,WAAW,YAAY,SAAS,MAAM,OAAO,KAAK,MAAM,GAAG,EAAE,CAAC,gBAAgB,KAAK,gBAAgB,SAAS,GAAG;AAG3H,kBAAgB,SAAS;AAGzB,MAAI;AACJ,QAAM,WAAW,mBAAmB;AAEpC,QAAM,UAAU,eAAe,IAAI;AAOnC,MAAI,qBAAkC,oBAAI,IAAI;AAC9C,MAAI;AACA,UAAM,SAAS,MAAM,OAAO,qBAAqB;AACjD,yBAAqB,OAAO;AAAA,EAChC,QAAQ;AAAA,EAAiB;AACzB,QAAM,UAAU,eAAe;AAE/B,MAAI,OAAO,SAAS,OAAO,MAAM,SAAS,GAAG;AACzC,UAAM,UAAU,IAAI,IAAI,OAAO,KAAK;AACpC,QAAI,CAAC,QAAS,SAAQ,OAAO,aAAa;AAE1C,YAAQ,IAAI,oBAAoB;AAChC,qBAAiB,SAAS,OAAO,OAAK,QAAQ,IAAI,EAAE,SAAS,IAAI,CAAC;AAAA,EACtE,OAAO;AACH,qBAAiB,SAAS,OAAO,OAAK,WAAW,EAAE,SAAS,SAAS,aAAa;AAAA,EACtF;AAMA,MAAI,WAAW,mBAAmB,OAAO,GAAG;AACxC,qBAAiB,eAAe,OAAO,OAAK,CAAC,mBAAmB,IAAI,EAAE,SAAS,IAAI,CAAC;AAAA,EACxF;AAcA,QAAM,eAAe,OAAO,gBAAgB,eAAe,SAAS;AACpE,QAAM,YAAY,qBAAqB;AAAA,IACnC,SAAS;AAAA,IACT,SAAS,OAAO,WAAW;AAAA,IAC3B,MAAM;AAAA,EACV,CAAC;AACD,MAAI,eAAe,GAAG,SAAS;AAAA;AAAA;AAAA,EAAgB,YAAY;AAG3D,QAAM,YAAY,OAAO;AACzB,MAAI,aAAa,cAAc,WAAW;AACtC,QAAI;AACA,YAAM,iBAAiB,wBAAwB,SAAS;AACxD,UAAI,gBAAgB;AAChB,wBAAgB;AAAA;AAAA,cAAmB,SAAS;AAAA,EAAK,cAAc;AAC/D,eAAO,MAAM,WAAW,IAAI,SAAS,sBAAsB,SAAS,EAAE;AAAA,MAC1E;AAAA,IACJ,QAAQ;AACJ,aAAO,MAAM,WAAW,IAAI,SAAS,cAAc,SAAS,gCAAgC;AAAA,IAChG;AAAA,EACJ;AAGA,MAAI,cAAkC;AACtC,MAAI;AAEJ,MAAI,OAAO,WAAW;AAClB,UAAM,eAAe,OAAO,QAAQ,mBAAmB,EAAE;AAAA,MACrD,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,aAAa,EAAE,iBAAiB,OAAO;AAAA,IACjE,IAAI,CAAC,KAAK;AAEV,kBAAc,aAAa,cAAc,KAAK;AAC9C,QAAI,aAAa;AAEb,iBAAW;AAAA,QACP,GAAG,YAAY;AAAA,QACf,EAAE,MAAM,QAAQ,SAAS,OAAO,KAAK;AAAA,MACzC;AACA,aAAO,KAAK,WAAW,wBAAwB,YAAY,EAAE,QAAQ,SAAS,KAAK,YAAY,SAAS,MAAM,kBAAkB;AAAA,IACpI,OAAO;AAEH,oBAAc,kBAAkB,cAAc,KAAK;AACnD,iBAAW;AAAA,QACP,EAAE,MAAM,UAAU,SAAS,aAAa;AAAA,QACxC,EAAE,MAAM,QAAQ,SAAS,OAAO,KAAK;AAAA,MACzC;AAAA,IACJ;AAAA,EACJ,OAAO;AACH,eAAW;AAAA,MACP,EAAE,MAAM,UAAU,SAAS,aAAa;AAAA,MACxC,EAAE,MAAM,QAAQ,SAAS,OAAO,KAAK;AAAA,IACzC;AAAA,EACJ;AAEA,QAAM,YAAsB,CAAC;AAC7B,MAAI,eAAe;AACnB,MAAI,SAAS;AAGb,QAAM,cAAoE,CAAC;AAC3E,MAAI,cAAc;AAClB,MAAI,aAAa;AACjB,QAAM,kBAAkB;AACxB,QAAM,iBAAiB;AAEvB,MAAI;AACA,aAAS,QAAQ,GAAG,QAAQ,WAAW,SAAS;AAC5C,eAAS,QAAQ;AACjB,aAAO,MAAM,WAAW,IAAI,SAAS,WAAW,MAAM,IAAI,SAAS,EAAE;AACrE,aAAO,aAAa,QAAQ,WAAW,SAAS;AAGhD,YAAM,WAAW,cAAc,SAAS;AACxC,YAAM,kBAAkB,yBAAyB,QAAQ;AACzD,UAAI,iBAAiB;AACjB,iBAAS,KAAK,EAAE,MAAM,UAAU,SAAS,gBAAgB,CAAC;AAC1D,eAAO,MAAM,WAAW,IAAI,SAAS,cAAc,SAAS,MAAM,uBAAuB;AAAA,MAC7F;AAGA,UAAI,eAAe,WAAW,KAAK,UAAU,GAAG;AAC5C,eAAO,KAAK,WAAW,IAAI,SAAS,sDAAiD;AACrF,uBAAe,4CAA4C,SAAS;AACpE;AAAA,MACJ;AAEA,YAAM,WAAW,MAAM,KAAK;AAAA,QACxB;AAAA,QACA;AAAA,QACA,OAAO,eAAe,SAAS,IAAI,iBAAiB;AAAA,QACpD,WAAW,OAAO,aAAa,YAAY,MAAM,aAAa;AAAA,QAC9D,aAAa;AAAA,MACjB,CAAC;AAGD,UAAI,CAAC,SAAS,aAAa,SAAS,UAAU,WAAW,GAAG;AACxD,uBAAe,SAAS,WAAW;AACnC;AAAA,MACJ;AAGA,eAAS,KAAK;AAAA,QACV,MAAM;AAAA,QACN,SAAS,SAAS,WAAW;AAAA,QAC7B,WAAW,SAAS;AAAA,MACxB,CAAC;AAGD,UAAI,OAAO,iBAAiB,YAAY;AACpC,mBAAW,MAAM,SAAS,WAAY;AAAE,iBAAO,gBAAgB,WAAW,GAAG,SAAS,MAAM,KAAK,MAAM,GAAG,SAAS,aAAa,IAAI,CAAC;AAAA,QAAG;AAAA,MAC5I;AAEA,YAAM,cAA4B,CAAC;AACnC,UAAI,iBAAiB;AACrB,iBAAW,MAAM,SAAS,WAAY;AAClC,YAAI;AACJ,YAAI;AACA,gBAAM,eAAe,MAAM,aAAa,CAAC,EAAE,CAAC;AAC5C,mBAAS,aAAa,CAAC;AACvB,cAAI,OAAO,YAAY,MAAO,kBAAiB;AAAA,QACnD,SAAS,SAAS;AACd,mBAAS;AAAA,YACL,YAAY,GAAG;AAAA,YACf,MAAM,GAAG,SAAS;AAAA,YAClB,SAAS,mBAAmB,GAAG,SAAS,IAAI,KAAM,QAAkB,OAAO;AAAA,YAC3E,SAAS;AAAA,YACT,YAAY;AAAA,UAChB;AACA,iBAAO,KAAK,WAAW,IAAI,SAAS,UAAU,GAAG,SAAS,IAAI,YAAa,QAAkB,OAAO,EAAE;AAAA,QAC1G;AAEA,cAAM,kBAAkB;AACxB,YAAI,OAAO,WAAW,OAAO,QAAQ,SAAS,iBAAiB;AAC3D,gBAAM,cAAc,OAAO,QAAQ;AACnC,gBAAM,SAAS;AAAA;AAAA,+BAA+B,WAAW,OAAO,eAAe;AAC/E,iBAAO,UAAU,OAAO,QAAQ,MAAM,GAAG,kBAAkB,OAAO,MAAM,IAAI;AAAA,QAChF;AACA,oBAAY,KAAK,MAAM;AACvB,oBAAY,KAAK,EAAE,MAAM,OAAO,MAAM,MAAM,GAAG,SAAS,aAAa,MAAM,MAAM,CAAC;AAAA,MACtF;AAGA,UAAI,kBAAkB,YAAY,SAAS,GAAG;AAC1C,cAAM,WAAW,YAAY,IAAI,OAAK,GAAG,EAAE,IAAI,KAAK,EAAE,QAAQ,MAAM,GAAG,GAAG,CAAC,EAAE,EAAE,KAAK,IAAI;AACxF,uBAAe,cAAc,YAAY,MAAM,4BAA4B,MAAM,KAAK,QAAQ;AAC9F,eAAO,KAAK,WAAW,IAAI,SAAS,4CAAuC,MAAM,SAAS;AAC1F;AAAA,MACJ;AAGA,UAAI,OAAO,iBAAiB,cAAc;AACtC,mBAAW,MAAM,aAAa;AAAE,iBAAO,gBAAgB,aAAa,GAAG,MAAM,GAAG,SAAS,GAAG,cAAc,GAAG,GAAG,YAAY,KAAK;AAAA,QAAG;AAAA,MACxI;AAEA,iBAAW,UAAU,aAAa;AAC9B,kBAAU,KAAK,OAAO,IAAI;AAC1B,iBAAS,KAAK;AAAA,UACV,MAAM;AAAA,UACN,SAAS,OAAO;AAAA,UAChB,YAAY,OAAO;AAAA,UACnB,MAAM,OAAO;AAAA,QACjB,CAAC;AAAA,MACL;AAGA,YAAM,iBAAiB,SAAS,WAAW;AAC3C,UAAI,kBAAkB,mBAAmB,aAAa;AAClD;AACA,eAAO,KAAK,WAAW,IAAI,SAAS,qBAAqB,UAAU,IAAI,eAAe,uCAAkC,MAAM,EAAE;AAChI,YAAI,cAAc,iBAAiB;AAC/B,yBAAe,sBAAsB,MAAM;AAC3C,iBAAO,KAAK,WAAW,IAAI,SAAS,yBAAyB;AAC7D;AAAA,QACJ;AAAA,MACJ,OAAO;AACH,qBAAa;AACb,sBAAc;AAAA,MAClB;AAGA,UAAI,YAAY,UAAU,GAAG;AACzB,cAAM,OAAO,YAAY,YAAY,SAAS,CAAC;AAC/C,cAAM,OAAO,YAAY,YAAY,SAAS,CAAC;AAC/C,YAAI,KAAK,SAAS,KAAK,QAAQ,KAAK,SAAS,KAAK,MAAM;AACpD,iBAAO,KAAK,WAAW,IAAI,SAAS,0BAAqB,KAAK,IAAI,mDAAmD;AACrH,yBAAe,qBAAqB,MAAM,mCAA8B,KAAK,IAAI;AACjF;AAAA,QACJ;AAAA,MACJ;AAGA,UAAI,UAAU,YAAY,GAAG;AACzB,uBAAe,SAAS,WAAW;AAAA,MACvC;AAAA,IACJ;AAEA,UAAM,aAAa,KAAK,IAAI,IAAI;AAChC,WAAO,KAAK,WAAW,GAAG,SAAS,iBAAiB,UAAU,OAAO,MAAM,YAAY,UAAU,MAAM,cAAc;AAGrH,UAAM,YAAY,uBAAuB,YAAY;AACrD,QAAI,CAAC,WAAW;AACZ,aAAO,KAAK,WAAW,IAAI,SAAS,gCAAgC,aAAa,MAAM,GAAG,EAAE,CAAC,MAAM;AAAA,IACvG;AAGA,QAAI;AACA,YAAM,EAAE,YAAY,IAAI,MAAM,OAAO,6BAA6B;AAClE,kBAAY,EAAE,OAAO,kBAAkB,OAAO,WAAW,MAAM,OAAO,KAAK,MAAM,GAAG,GAAG,GAAG,QAAQ,SAAS,CAAC,aAAa,YAAY,EAAE,WAAW,OAAO,KAAK,UAAU,CAAC;AAAA,IAC7K,QAAQ;AAAA,IAAqB;AAE7B,WAAO;AAAA,MACH,SAAS;AAAA,MACT,WAAW,CAAC,GAAG,IAAI,IAAI,SAAS,CAAC;AAAA,MACjC,SAAS,CAAC,aAAa,YAAY,EAAE,WAAW,OAAO,KAAK;AAAA,MAC5D;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AAAA,EACJ,SAAS,KAAK;AACV,UAAM,aAAa,KAAK,IAAI,IAAI;AAChC,WAAO,MAAM,WAAW,GAAG,SAAS,YAAa,IAAc,OAAO,EAAE;AAExE,QAAI;AACA,YAAM,EAAE,YAAY,IAAI,MAAM,OAAO,6BAA6B;AAClE,kBAAY,EAAE,OAAO,kBAAkB,OAAO,WAAW,MAAM,OAAO,KAAK,MAAM,GAAG,GAAG,GAAG,QAAQ,SAAS,OAAO,OAAQ,IAAc,QAAQ,CAAC;AAAA,IACrJ,QAAQ;AAAA,IAAqB;AAC7B,WAAO;AAAA,MACH,SAAS,oBAAqB,IAAc,OAAO;AAAA,MACnD,WAAW,CAAC,GAAG,IAAI,IAAI,SAAS,CAAC;AAAA,MACjC,SAAS;AAAA,MACT;AAAA,MACA;AAAA,MACA,WAAW;AAAA,IACf;AAAA,EACJ,UAAE;AACE,sBAAkB,OAAO,eAAe;AAGxC,sBAAkB,SAAS;AAG3B,QAAI,OAAO,aAAa,aAAa;AACjC,mBAAa,YAAY,IAAI,UAAU,WAAW,MAAM;AAAA,IAC5D;AAAA,EACJ;AACJ;AAGA,SAAS,uBAAuB,SAA0B;AACtD,MAAI,CAAC,WAAW,QAAQ,KAAK,EAAE,SAAS,GAAI,QAAO;AACnD,QAAM,QAAQ,QAAQ,YAAY;AAClC,MAAI,MAAM,WAAW,UAAU,KAAK,MAAM,WAAW,YAAa,KAAK,MAAM,WAAW,aAAa,EAAG,QAAO;AAC/G,MAAI,MAAM,WAAW,QAAQ,KAAK,MAAM,WAAW,kBAAkB,EAAG,QAAO;AAC/E,MAAI,UAAU,qBAAqB,QAAQ,SAAS,GAAI,QAAO;AAC/D,SAAO;AACX;AAGO,SAAS,yBAAiC;AAC7C,SAAO,kBAAkB;AAC7B;","names":[]}
@@ -22,61 +22,30 @@ async function setAgentStatus(role, status) {
22
22
  }
23
23
  }
24
24
  const COMPONENT = "AgentHandoff";
25
- const ROLE_MAP = {
26
- researcher: {
27
- template: "researcher",
28
- systemPrompt: "You are a research specialist. Thoroughly investigate the given topic using available tools. Cite sources and provide structured findings.",
29
- tier: "cloud"
30
- },
31
- coder: {
32
- template: "coder",
33
- systemPrompt: "You are a coding specialist. Write clean, well-structured code. Read existing files before modifying. Test your work.",
34
- tier: "fast"
35
- },
36
- analyst: {
37
- template: "analyst",
38
- systemPrompt: "You are an analysis specialist. Examine data, identify patterns, and produce structured analytical reports with confidence levels.",
39
- tier: "cloud"
40
- },
41
- writer: {
42
- systemPrompt: "You are a writing specialist. Produce clear, well-structured, publication-quality content. Match the requested tone and format.",
43
- tier: "smart"
44
- },
45
- reviewer: {
46
- template: "dev_reviewer",
47
- systemPrompt: "You are a review specialist. Critically evaluate the given content for accuracy, completeness, quality, and potential issues. Provide specific, actionable feedback.",
48
- tier: "smart"
49
- },
50
- explorer: {
51
- template: "explorer",
52
- systemPrompt: "You are a web research specialist. Search the web, fetch pages, and gather information from multiple sources.",
53
- tier: "smart"
54
- },
55
- debugger: {
56
- template: "dev_debugger",
57
- systemPrompt: "You are a debugging specialist. Diagnose issues systematically \u2014 read code, reproduce errors, identify root causes, and verify fixes.",
58
- tier: "smart"
59
- },
60
- architect: {
61
- template: "dev_architect",
62
- systemPrompt: "You are a system architecture specialist. Analyze structure, dependencies, and design patterns. Propose well-reasoned improvements.",
63
- tier: "cloud"
64
- }
25
+ const ROLE_ALIASES = {
26
+ researcher: "researcher",
27
+ coder: "coder",
28
+ analyst: "analyst",
29
+ writer: "writer",
30
+ explorer: "explorer",
31
+ reviewer: "dev_reviewer",
32
+ debugger: "dev_debugger",
33
+ architect: "dev_architect"
65
34
  };
66
35
  function resolveRole(role, task, context, maxRounds) {
67
36
  const roleLower = role.toLowerCase().trim();
68
- const mapping = ROLE_MAP[roleLower];
69
- const template = mapping?.template ? SUB_AGENT_TEMPLATES[mapping.template] : void 0;
37
+ const templateKey = ROLE_ALIASES[roleLower] || roleLower;
38
+ const template = SUB_AGENT_TEMPLATES[templateKey];
70
39
  const fullTask = context ? `${task}
71
40
 
72
41
  Context:
73
42
  ${context}` : task;
74
43
  return {
75
- name: `${role.charAt(0).toUpperCase() + role.slice(1)}Agent`,
44
+ name: template?.name || `${role.charAt(0).toUpperCase() + role.slice(1)}Agent`,
76
45
  task: fullTask,
77
46
  tools: template?.tools,
78
- systemPrompt: template?.systemPrompt || mapping?.systemPrompt || `You are a ${role} specialist. Complete the given task thoroughly and return a clear summary.`,
79
- tier: mapping?.tier || "smart",
47
+ systemPrompt: template?.systemPrompt || `You are a ${role} specialist. Complete the given task thoroughly and return a clear summary.`,
48
+ tier: template?.tier || "smart",
80
49
  maxRounds: maxRounds || template?.maxRounds || 10
81
50
  };
82
51
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/skills/builtin/agent_handoff.ts"],"sourcesContent":["/**\n * TITAN — Agent Handoff & Delegation Skill (Built-in)\n * Provides tools for multi-agent orchestration: delegate, team, chain, and critique patterns.\n * Uses TITAN's sub-agent infrastructure for isolated execution.\n */\nimport { registerSkill } from '../registry.js';\nimport { spawnSubAgent, SUB_AGENT_TEMPLATES, type SubAgentConfig, type ModelTier } from '../../agent/subAgent.js';\nimport logger from '../../utils/logger.js';\n\n// v4.14.0: role → specialist ID mapping for CP status tracking\nconst ROLE_TO_SPECIALIST: Record<string, string> = {\n researcher: 'scout',\n coder: 'builder',\n analyst: 'analyst',\n writer: 'writer',\n reviewer: 'sage',\n explorer: 'scout',\n debugger: 'builder',\n architect: 'builder',\n};\n\nasync function setAgentStatus(role: string, status: 'active' | 'idle'): Promise<void> {\n const specialistId = ROLE_TO_SPECIALIST[role.toLowerCase().trim()];\n if (!specialistId) return;\n try {\n const { updateAgentStatus } = await import('../../agent/commandPost.js');\n updateAgentStatus(specialistId, status);\n } catch { /* optional */ }\n}\n\nconst COMPONENT = 'AgentHandoff';\n\n/** Role-to-template mapping with fallback system prompts */\nconst ROLE_MAP: Record<string, { template?: string; systemPrompt: string; tier: ModelTier }> = {\n researcher: {\n template: 'researcher',\n systemPrompt: 'You are a research specialist. Thoroughly investigate the given topic using available tools. Cite sources and provide structured findings.',\n tier: 'cloud',\n },\n coder: {\n template: 'coder',\n systemPrompt: 'You are a coding specialist. Write clean, well-structured code. Read existing files before modifying. Test your work.',\n tier: 'fast',\n },\n analyst: {\n template: 'analyst',\n systemPrompt: 'You are an analysis specialist. Examine data, identify patterns, and produce structured analytical reports with confidence levels.',\n tier: 'cloud',\n },\n writer: {\n systemPrompt: 'You are a writing specialist. Produce clear, well-structured, publication-quality content. Match the requested tone and format.',\n tier: 'smart',\n },\n reviewer: {\n template: 'dev_reviewer',\n systemPrompt: 'You are a review specialist. Critically evaluate the given content for accuracy, completeness, quality, and potential issues. Provide specific, actionable feedback.',\n tier: 'smart',\n },\n explorer: {\n template: 'explorer',\n systemPrompt: 'You are a web research specialist. Search the web, fetch pages, and gather information from multiple sources.',\n tier: 'smart',\n },\n debugger: {\n template: 'dev_debugger',\n systemPrompt: 'You are a debugging specialist. Diagnose issues systematically — read code, reproduce errors, identify root causes, and verify fixes.',\n tier: 'smart',\n },\n architect: {\n template: 'dev_architect',\n systemPrompt: 'You are a system architecture specialist. Analyze structure, dependencies, and design patterns. Propose well-reasoned improvements.',\n tier: 'cloud',\n },\n};\n\n/** Resolve a role string into a SubAgentConfig */\nfunction resolveRole(role: string, task: string, context?: string, maxRounds?: number): SubAgentConfig {\n const roleLower = role.toLowerCase().trim();\n const mapping = ROLE_MAP[roleLower];\n const template = mapping?.template ? SUB_AGENT_TEMPLATES[mapping.template] : undefined;\n\n const fullTask = context ? `${task}\\n\\nContext:\\n${context}` : task;\n\n return {\n name: `${role.charAt(0).toUpperCase() + role.slice(1)}Agent`,\n task: fullTask,\n tools: template?.tools,\n systemPrompt: template?.systemPrompt || mapping?.systemPrompt || `You are a ${role} specialist. Complete the given task thoroughly and return a clear summary.`,\n tier: mapping?.tier || 'smart',\n maxRounds: maxRounds || template?.maxRounds || 10,\n };\n}\n\n// ─── Tool: agent_delegate ───────────────────────────────────────────\n\nconst delegateHandler = {\n name: 'agent_delegate',\n description: 'Delegate a task to a specialized sub-agent. Supported roles: researcher, coder, analyst, writer, reviewer, explorer, debugger, architect. The sub-agent runs in isolation with role-appropriate tools and returns its result. USE THIS WHEN: you need a focused specialist to handle a specific sub-task.',\n parameters: {\n type: 'object',\n properties: {\n role: {\n type: 'string',\n description: 'The specialist role (researcher, coder, analyst, writer, reviewer, explorer, debugger, architect)',\n },\n task: {\n type: 'string',\n description: 'The specific task description for the sub-agent',\n },\n context: {\n type: 'string',\n description: 'Optional context to pass to the sub-agent',\n },\n maxRounds: {\n type: 'number',\n description: 'Maximum tool-use rounds (default: 10)',\n },\n },\n required: ['role', 'task'],\n },\n execute: async (args: Record<string, unknown>): Promise<string> => {\n const role = args.role as string;\n const task = args.task as string;\n const context = args.context as string | undefined;\n const maxRounds = args.maxRounds as number | undefined;\n\n if (!role || !task) {\n return 'Error: Both \"role\" and \"task\" are required.';\n }\n\n logger.info(COMPONENT, `Delegating to ${role}: \"${task.slice(0, 80)}...\"`);\n\n await setAgentStatus(role, 'active');\n try {\n const config = resolveRole(role, task, context, maxRounds);\n const result = await spawnSubAgent(config);\n await setAgentStatus(role, 'idle');\n\n const status = result.success ? 'SUCCESS' : 'FAILED';\n const tools = result.toolsUsed.length > 0 ? `\\nTools used: ${result.toolsUsed.join(', ')}` : '';\n return `[${status}] Agent: ${config.name} | Rounds: ${result.rounds} | Duration: ${result.durationMs}ms${tools}\\n\\n${result.content}`;\n } catch (err) {\n await setAgentStatus(role, 'idle');\n throw err;\n }\n },\n};\n\n// ─── Tool: agent_team ───────────────────────────────────────────────\n\ninterface TeamTask {\n role: string;\n task: string;\n context?: string;\n}\n\nconst teamHandler = {\n name: 'agent_team',\n description: 'Run multiple specialized agents in PARALLEL on different aspects of a problem. Each agent runs independently and results are combined. USE THIS WHEN: a problem can be decomposed into independent sub-tasks that different specialists can tackle simultaneously (e.g., one researches while another codes).',\n parameters: {\n type: 'object',\n properties: {\n tasks: {\n type: 'string',\n description: 'JSON array of task objects: [{\"role\": \"researcher\", \"task\": \"...\", \"context\": \"...\"}]. Each object needs \"role\" and \"task\".',\n },\n },\n required: ['tasks'],\n },\n execute: async (args: Record<string, unknown>): Promise<string> => {\n let tasks: TeamTask[];\n try {\n const raw = args.tasks as string;\n tasks = JSON.parse(raw) as TeamTask[];\n } catch {\n return 'Error: \"tasks\" must be a valid JSON array of {role, task, context?} objects.';\n }\n\n if (!Array.isArray(tasks) || tasks.length === 0) {\n return 'Error: \"tasks\" must be a non-empty array.';\n }\n\n if (tasks.length > 6) {\n return 'Error: Maximum 6 parallel agents allowed.';\n }\n\n logger.info(COMPONENT, `Running agent team: ${tasks.length} agents in parallel`);\n\n // Activate all team members before spawning\n await Promise.all(tasks.map(t => setAgentStatus(t.role, 'active')));\n\n const results = await Promise.all(\n tasks.map(async (t, i) => {\n const config = resolveRole(t.role, t.task, t.context);\n const result = await spawnSubAgent(config);\n return { index: i, role: t.role, task: t.task, result };\n })\n );\n\n // Deactivate all team members after completion\n await Promise.all(tasks.map(t => setAgentStatus(t.role, 'idle')));\n\n const sections = results.map(r => {\n const status = r.result.success ? 'SUCCESS' : 'FAILED';\n return `## Agent ${r.index + 1}: ${r.role} [${status}]\\nTask: ${r.task}\\nRounds: ${r.result.rounds} | Duration: ${r.result.durationMs}ms\\n\\n${r.result.content}`;\n });\n\n const successCount = results.filter(r => r.result.success).length;\n return `# Agent Team Results (${successCount}/${results.length} succeeded)\\n\\n${sections.join('\\n\\n---\\n\\n')}`;\n },\n};\n\n// ─── Tool: agent_chain ──────────────────────────────────────────────\n\ninterface ChainStep {\n role: string;\n task: string;\n}\n\nconst chainHandler = {\n name: 'agent_chain',\n description: 'Run agents SEQUENTIALLY in a chain, passing each output as context to the next agent. USE THIS WHEN: tasks have dependencies — e.g., first research a topic, then write an article based on findings, then review the article.',\n parameters: {\n type: 'object',\n properties: {\n steps: {\n type: 'string',\n description: 'JSON array of step objects: [{\"role\": \"researcher\", \"task\": \"...\"}, {\"role\": \"writer\", \"task\": \"...\"}]. Each step gets the previous step\\'s output as context.',\n },\n },\n required: ['steps'],\n },\n execute: async (args: Record<string, unknown>): Promise<string> => {\n let steps: ChainStep[];\n try {\n const raw = args.steps as string;\n steps = JSON.parse(raw) as ChainStep[];\n } catch {\n return 'Error: \"steps\" must be a valid JSON array of {role, task} objects.';\n }\n\n if (!Array.isArray(steps) || steps.length === 0) {\n return 'Error: \"steps\" must be a non-empty array.';\n }\n\n if (steps.length > 8) {\n return 'Error: Maximum 8 chain steps allowed.';\n }\n\n logger.info(COMPONENT, `Running agent chain: ${steps.length} sequential steps`);\n\n const intermediateResults: Array<{ role: string; task: string; content: string; success: boolean }> = [];\n let previousOutput = '';\n\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i];\n const context = previousOutput\n ? `Output from previous step (${intermediateResults[i - 1]?.role || 'unknown'}):\\n${previousOutput}`\n : undefined;\n\n logger.info(COMPONENT, `Chain step ${i + 1}/${steps.length}: ${step.role}`);\n\n await setAgentStatus(step.role, 'active');\n try {\n const config = resolveRole(step.role, step.task, context);\n const result = await spawnSubAgent(config);\n await setAgentStatus(step.role, 'idle');\n\n intermediateResults.push({\n role: step.role,\n task: step.task,\n content: result.content,\n success: result.success,\n });\n\n previousOutput = result.content;\n\n // If a step fails, continue but note it\n if (!result.success) {\n logger.warn(COMPONENT, `Chain step ${i + 1} (${step.role}) failed, continuing with partial output`);\n }\n } catch (err) {\n await setAgentStatus(step.role, 'idle');\n throw err;\n }\n }\n\n const stepSummaries = intermediateResults.map((r, i) => {\n const status = r.success ? 'SUCCESS' : 'FAILED';\n return `## Step ${i + 1}: ${r.role} [${status}]\\nTask: ${r.task}\\n\\n${r.content}`;\n });\n\n const finalResult = intermediateResults[intermediateResults.length - 1];\n return `# Agent Chain Results (${steps.length} steps)\\n\\n${stepSummaries.join('\\n\\n---\\n\\n')}\\n\\n---\\n\\n## Final Output\\n${finalResult?.content || 'No output'}`;\n },\n};\n\n// ─── Tool: agent_critique ───────────────────────────────────────────\n\nconst critiqueHandler = {\n name: 'agent_critique',\n description: 'Generate-critique loop: one agent produces output, another critiques it, then the first agent improves based on feedback. Repeats for the specified number of rounds. USE THIS WHEN: you need high-quality output that benefits from iterative refinement — articles, code, analyses, proposals.',\n parameters: {\n type: 'object',\n properties: {\n task: {\n type: 'string',\n description: 'The task to generate output for',\n },\n generatorRole: {\n type: 'string',\n description: 'Role for the generator agent (default: \"writer\")',\n },\n criticRole: {\n type: 'string',\n description: 'Role for the critic agent (default: \"reviewer\")',\n },\n rounds: {\n type: 'number',\n description: 'Number of generate-critique cycles (default: 2, max: 5)',\n },\n },\n required: ['task'],\n },\n execute: async (args: Record<string, unknown>): Promise<string> => {\n const task = args.task as string;\n const generatorRole = (args.generatorRole as string) || 'writer';\n const criticRole = (args.criticRole as string) || 'reviewer';\n const rounds = Math.min(Math.max((args.rounds as number) || 2, 1), 5);\n\n if (!task) {\n return 'Error: \"task\" is required.';\n }\n\n logger.info(COMPONENT, `Starting critique loop: ${generatorRole} + ${criticRole}, ${rounds} rounds`);\n\n let currentOutput = '';\n const history: Array<{ round: number; type: 'generation' | 'critique'; content: string }> = [];\n\n for (let round = 1; round <= rounds; round++) {\n // ── Generate ──\n const genContext = round === 1\n ? undefined\n : `Previous version:\\n${currentOutput}\\n\\nCritique feedback:\\n${history[history.length - 1]?.content || 'No feedback'}`;\n\n const genTask = round === 1\n ? task\n : `Improve the following work based on the critique feedback. Original task: ${task}`;\n\n const genConfig = resolveRole(generatorRole, genTask, genContext);\n const genResult = await spawnSubAgent(genConfig);\n\n currentOutput = genResult.content;\n history.push({ round, type: 'generation', content: genResult.content });\n\n logger.info(COMPONENT, `Critique round ${round}/${rounds}: generation complete`);\n\n // ── Critique (skip on last round — final output is the last generation) ──\n if (round < rounds) {\n const critiqueTask = `Critically review the following output. Identify strengths, weaknesses, errors, and specific improvements. Be constructive but thorough.\\n\\nOriginal task: ${task}`;\n const critiqueContext = `Content to review:\\n${currentOutput}`;\n\n const critiqueConfig = resolveRole(criticRole, critiqueTask, critiqueContext);\n const critiqueResult = await spawnSubAgent(critiqueConfig);\n\n history.push({ round, type: 'critique', content: critiqueResult.content });\n\n logger.info(COMPONENT, `Critique round ${round}/${rounds}: critique complete`);\n }\n }\n\n const roundSummaries = history.map(h => {\n const label = h.type === 'generation' ? `Round ${h.round} — Generation` : `Round ${h.round} — Critique`;\n return `## ${label}\\n${h.content}`;\n });\n\n return `# Agent Critique Results (${rounds} rounds: ${generatorRole} + ${criticRole})\\n\\n${roundSummaries.join('\\n\\n---\\n\\n')}\\n\\n---\\n\\n## Final Output\\n${currentOutput}`;\n },\n};\n\n// ─── Registration ───────────────────────────────────────────────────\n\nexport function registerAgentHandoffSkill(): void {\n const meta = {\n name: 'agent-handoff',\n description: 'Agent handoff and delegation — delegate tasks to specialists, run agent teams in parallel, chain agents sequentially, or use generate-critique loops for quality output.',\n version: '1.0.0',\n source: 'bundled' as const,\n enabled: true,\n };\n\n registerSkill(meta, delegateHandler);\n registerSkill(meta, teamHandler);\n registerSkill(meta, chainHandler);\n registerSkill(meta, critiqueHandler);\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/skills/builtin/agent_handoff.ts"],"sourcesContent":["/**\n * TITAN — Agent Handoff & Delegation Skill (Built-in)\n * Provides tools for multi-agent orchestration: delegate, team, chain, and critique patterns.\n * Uses TITAN's sub-agent infrastructure for isolated execution.\n */\nimport { registerSkill } from '../registry.js';\nimport { spawnSubAgent, SUB_AGENT_TEMPLATES, type SubAgentConfig } from '../../agent/subAgent.js';\nimport logger from '../../utils/logger.js';\n\n// v4.14.0: role → specialist ID mapping for CP status tracking\nconst ROLE_TO_SPECIALIST: Record<string, string> = {\n researcher: 'scout',\n coder: 'builder',\n analyst: 'analyst',\n writer: 'writer',\n reviewer: 'sage',\n explorer: 'scout',\n debugger: 'builder',\n architect: 'builder',\n};\n\nasync function setAgentStatus(role: string, status: 'active' | 'idle'): Promise<void> {\n const specialistId = ROLE_TO_SPECIALIST[role.toLowerCase().trim()];\n if (!specialistId) return;\n try {\n const { updateAgentStatus } = await import('../../agent/commandPost.js');\n updateAgentStatus(specialistId, status);\n } catch { /* optional */ }\n}\n\nconst COMPONENT = 'AgentHandoff';\n\n/**\n * Role-aliases → SUB_AGENT_TEMPLATES key. The user-facing role names this\n * skill exposes (researcher, coder, analyst, writer, reviewer, explorer,\n * debugger, architect) sometimes match the canonical template name and\n * sometimes need translation (debugger → dev_debugger). All system prompts,\n * tier, and tools come from SUB_AGENT_TEMPLATES — this map is just the\n * vocabulary translation layer.\n *\n * v5.5.23: Eliminated parallel `ROLE_MAP` that duplicated systemPrompt and\n * tier per role. Eight inline systemPrompts removed; SUB_AGENT_TEMPLATES is\n * now the single source of truth for sub-agent role definitions, shared\n * across spawn_agent, agent_delegate, agent_team, and agent_chain.\n */\nconst ROLE_ALIASES: Record<string, string> = {\n researcher: 'researcher',\n coder: 'coder',\n analyst: 'analyst',\n writer: 'writer',\n explorer: 'explorer',\n reviewer: 'dev_reviewer',\n debugger: 'dev_debugger',\n architect: 'dev_architect',\n};\n\n/** Resolve a role string into a SubAgentConfig from SUB_AGENT_TEMPLATES. */\nfunction resolveRole(role: string, task: string, context?: string, maxRounds?: number): SubAgentConfig {\n const roleLower = role.toLowerCase().trim();\n const templateKey = ROLE_ALIASES[roleLower] || roleLower;\n const template = SUB_AGENT_TEMPLATES[templateKey];\n\n const fullTask = context ? `${task}\\n\\nContext:\\n${context}` : task;\n\n return {\n name: template?.name || `${role.charAt(0).toUpperCase() + role.slice(1)}Agent`,\n task: fullTask,\n tools: template?.tools,\n systemPrompt: template?.systemPrompt || `You are a ${role} specialist. Complete the given task thoroughly and return a clear summary.`,\n tier: template?.tier || 'smart',\n maxRounds: maxRounds || template?.maxRounds || 10,\n };\n}\n\n// ─── Tool: agent_delegate ───────────────────────────────────────────\n\nconst delegateHandler = {\n name: 'agent_delegate',\n description: 'Delegate a task to a specialized sub-agent. Supported roles: researcher, coder, analyst, writer, reviewer, explorer, debugger, architect. The sub-agent runs in isolation with role-appropriate tools and returns its result. USE THIS WHEN: you need a focused specialist to handle a specific sub-task.',\n parameters: {\n type: 'object',\n properties: {\n role: {\n type: 'string',\n description: 'The specialist role (researcher, coder, analyst, writer, reviewer, explorer, debugger, architect)',\n },\n task: {\n type: 'string',\n description: 'The specific task description for the sub-agent',\n },\n context: {\n type: 'string',\n description: 'Optional context to pass to the sub-agent',\n },\n maxRounds: {\n type: 'number',\n description: 'Maximum tool-use rounds (default: 10)',\n },\n },\n required: ['role', 'task'],\n },\n execute: async (args: Record<string, unknown>): Promise<string> => {\n const role = args.role as string;\n const task = args.task as string;\n const context = args.context as string | undefined;\n const maxRounds = args.maxRounds as number | undefined;\n\n if (!role || !task) {\n return 'Error: Both \"role\" and \"task\" are required.';\n }\n\n logger.info(COMPONENT, `Delegating to ${role}: \"${task.slice(0, 80)}...\"`);\n\n await setAgentStatus(role, 'active');\n try {\n const config = resolveRole(role, task, context, maxRounds);\n const result = await spawnSubAgent(config);\n await setAgentStatus(role, 'idle');\n\n const status = result.success ? 'SUCCESS' : 'FAILED';\n const tools = result.toolsUsed.length > 0 ? `\\nTools used: ${result.toolsUsed.join(', ')}` : '';\n return `[${status}] Agent: ${config.name} | Rounds: ${result.rounds} | Duration: ${result.durationMs}ms${tools}\\n\\n${result.content}`;\n } catch (err) {\n await setAgentStatus(role, 'idle');\n throw err;\n }\n },\n};\n\n// ─── Tool: agent_team ───────────────────────────────────────────────\n\ninterface TeamTask {\n role: string;\n task: string;\n context?: string;\n}\n\nconst teamHandler = {\n name: 'agent_team',\n description: 'Run multiple specialized agents in PARALLEL on different aspects of a problem. Each agent runs independently and results are combined. USE THIS WHEN: a problem can be decomposed into independent sub-tasks that different specialists can tackle simultaneously (e.g., one researches while another codes).',\n parameters: {\n type: 'object',\n properties: {\n tasks: {\n type: 'string',\n description: 'JSON array of task objects: [{\"role\": \"researcher\", \"task\": \"...\", \"context\": \"...\"}]. Each object needs \"role\" and \"task\".',\n },\n },\n required: ['tasks'],\n },\n execute: async (args: Record<string, unknown>): Promise<string> => {\n let tasks: TeamTask[];\n try {\n const raw = args.tasks as string;\n tasks = JSON.parse(raw) as TeamTask[];\n } catch {\n return 'Error: \"tasks\" must be a valid JSON array of {role, task, context?} objects.';\n }\n\n if (!Array.isArray(tasks) || tasks.length === 0) {\n return 'Error: \"tasks\" must be a non-empty array.';\n }\n\n if (tasks.length > 6) {\n return 'Error: Maximum 6 parallel agents allowed.';\n }\n\n logger.info(COMPONENT, `Running agent team: ${tasks.length} agents in parallel`);\n\n // Activate all team members before spawning\n await Promise.all(tasks.map(t => setAgentStatus(t.role, 'active')));\n\n const results = await Promise.all(\n tasks.map(async (t, i) => {\n const config = resolveRole(t.role, t.task, t.context);\n const result = await spawnSubAgent(config);\n return { index: i, role: t.role, task: t.task, result };\n })\n );\n\n // Deactivate all team members after completion\n await Promise.all(tasks.map(t => setAgentStatus(t.role, 'idle')));\n\n const sections = results.map(r => {\n const status = r.result.success ? 'SUCCESS' : 'FAILED';\n return `## Agent ${r.index + 1}: ${r.role} [${status}]\\nTask: ${r.task}\\nRounds: ${r.result.rounds} | Duration: ${r.result.durationMs}ms\\n\\n${r.result.content}`;\n });\n\n const successCount = results.filter(r => r.result.success).length;\n return `# Agent Team Results (${successCount}/${results.length} succeeded)\\n\\n${sections.join('\\n\\n---\\n\\n')}`;\n },\n};\n\n// ─── Tool: agent_chain ──────────────────────────────────────────────\n\ninterface ChainStep {\n role: string;\n task: string;\n}\n\nconst chainHandler = {\n name: 'agent_chain',\n description: 'Run agents SEQUENTIALLY in a chain, passing each output as context to the next agent. USE THIS WHEN: tasks have dependencies — e.g., first research a topic, then write an article based on findings, then review the article.',\n parameters: {\n type: 'object',\n properties: {\n steps: {\n type: 'string',\n description: 'JSON array of step objects: [{\"role\": \"researcher\", \"task\": \"...\"}, {\"role\": \"writer\", \"task\": \"...\"}]. Each step gets the previous step\\'s output as context.',\n },\n },\n required: ['steps'],\n },\n execute: async (args: Record<string, unknown>): Promise<string> => {\n let steps: ChainStep[];\n try {\n const raw = args.steps as string;\n steps = JSON.parse(raw) as ChainStep[];\n } catch {\n return 'Error: \"steps\" must be a valid JSON array of {role, task} objects.';\n }\n\n if (!Array.isArray(steps) || steps.length === 0) {\n return 'Error: \"steps\" must be a non-empty array.';\n }\n\n if (steps.length > 8) {\n return 'Error: Maximum 8 chain steps allowed.';\n }\n\n logger.info(COMPONENT, `Running agent chain: ${steps.length} sequential steps`);\n\n const intermediateResults: Array<{ role: string; task: string; content: string; success: boolean }> = [];\n let previousOutput = '';\n\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i];\n const context = previousOutput\n ? `Output from previous step (${intermediateResults[i - 1]?.role || 'unknown'}):\\n${previousOutput}`\n : undefined;\n\n logger.info(COMPONENT, `Chain step ${i + 1}/${steps.length}: ${step.role}`);\n\n await setAgentStatus(step.role, 'active');\n try {\n const config = resolveRole(step.role, step.task, context);\n const result = await spawnSubAgent(config);\n await setAgentStatus(step.role, 'idle');\n\n intermediateResults.push({\n role: step.role,\n task: step.task,\n content: result.content,\n success: result.success,\n });\n\n previousOutput = result.content;\n\n // If a step fails, continue but note it\n if (!result.success) {\n logger.warn(COMPONENT, `Chain step ${i + 1} (${step.role}) failed, continuing with partial output`);\n }\n } catch (err) {\n await setAgentStatus(step.role, 'idle');\n throw err;\n }\n }\n\n const stepSummaries = intermediateResults.map((r, i) => {\n const status = r.success ? 'SUCCESS' : 'FAILED';\n return `## Step ${i + 1}: ${r.role} [${status}]\\nTask: ${r.task}\\n\\n${r.content}`;\n });\n\n const finalResult = intermediateResults[intermediateResults.length - 1];\n return `# Agent Chain Results (${steps.length} steps)\\n\\n${stepSummaries.join('\\n\\n---\\n\\n')}\\n\\n---\\n\\n## Final Output\\n${finalResult?.content || 'No output'}`;\n },\n};\n\n// ─── Tool: agent_critique ───────────────────────────────────────────\n\nconst critiqueHandler = {\n name: 'agent_critique',\n description: 'Generate-critique loop: one agent produces output, another critiques it, then the first agent improves based on feedback. Repeats for the specified number of rounds. USE THIS WHEN: you need high-quality output that benefits from iterative refinement — articles, code, analyses, proposals.',\n parameters: {\n type: 'object',\n properties: {\n task: {\n type: 'string',\n description: 'The task to generate output for',\n },\n generatorRole: {\n type: 'string',\n description: 'Role for the generator agent (default: \"writer\")',\n },\n criticRole: {\n type: 'string',\n description: 'Role for the critic agent (default: \"reviewer\")',\n },\n rounds: {\n type: 'number',\n description: 'Number of generate-critique cycles (default: 2, max: 5)',\n },\n },\n required: ['task'],\n },\n execute: async (args: Record<string, unknown>): Promise<string> => {\n const task = args.task as string;\n const generatorRole = (args.generatorRole as string) || 'writer';\n const criticRole = (args.criticRole as string) || 'reviewer';\n const rounds = Math.min(Math.max((args.rounds as number) || 2, 1), 5);\n\n if (!task) {\n return 'Error: \"task\" is required.';\n }\n\n logger.info(COMPONENT, `Starting critique loop: ${generatorRole} + ${criticRole}, ${rounds} rounds`);\n\n let currentOutput = '';\n const history: Array<{ round: number; type: 'generation' | 'critique'; content: string }> = [];\n\n for (let round = 1; round <= rounds; round++) {\n // ── Generate ──\n const genContext = round === 1\n ? undefined\n : `Previous version:\\n${currentOutput}\\n\\nCritique feedback:\\n${history[history.length - 1]?.content || 'No feedback'}`;\n\n const genTask = round === 1\n ? task\n : `Improve the following work based on the critique feedback. Original task: ${task}`;\n\n const genConfig = resolveRole(generatorRole, genTask, genContext);\n const genResult = await spawnSubAgent(genConfig);\n\n currentOutput = genResult.content;\n history.push({ round, type: 'generation', content: genResult.content });\n\n logger.info(COMPONENT, `Critique round ${round}/${rounds}: generation complete`);\n\n // ── Critique (skip on last round — final output is the last generation) ──\n if (round < rounds) {\n const critiqueTask = `Critically review the following output. Identify strengths, weaknesses, errors, and specific improvements. Be constructive but thorough.\\n\\nOriginal task: ${task}`;\n const critiqueContext = `Content to review:\\n${currentOutput}`;\n\n const critiqueConfig = resolveRole(criticRole, critiqueTask, critiqueContext);\n const critiqueResult = await spawnSubAgent(critiqueConfig);\n\n history.push({ round, type: 'critique', content: critiqueResult.content });\n\n logger.info(COMPONENT, `Critique round ${round}/${rounds}: critique complete`);\n }\n }\n\n const roundSummaries = history.map(h => {\n const label = h.type === 'generation' ? `Round ${h.round} — Generation` : `Round ${h.round} — Critique`;\n return `## ${label}\\n${h.content}`;\n });\n\n return `# Agent Critique Results (${rounds} rounds: ${generatorRole} + ${criticRole})\\n\\n${roundSummaries.join('\\n\\n---\\n\\n')}\\n\\n---\\n\\n## Final Output\\n${currentOutput}`;\n },\n};\n\n// ─── Registration ───────────────────────────────────────────────────\n\nexport function registerAgentHandoffSkill(): void {\n const meta = {\n name: 'agent-handoff',\n description: 'Agent handoff and delegation — delegate tasks to specialists, run agent teams in parallel, chain agents sequentially, or use generate-critique loops for quality output.',\n version: '1.0.0',\n source: 'bundled' as const,\n enabled: true,\n };\n\n registerSkill(meta, delegateHandler);\n registerSkill(meta, teamHandler);\n registerSkill(meta, chainHandler);\n registerSkill(meta, critiqueHandler);\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { homedir } from "os";
3
3
  import { join } from "path";
4
- const TITAN_VERSION = "5.5.22";
4
+ const TITAN_VERSION = "5.5.23";
5
5
  const TITAN_CODENAME = "Spacewalk";
6
6
  const TITAN_NAME = "TITAN";
7
7
  const TITAN_FULL_NAME = "The Intelligent Task Automation Network";
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/constants.ts"],"sourcesContent":["/**\n * TITAN Constants\n */\nimport { homedir } from 'os';\nimport { join } from 'path';\n\nexport const TITAN_VERSION = '5.5.22';\nexport const TITAN_CODENAME = 'Spacewalk';\nexport const TITAN_NAME = 'TITAN';\nexport const TITAN_FULL_NAME = 'The Intelligent Task Automation Network';\nexport const TITAN_ASCII_LOGO = `\n╔══════════════════════════════════════════════════════╗\n║ ║\n║ ████████╗██╗████████╗ █████╗ ███╗ ██╗ ║\n║ ██║ ██║ ██║ ██╔══██╗████╗ ██║ ║\n║ ██║ ██║ ██║ ███████║██╔██╗ ██║ ║\n║ ██║ ██║ ██║ ██╔══██║██║╚██╗██║ ║\n║ ██║ ██║ ██║ ██║ ██║██║ ╚████║ ║\n║ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ║\n║ ║\n║ The Intelligent Task Automation Network ║\n║ v${TITAN_VERSION} • by Tony Elliott ║\n╚══════════════════════════════════════════════════════╝`;\n\n// Paths\n// Hunt Finding #03 (2026-04-14): honor TITAN_HOME env var if set.\n// Previously this was hardcoded to `~/.titan`, which meant:\n// - Docker containers couldn't override the config path\n// - Shared machines couldn't isolate per-user state\n// - Test fixtures couldn't run against an isolated home\n// - The systemd unit's `Environment=TITAN_HOME=...` was silently ignored\n// The env var is read once at module load (constants are resolved at import time).\n// If TITAN_HOME starts with `~/`, expand it to the user's home dir.\nfunction resolveTitanHome(): string {\n const envHome = process.env.TITAN_HOME;\n if (envHome && envHome.trim().length > 0) {\n const trimmed = envHome.trim();\n if (trimmed.startsWith('~/')) {\n return join(homedir(), trimmed.slice(2));\n }\n if (trimmed === '~') {\n return homedir();\n }\n return trimmed;\n }\n return join(homedir(), '.titan');\n}\nexport const TITAN_HOME = resolveTitanHome();\nexport const TITAN_CONFIG_PATH = join(TITAN_HOME, 'titan.json');\nexport const TITAN_DB_PATH = join(TITAN_HOME, 'titan.db');\nexport const TITAN_WORKSPACE = join(TITAN_HOME, 'workspace');\nexport const TITAN_SKILLS_DIR = join(TITAN_WORKSPACE, 'skills');\nexport const TITAN_LOGS_DIR = join(TITAN_HOME, 'logs');\nexport const TITAN_MEMORY_DIR = join(TITAN_HOME, 'memory');\n\n// Workspace prompt files (injected into agent context)\nexport const AGENTS_MD = join(TITAN_WORKSPACE, 'AGENTS.md');\nexport const SOUL_MD = join(TITAN_WORKSPACE, 'SOUL.md');\nexport const TOOLS_MD = join(TITAN_WORKSPACE, 'TOOLS.md');\nexport const TITAN_MD_FILENAME = 'TITAN.md';\nexport const AUTOPILOT_MD = join(TITAN_HOME, 'AUTOPILOT.md');\nexport const AUTOPILOT_RUNS_PATH = join(TITAN_HOME, 'autopilot-runs.jsonl');\nexport const TITAN_CREDENTIALS_DIR = join(TITAN_HOME, 'credentials');\n\n// Income & lead tracking\nexport const INCOME_LEDGER_PATH = join(TITAN_HOME, 'income-ledger.jsonl');\nexport const FREELANCE_LEADS_PATH = join(TITAN_HOME, 'freelance-leads.jsonl');\nexport const FREELANCE_PROFILE_PATH = join(TITAN_HOME, 'freelance-profile.json');\nexport const LEADS_PATH = join(TITAN_HOME, 'leads.jsonl');\nexport const TELEMETRY_EVENTS_PATH = join(TITAN_HOME, 'telemetry-events.jsonl');\nexport const SOMADRIVE_STATE_PATH = join(TITAN_HOME, 'soma-drive-state.json');\nexport const ACTIVITY_LOG_PATH = join(TITAN_HOME, 'activity-log.jsonl');\n\n// Gateway defaults\nexport const DEFAULT_GATEWAY_HOST = '0.0.0.0';\nexport const DEFAULT_GATEWAY_PORT = 48420;\nexport const DEFAULT_WEB_PORT = 48421;\n\n// Agent defaults\nexport const DEFAULT_MODEL = 'anthropic/claude-sonnet-4-20250514';\n/** v5.4.1: User-preference ceiling. Providers clamp per-model via\n * clampMaxTokens() so this can be high without causing 400s on\n * capped endpoints (e.g. Claude Sonnet 4 8K, Cohere 4K). */\nexport const DEFAULT_MAX_TOKENS = 200000;\nexport const DEFAULT_TEMPERATURE = 0.7;\nexport const MAX_CONTEXT_MESSAGES = 50;\nexport const SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes\n\n// Security\nexport const DEFAULT_SANDBOX_MODE = 'host';\n/** Default allowed tools. Empty = allow ALL registered tools.\n * Use security.deniedTools to block specific tools instead. */\nexport const ALLOWED_TOOLS_DEFAULT: string[] = [];\nexport const DENIED_TOOLS_DEFAULT: string[] = [];\n"],"mappings":";AAGA,SAAS,eAAe;AACxB,SAAS,YAAY;AAEd,MAAM,gBAAgB;AACtB,MAAM,iBAAiB;AACvB,MAAM,aAAa;AACnB,MAAM,kBAAkB;AACxB,MAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAW1B,aAAa;AAAA;AAYnB,SAAS,mBAA2B;AAChC,QAAM,UAAU,QAAQ,IAAI;AAC5B,MAAI,WAAW,QAAQ,KAAK,EAAE,SAAS,GAAG;AACtC,UAAM,UAAU,QAAQ,KAAK;AAC7B,QAAI,QAAQ,WAAW,IAAI,GAAG;AAC1B,aAAO,KAAK,QAAQ,GAAG,QAAQ,MAAM,CAAC,CAAC;AAAA,IAC3C;AACA,QAAI,YAAY,KAAK;AACjB,aAAO,QAAQ;AAAA,IACnB;AACA,WAAO;AAAA,EACX;AACA,SAAO,KAAK,QAAQ,GAAG,QAAQ;AACnC;AACO,MAAM,aAAa,iBAAiB;AACpC,MAAM,oBAAoB,KAAK,YAAY,YAAY;AACvD,MAAM,gBAAgB,KAAK,YAAY,UAAU;AACjD,MAAM,kBAAkB,KAAK,YAAY,WAAW;AACpD,MAAM,mBAAmB,KAAK,iBAAiB,QAAQ;AACvD,MAAM,iBAAiB,KAAK,YAAY,MAAM;AAC9C,MAAM,mBAAmB,KAAK,YAAY,QAAQ;AAGlD,MAAM,YAAY,KAAK,iBAAiB,WAAW;AACnD,MAAM,UAAU,KAAK,iBAAiB,SAAS;AAC/C,MAAM,WAAW,KAAK,iBAAiB,UAAU;AACjD,MAAM,oBAAoB;AAC1B,MAAM,eAAe,KAAK,YAAY,cAAc;AACpD,MAAM,sBAAsB,KAAK,YAAY,sBAAsB;AACnE,MAAM,wBAAwB,KAAK,YAAY,aAAa;AAG5D,MAAM,qBAAqB,KAAK,YAAY,qBAAqB;AACjE,MAAM,uBAAuB,KAAK,YAAY,uBAAuB;AACrE,MAAM,yBAAyB,KAAK,YAAY,wBAAwB;AACxE,MAAM,aAAa,KAAK,YAAY,aAAa;AACjD,MAAM,wBAAwB,KAAK,YAAY,wBAAwB;AACvE,MAAM,uBAAuB,KAAK,YAAY,uBAAuB;AACrE,MAAM,oBAAoB,KAAK,YAAY,oBAAoB;AAG/D,MAAM,uBAAuB;AAC7B,MAAM,uBAAuB;AAC7B,MAAM,mBAAmB;AAGzB,MAAM,gBAAgB;AAItB,MAAM,qBAAqB;AAC3B,MAAM,sBAAsB;AAC5B,MAAM,uBAAuB;AAC7B,MAAM,qBAAqB,KAAK,KAAK;AAGrC,MAAM,uBAAuB;AAG7B,MAAM,wBAAkC,CAAC;AACzC,MAAM,uBAAiC,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../src/utils/constants.ts"],"sourcesContent":["/**\n * TITAN Constants\n */\nimport { homedir } from 'os';\nimport { join } from 'path';\n\nexport const TITAN_VERSION = '5.5.23';\nexport const TITAN_CODENAME = 'Spacewalk';\nexport const TITAN_NAME = 'TITAN';\nexport const TITAN_FULL_NAME = 'The Intelligent Task Automation Network';\nexport const TITAN_ASCII_LOGO = `\n╔══════════════════════════════════════════════════════╗\n║ ║\n║ ████████╗██╗████████╗ █████╗ ███╗ ██╗ ║\n║ ██║ ██║ ██║ ██╔══██╗████╗ ██║ ║\n║ ██║ ██║ ██║ ███████║██╔██╗ ██║ ║\n║ ██║ ██║ ██║ ██╔══██║██║╚██╗██║ ║\n║ ██║ ██║ ██║ ██║ ██║██║ ╚████║ ║\n║ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ║\n║ ║\n║ The Intelligent Task Automation Network ║\n║ v${TITAN_VERSION} • by Tony Elliott ║\n╚══════════════════════════════════════════════════════╝`;\n\n// Paths\n// Hunt Finding #03 (2026-04-14): honor TITAN_HOME env var if set.\n// Previously this was hardcoded to `~/.titan`, which meant:\n// - Docker containers couldn't override the config path\n// - Shared machines couldn't isolate per-user state\n// - Test fixtures couldn't run against an isolated home\n// - The systemd unit's `Environment=TITAN_HOME=...` was silently ignored\n// The env var is read once at module load (constants are resolved at import time).\n// If TITAN_HOME starts with `~/`, expand it to the user's home dir.\nfunction resolveTitanHome(): string {\n const envHome = process.env.TITAN_HOME;\n if (envHome && envHome.trim().length > 0) {\n const trimmed = envHome.trim();\n if (trimmed.startsWith('~/')) {\n return join(homedir(), trimmed.slice(2));\n }\n if (trimmed === '~') {\n return homedir();\n }\n return trimmed;\n }\n return join(homedir(), '.titan');\n}\nexport const TITAN_HOME = resolveTitanHome();\nexport const TITAN_CONFIG_PATH = join(TITAN_HOME, 'titan.json');\nexport const TITAN_DB_PATH = join(TITAN_HOME, 'titan.db');\nexport const TITAN_WORKSPACE = join(TITAN_HOME, 'workspace');\nexport const TITAN_SKILLS_DIR = join(TITAN_WORKSPACE, 'skills');\nexport const TITAN_LOGS_DIR = join(TITAN_HOME, 'logs');\nexport const TITAN_MEMORY_DIR = join(TITAN_HOME, 'memory');\n\n// Workspace prompt files (injected into agent context)\nexport const AGENTS_MD = join(TITAN_WORKSPACE, 'AGENTS.md');\nexport const SOUL_MD = join(TITAN_WORKSPACE, 'SOUL.md');\nexport const TOOLS_MD = join(TITAN_WORKSPACE, 'TOOLS.md');\nexport const TITAN_MD_FILENAME = 'TITAN.md';\nexport const AUTOPILOT_MD = join(TITAN_HOME, 'AUTOPILOT.md');\nexport const AUTOPILOT_RUNS_PATH = join(TITAN_HOME, 'autopilot-runs.jsonl');\nexport const TITAN_CREDENTIALS_DIR = join(TITAN_HOME, 'credentials');\n\n// Income & lead tracking\nexport const INCOME_LEDGER_PATH = join(TITAN_HOME, 'income-ledger.jsonl');\nexport const FREELANCE_LEADS_PATH = join(TITAN_HOME, 'freelance-leads.jsonl');\nexport const FREELANCE_PROFILE_PATH = join(TITAN_HOME, 'freelance-profile.json');\nexport const LEADS_PATH = join(TITAN_HOME, 'leads.jsonl');\nexport const TELEMETRY_EVENTS_PATH = join(TITAN_HOME, 'telemetry-events.jsonl');\nexport const SOMADRIVE_STATE_PATH = join(TITAN_HOME, 'soma-drive-state.json');\nexport const ACTIVITY_LOG_PATH = join(TITAN_HOME, 'activity-log.jsonl');\n\n// Gateway defaults\nexport const DEFAULT_GATEWAY_HOST = '0.0.0.0';\nexport const DEFAULT_GATEWAY_PORT = 48420;\nexport const DEFAULT_WEB_PORT = 48421;\n\n// Agent defaults\nexport const DEFAULT_MODEL = 'anthropic/claude-sonnet-4-20250514';\n/** v5.4.1: User-preference ceiling. Providers clamp per-model via\n * clampMaxTokens() so this can be high without causing 400s on\n * capped endpoints (e.g. Claude Sonnet 4 8K, Cohere 4K). */\nexport const DEFAULT_MAX_TOKENS = 200000;\nexport const DEFAULT_TEMPERATURE = 0.7;\nexport const MAX_CONTEXT_MESSAGES = 50;\nexport const SESSION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes\n\n// Security\nexport const DEFAULT_SANDBOX_MODE = 'host';\n/** Default allowed tools. Empty = allow ALL registered tools.\n * Use security.deniedTools to block specific tools instead. */\nexport const ALLOWED_TOOLS_DEFAULT: string[] = [];\nexport const DENIED_TOOLS_DEFAULT: string[] = [];\n"],"mappings":";AAGA,SAAS,eAAe;AACxB,SAAS,YAAY;AAEd,MAAM,gBAAgB;AACtB,MAAM,iBAAiB;AACvB,MAAM,aAAa;AACnB,MAAM,kBAAkB;AACxB,MAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAW1B,aAAa;AAAA;AAYnB,SAAS,mBAA2B;AAChC,QAAM,UAAU,QAAQ,IAAI;AAC5B,MAAI,WAAW,QAAQ,KAAK,EAAE,SAAS,GAAG;AACtC,UAAM,UAAU,QAAQ,KAAK;AAC7B,QAAI,QAAQ,WAAW,IAAI,GAAG;AAC1B,aAAO,KAAK,QAAQ,GAAG,QAAQ,MAAM,CAAC,CAAC;AAAA,IAC3C;AACA,QAAI,YAAY,KAAK;AACjB,aAAO,QAAQ;AAAA,IACnB;AACA,WAAO;AAAA,EACX;AACA,SAAO,KAAK,QAAQ,GAAG,QAAQ;AACnC;AACO,MAAM,aAAa,iBAAiB;AACpC,MAAM,oBAAoB,KAAK,YAAY,YAAY;AACvD,MAAM,gBAAgB,KAAK,YAAY,UAAU;AACjD,MAAM,kBAAkB,KAAK,YAAY,WAAW;AACpD,MAAM,mBAAmB,KAAK,iBAAiB,QAAQ;AACvD,MAAM,iBAAiB,KAAK,YAAY,MAAM;AAC9C,MAAM,mBAAmB,KAAK,YAAY,QAAQ;AAGlD,MAAM,YAAY,KAAK,iBAAiB,WAAW;AACnD,MAAM,UAAU,KAAK,iBAAiB,SAAS;AAC/C,MAAM,WAAW,KAAK,iBAAiB,UAAU;AACjD,MAAM,oBAAoB;AAC1B,MAAM,eAAe,KAAK,YAAY,cAAc;AACpD,MAAM,sBAAsB,KAAK,YAAY,sBAAsB;AACnE,MAAM,wBAAwB,KAAK,YAAY,aAAa;AAG5D,MAAM,qBAAqB,KAAK,YAAY,qBAAqB;AACjE,MAAM,uBAAuB,KAAK,YAAY,uBAAuB;AACrE,MAAM,yBAAyB,KAAK,YAAY,wBAAwB;AACxE,MAAM,aAAa,KAAK,YAAY,aAAa;AACjD,MAAM,wBAAwB,KAAK,YAAY,wBAAwB;AACvE,MAAM,uBAAuB,KAAK,YAAY,uBAAuB;AACrE,MAAM,oBAAoB,KAAK,YAAY,oBAAoB;AAG/D,MAAM,uBAAuB;AAC7B,MAAM,uBAAuB;AAC7B,MAAM,mBAAmB;AAGzB,MAAM,gBAAgB;AAItB,MAAM,qBAAqB;AAC3B,MAAM,sBAAsB;AAC5B,MAAM,uBAAuB;AAC7B,MAAM,qBAAqB,KAAK,KAAK;AAGrC,MAAM,uBAAuB;AAG7B,MAAM,wBAAkC,CAAC;AACzC,MAAM,uBAAiC,CAAC;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "titan-agent",
3
- "version": "5.5.22",
3
+ "version": "5.5.23",
4
4
  "description": "TITAN — Autonomous AI agent framework with self-improvement, multi-agent orchestration, 36 LLM providers, 16 channel adapters, GPU VRAM management, mesh networking, LiveKit voice, TITAN-Soma homeostatic drives, and a React Mission Control dashboard. Open-source, TypeScript, MIT licensed.",
5
5
  "author": "Tony Elliott (https://github.com/Djtony707)",
6
6
  "repository": {