From eb8e4f765720f4b2d860c4b5be55af6cc5a6e217 Mon Sep 17 00:00:00 2001 From: can1357 Date: Fri, 5 Jun 2026 11:36:13 +0200 Subject: [PATCH] feat(task): added read-summarize override for subagents - Parsed `read-summarize` frontmatter into `readSummarize` field. - Applied `read.summarize.enabled: false` override on isolated subagent settings. - Disabled summarization for `explore` and `librarian` agents. --- docs/task-agent-discovery.md | 3 ++- .../coding-agent/src/discovery/helpers.ts | 4 +++- .../src/prompts/agents/explore.md | 1 + .../src/prompts/agents/librarian.md | 1 + packages/coding-agent/src/task/executor.ts | 11 +++++++-- packages/coding-agent/src/task/types.ts | 2 ++ .../test/discovery/agent-fields.test.ts | 23 +++++++++++++++++++ 7 files changed, 41 insertions(+), 4 deletions(-) diff --git a/docs/task-agent-discovery.md b/docs/task-agent-discovery.md index 502bb482e..82156f310 100644 --- a/docs/task-agent-discovery.md +++ b/docs/task-agent-discovery.md @@ -24,7 +24,7 @@ It covers runtime behavior as implemented today, including precedence, invalid-d Task agents normalize into `AgentDefinition` (`src/task/types.ts`): - `name`, `description`, `systemPrompt` (required for a valid loaded agent) -- optional `tools`, `spawns`, `model`, `thinkingLevel`, `output`, `blocking` +- optional `tools`, `spawns`, `model`, `thinkingLevel`, `output`, `blocking`, `autoloadSkills`, `readSummarize` - `source`: `"bundled" | "user" | "project"` - optional `filePath` @@ -35,6 +35,7 @@ Parsing comes from frontmatter via `parseAgentFields()` (`src/discovery/helpers. - `spawns` accepts `*`, CSV, or array - backward-compat behavior: if `spawns` missing but `tools` includes `task`, `spawns` becomes `*` - `output` is passed through as opaque schema data +- `read-summarize: false` (parsed as `readSummarize`) forces the subagent's `read` tool to return verbatim file content instead of structural summaries — `runSubprocess` applies it as a `read.summarize.enabled: false` override on the subagent's isolated settings (`src/task/executor.ts`). `explore` and `librarian` ship with it disabled. Defaults to enabled when the field is absent. ## Bundled agents diff --git a/packages/coding-agent/src/discovery/helpers.ts b/packages/coding-agent/src/discovery/helpers.ts index 72e200c67..ac6e92ad0 100644 --- a/packages/coding-agent/src/discovery/helpers.ts +++ b/packages/coding-agent/src/discovery/helpers.ts @@ -212,6 +212,7 @@ export interface ParsedAgentFields { output?: unknown; thinkingLevel?: ThinkingLevel; autoloadSkills?: string[]; + readSummarize?: boolean; blocking?: boolean; } @@ -265,10 +266,11 @@ export function parseAgentFields(frontmatter: Record): ParsedAg const thinkingLevel = parseThinkingLevel(rawThinkingLevel); const model = parseModelList(frontmatter.model); const blocking = parseBoolean(frontmatter.blocking); + const readSummarize = parseBoolean(frontmatter.readSummarize); const autoloadSkills = parseArrayOrCSV(frontmatter.autoloadSkills) ?.map(s => s.trim()) .filter(Boolean); - return { name, description, tools, spawns, model, output, thinkingLevel, blocking, autoloadSkills }; + return { name, description, tools, spawns, model, output, thinkingLevel, blocking, autoloadSkills, readSummarize }; } async function globIf( diff --git a/packages/coding-agent/src/prompts/agents/explore.md b/packages/coding-agent/src/prompts/agents/explore.md index 6ba32f97d..d7ceb117e 100644 --- a/packages/coding-agent/src/prompts/agents/explore.md +++ b/packages/coding-agent/src/prompts/agents/explore.md @@ -4,6 +4,7 @@ description: Fast read-only codebase scout returning compressed context for hand tools: read, search, find, web_search model: pi/smol thinking-level: med +read-summarize: false output: properties: summary: diff --git a/packages/coding-agent/src/prompts/agents/librarian.md b/packages/coding-agent/src/prompts/agents/librarian.md index a805c886c..766aaecfa 100644 --- a/packages/coding-agent/src/prompts/agents/librarian.md +++ b/packages/coding-agent/src/prompts/agents/librarian.md @@ -4,6 +4,7 @@ description: Researches external libraries and APIs by reading source code. Retu tools: read, search, find, bash, lsp, web_search, ast_grep model: pi/smol thinking-level: minimal +read-summarize: false output: properties: answer: diff --git a/packages/coding-agent/src/task/executor.ts b/packages/coding-agent/src/task/executor.ts index da5bada9d..c884bb468 100644 --- a/packages/coding-agent/src/task/executor.ts +++ b/packages/coding-agent/src/task/executor.ts @@ -531,7 +531,10 @@ function createMCPProxyTools(mcpManager: MCPManager): CustomTool[] { }); } -function createSubagentSettings(baseSettings: Settings): Settings { +function createSubagentSettings( + baseSettings: Settings, + overrides?: Partial>, +): Settings { const snapshot: Partial> = {}; for (const key of Object.keys(SETTINGS_SCHEMA) as SettingPath[]) { snapshot[key] = baseSettings.get(key); @@ -545,6 +548,7 @@ function createSubagentSettings(baseSettings: Settings): Settings { // the parent task approval is the authorization boundary. Use yolo mode // to preserve unattended subagent execution. User `tools.approval` policies still apply. "tools.approvalMode": "yolo", + ...overrides, }); } @@ -619,7 +623,10 @@ export async function runSubprocess(options: ExecutorOptions): Promise { expect(fields).toBeDefined(); expect(fields?.autoloadSkills).toBeUndefined(); }); + + test("parses readSummarize from boolean frontmatter", () => { + expect(parseAgentFields({ name: "explore", description: "desc", readSummarize: false })?.readSummarize).toBe( + false, + ); + expect(parseAgentFields({ name: "explore", description: "desc", readSummarize: true })?.readSummarize).toBe( + true, + ); + }); + + test("parses readSummarize from string frontmatter", () => { + expect(parseAgentFields({ name: "explore", description: "desc", readSummarize: "false" })?.readSummarize).toBe( + false, + ); + }); + + test("ignores invalid readSummarize values", () => { + expect(parseAgentFields({ name: "explore", description: "desc", readSummarize: "nope" })?.readSummarize).toBeUndefined(); + }); + + test("returns undefined readSummarize when field absent", () => { + expect(parseAgentFields({ name: "explore", description: "desc" })?.readSummarize).toBeUndefined(); + }); });