From 2fc19f69ca02787a14badb7ed55ef72688307606 Mon Sep 17 00:00:00 2001 From: can1357 Date: Sat, 31 Jan 2026 10:03:50 +0100 Subject: [PATCH] feat(coding-agent): added subagent context passing and automatic tool injection for agent sessions - Added getCompactContext() API to agent session for accessing parent conversation context. - Implemented automatic submit_result tool injection for subagents with explicit tool lists. - Added contextFile parameter to ExecutorOptions for passing parent conversation context to subagents. - Enhanced subagent system prompt with conditional context file instructions and improved code formatting. - Removed schema override notification from task summary prompt to simplify output. - Implemented formatCompactContext() method to format conversation history for subagent consumption. --- packages/coding-agent/CHANGELOG.md | 14 +++++ .../coding-agent/src/discovery/helpers.ts | 7 ++- .../prompts/system/subagent-system-prompt.md | 21 ++++--- .../src/prompts/tools/task-summary.md | 7 --- packages/coding-agent/src/sdk.ts | 1 + .../coding-agent/src/session/agent-session.ts | 63 +++++++++++++++++++ packages/coding-agent/src/task/executor.ts | 3 + packages/coding-agent/src/task/index.ts | 14 ++++- packages/coding-agent/src/tools/index.ts | 2 + 9 files changed, 114 insertions(+), 18 deletions(-) diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 7f98c9de0..9a29cfb17 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -1,6 +1,20 @@ # Changelog ## [Unreleased] +### Added + +- Added `getCompactContext()` API to retrieve parent conversation context for subagents, excluding system prompts and tool results +- Added automatic `submit_result` tool injection for subagents with explicit tool lists +- Added `contextFile` parameter to pass parent conversation context to subagent sessions + +### Changed + +- Updated subagent system prompt to reference parent conversation context file when available +- Enhanced subagent system prompt formatting with clearer backtick notation for tool and parameter names + +### Removed + +- Removed schema override notification from task summary prompt ## [9.2.5] - 2026-01-31 ### Changed diff --git a/packages/coding-agent/src/discovery/helpers.ts b/packages/coding-agent/src/discovery/helpers.ts index ada59df22..eb0cfaf5d 100644 --- a/packages/coding-agent/src/discovery/helpers.ts +++ b/packages/coding-agent/src/discovery/helpers.ts @@ -189,7 +189,12 @@ export function parseAgentFields(frontmatter: Record): ParsedAg return null; } - const tools = parseArrayOrCSV(frontmatter.tools); + let tools = parseArrayOrCSV(frontmatter.tools); + + // Subagents with explicit tool lists always need submit_result + if (tools && !tools.includes("submit_result")) { + tools = [...tools, "submit_result"]; + } // Parse spawns field (array, "*", or CSV) let spawns: string[] | "*" | undefined; diff --git a/packages/coding-agent/src/prompts/system/subagent-system-prompt.md b/packages/coding-agent/src/prompts/system/subagent-system-prompt.md index c65a683a7..ab5c67b78 100644 --- a/packages/coding-agent/src/prompts/system/subagent-system-prompt.md +++ b/packages/coding-agent/src/prompts/system/subagent-system-prompt.md @@ -1,24 +1,31 @@ {{base}} ------------------------------------ + +==================================================== {{agent}} +{{#if contextFile}} + +If you need additional context about the parent conversation, check {{contextFile}} (e.g., `tail -100` or `grep` for relevant terms). + +{{/if}} + {{#if worktree}} - You MUST work under this working tree: {{worktree}}. Do not modify anything under the original repository. {{/if}} -- You MUST call the submit_result tool exactly once when finished. Do not output JSON in text. Do not end with a plain-text summary. Call submit_result with your result as the data parameter. +- You MUST call the `submit_result` tool exactly once when finished. Do not output JSON in text. Do not end with a plain-text summary. Call `submit_result` with your result as the `data` parameter. {{#if outputSchema}} -- If you cannot complete the task, call submit_result with status="aborted" and an error message. Do not provide a success result or pretend completion. +- If you cannot complete the task, call `submit_result` with `status="aborted"` and an error message. Do not provide a success result or pretend completion. {{else}} -- If you cannot complete the task, call submit_result with status="aborted" and an error message. Do not claim success. +- If you cannot complete the task, call `submit_result` with `status="aborted"` and an error message. Do not claim success. {{/if}} {{#if outputSchema}} -- The data parameter MUST be valid JSON matching this TypeScript interface: -```typescript +- The `data` parameter MUST be valid JSON matching this TypeScript interface: +```ts {{jtdToTypeScript outputSchema}} ``` {{/if}} -- If you cannot complete the task, call submit_result exactly once with a result that explicitly indicates failure or abort status (use a failure/notes field if available). Do not claim success. +- If you cannot complete the task, call `submit_result` exactly once with a result that explicitly indicates failure or abort status (use a failure/notes field if available). Do not claim success. - Keep going until request is fully fulfilled. This matters. \ No newline at end of file diff --git a/packages/coding-agent/src/prompts/tools/task-summary.md b/packages/coding-agent/src/prompts/tools/task-summary.md index e81743aad..f8de1ac68 100644 --- a/packages/coding-agent/src/prompts/tools/task-summary.md +++ b/packages/coding-agent/src/prompts/tools/task-summary.md @@ -20,13 +20,6 @@ {{/unless}} {{/each}} -{{#if schemaOverridden}} - -Note: Agent '{{agentName}}' has a fixed output schema: -{{requiredSchema}} - -{{/if}} - {{#if patchApplySummary}} {{patchApplySummary}} diff --git a/packages/coding-agent/src/sdk.ts b/packages/coding-agent/src/sdk.ts index 4ef5cc77a..676b496bb 100644 --- a/packages/coding-agent/src/sdk.ts +++ b/packages/coding-agent/src/sdk.ts @@ -760,6 +760,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {} return undefined; }, getPlanModeState: () => session.getPlanModeState(), + getCompactContext: () => session.formatCompactContext(), settings: settingsManager, settingsManager, authStorage, diff --git a/packages/coding-agent/src/session/agent-session.ts b/packages/coding-agent/src/session/agent-session.ts index 435736c84..06f5ecd13 100644 --- a/packages/coding-agent/src/session/agent-session.ts +++ b/packages/coding-agent/src/session/agent-session.ts @@ -3916,6 +3916,69 @@ Be thorough - include exact file paths, function names, error messages, and tech return lines.join("\n").trim(); } + /** + * Format the conversation as compact context for subagents. + * Includes only user messages and assistant text responses. + * Excludes: system prompt, tool definitions, tool calls/results, thinking blocks. + */ + formatCompactContext(): string { + const lines: string[] = []; + lines.push("# Conversation Context"); + lines.push(""); + lines.push( + "This is a summary of the parent conversation. Read this if you need additional context about what was discussed or decided.", + ); + lines.push(""); + + for (const msg of this.messages) { + if (msg.role === "user") { + lines.push("## User"); + lines.push(""); + if (typeof msg.content === "string") { + lines.push(msg.content); + } else { + for (const c of msg.content) { + if (c.type === "text") { + lines.push(c.text); + } else if (c.type === "image") { + lines.push("[Image attached]"); + } + } + } + lines.push(""); + } else if (msg.role === "assistant") { + const assistantMsg = msg as AssistantMessage; + // Only include text content, skip tool calls and thinking + const textParts: string[] = []; + for (const c of assistantMsg.content) { + if (c.type === "text" && c.text.trim()) { + textParts.push(c.text); + } + } + if (textParts.length > 0) { + lines.push("## Assistant"); + lines.push(""); + lines.push(textParts.join("\n\n")); + lines.push(""); + } + } else if (msg.role === "fileMention") { + const fileMsg = msg as FileMentionMessage; + const paths = fileMsg.files.map(f => f.path).join(", "); + lines.push(`[Files referenced: ${paths}]`); + lines.push(""); + } else if (msg.role === "compactionSummary") { + const compactMsg = msg as CompactionSummaryMessage; + lines.push("## Earlier Context (Summarized)"); + lines.push(""); + lines.push(compactMsg.summary); + lines.push(""); + } + // Skip: toolResult, bashExecution, pythonExecution, branchSummary, custom, hookMessage + } + + return lines.join("\n").trim(); + } + // ========================================================================= // Extension System // ========================================================================= diff --git a/packages/coding-agent/src/task/executor.ts b/packages/coding-agent/src/task/executor.ts index 57d8891f7..7d3b3ae3a 100644 --- a/packages/coding-agent/src/task/executor.ts +++ b/packages/coding-agent/src/task/executor.ts @@ -196,6 +196,8 @@ export interface ExecutorOptions { sessionFile?: string | null; persistArtifacts?: boolean; artifactsDir?: string; + /** Path to parent conversation context file */ + contextFile?: string; eventBus?: EventBus; contextFiles?: ContextFileEntry[]; skills?: Skill[]; @@ -948,6 +950,7 @@ export async function runSubprocess(options: ExecutorOptions): Promise params > inherited from parent session - const schemaOverridden = outputSchema !== undefined && effectiveAgent.output !== undefined; const effectiveOutputSchema = effectiveAgent.output ?? outputSchema ?? this.session.outputSchema; // Handle empty or missing tasks @@ -382,6 +381,15 @@ export class TaskTool implements AgentTool PlanModeState | undefined; + /** Get compact conversation context for subagents (excludes tool results, system prompts) */ + getCompactContext?: () => string; } type ToolFactory = (session: ToolSession) => Tool | null | Promise;