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.
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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<string, unknown>): 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(
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -531,7 +531,10 @@ function createMCPProxyTools(mcpManager: MCPManager): CustomTool[] {
|
||||
});
|
||||
}
|
||||
|
||||
function createSubagentSettings(baseSettings: Settings): Settings {
|
||||
function createSubagentSettings(
|
||||
baseSettings: Settings,
|
||||
overrides?: Partial<Record<SettingPath, unknown>>,
|
||||
): Settings {
|
||||
const snapshot: Partial<Record<SettingPath, unknown>> = {};
|
||||
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<SingleRes
|
||||
}
|
||||
|
||||
const settings = options.settings ?? Settings.isolated();
|
||||
const subagentSettings = createSubagentSettings(settings);
|
||||
const subagentSettings = createSubagentSettings(
|
||||
settings,
|
||||
agent.readSummarize === false ? { "read.summarize.enabled": false } : undefined,
|
||||
);
|
||||
const maxRecursionDepth = settings.get("task.maxRecursionDepth") ?? 2;
|
||||
const maxRuntimeMs = Math.max(0, Math.trunc(Number(settings.get("task.maxRuntimeMs") ?? 0) || 0));
|
||||
const parentDepth = options.taskDepth ?? 0;
|
||||
|
||||
@@ -174,6 +174,8 @@ export interface AgentDefinition {
|
||||
output?: unknown;
|
||||
blocking?: boolean;
|
||||
autoloadSkills?: string[];
|
||||
/** When `false`, the agent's `read` tool returns verbatim file content instead of structural summaries. */
|
||||
readSummarize?: boolean;
|
||||
source: AgentSource;
|
||||
filePath?: string;
|
||||
}
|
||||
|
||||
@@ -109,4 +109,27 @@ describe("parseAgentFields", () => {
|
||||
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();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user