From 1c1c5fe8fbd8e8c5162ed1431c7cfd452db7c6a8 Mon Sep 17 00:00:00 2001 From: AJ Date: Thu, 19 Feb 2026 21:03:06 -0800 Subject: [PATCH] Consolidate agent delegation prompt --- apps/desktop/src/main/acp/acp-smart-router.ts | 40 ++----- apps/desktop/src/main/system-prompts.test.ts | 2 +- apps/desktop/src/main/system-prompts.ts | 103 ++++++------------ 3 files changed, 46 insertions(+), 99 deletions(-) diff --git a/apps/desktop/src/main/acp/acp-smart-router.ts b/apps/desktop/src/main/acp/acp-smart-router.ts index cb7e9c929..25ed51ef2 100644 --- a/apps/desktop/src/main/acp/acp-smart-router.ts +++ b/apps/desktop/src/main/acp/acp-smart-router.ts @@ -17,48 +17,28 @@ type ACPAgentForDelegationPrompt = { */ export class ACPSmartRouter { /** - * Generate system prompt text describing available agents. - * This text can be injected into the main AI's system prompt to inform it - * about delegation options. + * Format available ACP agents into compact delegation lines for a unified prompt. * * @param availableAgents - List of agents to include in the prompt - * @returns Formatted string for system prompt injection + * @returns Array of formatted lines for system prompt injection * * @example * ```typescript * const agents = acpRegistry.getReadyAgents() - * const promptAddition = acpSmartRouter.generateDelegationPromptAddition(agents) - * // Returns: "You have access to the following specialized agents..." + * const lines = acpSmartRouter.formatDelegationAgentLines(agents) + * // Returns: ["- **research-agent** (external): Web research and fact-finding", ...] * ``` */ - generateDelegationPromptAddition(availableAgents: ReadonlyArray): string { + formatDelegationAgentLines(availableAgents: ReadonlyArray): string[] { if (availableAgents.length === 0) { - return '' + return [] } - const agentDescriptions = availableAgents.map(agent => { + return availableAgents.map(agent => { const def = agent.definition - return `- **${def.displayName || def.name}**: ${def.description || 'No description available'}` - }).join('\n') - - return ` -## Available Specialized Agents - -You have access to the following specialized agents that can help with specific tasks. -Consider delegating work to these agents when appropriate: - -${agentDescriptions} - -### When to Delegate -- Use the **research** agent for information gathering, web searches, and fact-finding -- Use the **coding** agent for complex programming tasks, debugging, or code generation -- Use the **analysis** agent for data analysis, comparisons, and evaluations -- Use the **writing** agent for document creation, summarization, and content drafting - -### How to Delegate -Use the delegate_to_agent tool with the agent name and a clear task description. -Monitor the agent's progress and incorporate its results into your response. -`.trim() + const summary = (def.description || def.displayName || 'External agent').trim() + return `- **${def.name}** (external): ${summary}` + }) } } diff --git a/apps/desktop/src/main/system-prompts.test.ts b/apps/desktop/src/main/system-prompts.test.ts index f6f5ab3b2..dcf8fe1f7 100644 --- a/apps/desktop/src/main/system-prompts.test.ts +++ b/apps/desktop/src/main/system-prompts.test.ts @@ -3,7 +3,7 @@ import { describe, it, expect, vi, beforeEach } from "vitest" // Avoid pulling in real ACP/services (can have side effects / require Electron runtime) vi.mock("./acp/acp-smart-router", () => ({ acpSmartRouter: { - generateDelegationPromptAddition: () => "", + formatDelegationAgentLines: () => [], }, })) diff --git a/apps/desktop/src/main/system-prompts.ts b/apps/desktop/src/main/system-prompts.ts index 74a4aaac5..0e83e8a54 100644 --- a/apps/desktop/src/main/system-prompts.ts +++ b/apps/desktop/src/main/system-prompts.ts @@ -128,74 +128,50 @@ function formatLightweightToolInfo( } /** - * Generate ACP routing prompt addition based on available agents. - * Returns an empty string if no agents are ready. + * Generate a unified prompt addition for ACP agents, personas, and the internal agent. + * Returns an empty string only if there are no delegation entries at all. */ -export function getACPRoutingPromptAddition(): string { - // Get agents from acpService which has runtime status - const agentStatuses = acpService.getAgents() +export function getAgentDelegationPromptAddition(): string { + const lines: string[] = [] - // Filter to only ready agents + // ACP agents (external) + const agentStatuses = acpService.getAgents() const readyAgents = agentStatuses.filter(a => a.status === 'ready') - - if (readyAgents.length === 0) { - return '' + if (readyAgents.length > 0) { + const formattedAgents = readyAgents.map(a => ({ + definition: { + name: a.config.name, + displayName: a.config.displayName, + description: a.config.description || '', + }, + })) + lines.push(...acpSmartRouter.formatDelegationAgentLines(formattedAgents)) } - // Format agents for the smart router - const formattedAgents = readyAgents.map(a => ({ - definition: { - name: a.config.name, - displayName: a.config.displayName, - description: a.config.description || '', - }, - status: 'ready' as const, - activeRuns: 0, - })) - - return acpSmartRouter.generateDelegationPromptAddition(formattedAgents) -} - -/** - * Generate prompt addition for the internal agent. - * This instructs the agent on when and how to use the internal agent for parallel work. - */ -export function getSubSessionPromptAddition(): string { - const info = getInternalAgentInfo() - - return ` -INTERNAL AGENT: Use \`delegate_to_agent\` with \`agentName: "internal"\` to spawn parallel sub-agents. Batch multiple calls for efficiency. -- USE FOR: Independent parallel tasks (analyzing multiple files, researching different topics, divide-and-conquer) -- AVOID FOR: Sequential dependencies, shared state/file conflicts, simple tasks -- LIMITS: Max depth ${info.maxRecursionDepth}, max ${info.maxConcurrent} concurrent per parent -`.trim() -} - -/** - * Generate prompt addition for available agent personas (delegation-targets). - * These are internal personas that can be delegated to via delegate_to_agent. - * Similar format to tools/skills for easy discoverability. - */ -export function getAgentPersonasPromptAddition(): string { - // Get enabled delegation-target profiles + // Personas (delegation-targets) const delegationTargets = agentProfileService.getByRole('delegation-target') .filter(p => p.enabled) + if (delegationTargets.length > 0) { + const personaLines = delegationTargets.map(p => { + const summary = (p.description || p.displayName || 'General tasks').trim() + return `- **${p.name}** (persona): ${summary}` + }) + lines.push(...personaLines) + } - if (delegationTargets.length === 0) { + // Internal agent (always available in agent mode) + const info = getInternalAgentInfo() + lines.push(`- **internal**: Spawn parallel sub-agents (max depth ${info.maxRecursionDepth}, max ${info.maxConcurrent} concurrent)`) + + if (lines.length === 0) { return '' } - // Format personas in a compact, discoverable format similar to tools/skills - const personasList = delegationTargets.map(p => { - return `- **${p.name}**: ${p.description || p.displayName || 'No description'}` - }).join('\n') - return ` -AVAILABLE AGENT PERSONAS (${delegationTargets.length}): -${personasList} +AVAILABLE AGENTS (delegate via delegate_to_agent): +${lines.join('\n')} -To delegate: \`delegate_to_agent(agentName: "persona_name", task: "...")\` -When user mentions a persona by name (e.g., "ask joker...", "have coder..."), delegate to that persona. +Delegate when user mentions an agent by name or task matches agent specialty. `.trim() } @@ -222,20 +198,11 @@ export function constructSystemPrompt( if (isAgentMode) { prompt += AGENT_MODE_ADDITIONS - // Add ACP agent delegation information if agents are available - const acpPromptAddition = getACPRoutingPromptAddition() - if (acpPromptAddition) { - prompt += '\n\n' + acpPromptAddition + // Add unified agent delegation block (ACP agents, personas, internal agent) + const delegationAddition = getAgentDelegationPromptAddition() + if (delegationAddition) { + prompt += '\n\n' + delegationAddition } - - // Add agent personas (delegation-targets) in a discoverable format - const personasAddition = getAgentPersonasPromptAddition() - if (personasAddition) { - prompt += '\n\n' + personasAddition - } - - // Add internal sub-session instructions (always available in agent mode) - prompt += '\n\n' + getSubSessionPromptAddition() } // Add agent skills instructions if provided