@kolisachint/hoocode-agent 0.4.76 → 0.4.78

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.
Files changed (65) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/core/agent-frontmatter.d.ts +7 -5
  3. package/dist/core/agent-frontmatter.d.ts.map +1 -1
  4. package/dist/core/agent-frontmatter.js +4 -2
  5. package/dist/core/agent-frontmatter.js.map +1 -1
  6. package/dist/core/agent-registry.d.ts +1 -1
  7. package/dist/core/agent-registry.d.ts.map +1 -1
  8. package/dist/core/agent-registry.js +2 -2
  9. package/dist/core/agent-registry.js.map +1 -1
  10. package/dist/core/agent-session.d.ts.map +1 -1
  11. package/dist/core/agent-session.js +3 -3
  12. package/dist/core/agent-session.js.map +1 -1
  13. package/dist/core/dispatch-evaluator.d.ts +1 -1
  14. package/dist/core/dispatch-evaluator.d.ts.map +1 -1
  15. package/dist/core/dispatch-evaluator.js +1 -1
  16. package/dist/core/dispatch-evaluator.js.map +1 -1
  17. package/dist/core/provider-health.d.ts +1 -1
  18. package/dist/core/provider-health.d.ts.map +1 -1
  19. package/dist/core/provider-health.js +1 -1
  20. package/dist/core/provider-health.js.map +1 -1
  21. package/dist/core/subagent-pool.d.ts +7 -0
  22. package/dist/core/subagent-pool.d.ts.map +1 -1
  23. package/dist/core/subagent-pool.js +60 -5
  24. package/dist/core/subagent-pool.js.map +1 -1
  25. package/dist/core/system-prompt.d.ts +1 -1
  26. package/dist/core/system-prompt.d.ts.map +1 -1
  27. package/dist/core/system-prompt.js +8 -8
  28. package/dist/core/system-prompt.js.map +1 -1
  29. package/dist/core/task-store.d.ts +10 -4
  30. package/dist/core/task-store.d.ts.map +1 -1
  31. package/dist/core/task-store.js +20 -2
  32. package/dist/core/task-store.js.map +1 -1
  33. package/dist/core/tools/index.d.ts +1 -1
  34. package/dist/core/tools/index.d.ts.map +1 -1
  35. package/dist/core/tools/index.js +1 -1
  36. package/dist/core/tools/index.js.map +1 -1
  37. package/dist/core/tools/subagent.d.ts +3 -3
  38. package/dist/core/tools/subagent.d.ts.map +1 -1
  39. package/dist/core/tools/subagent.js +96 -55
  40. package/dist/core/tools/subagent.js.map +1 -1
  41. package/dist/core/tools/todo.d.ts.map +1 -1
  42. package/dist/core/tools/todo.js +26 -18
  43. package/dist/core/tools/todo.js.map +1 -1
  44. package/dist/index.d.ts +1 -1
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +1 -1
  47. package/dist/index.js.map +1 -1
  48. package/dist/init-templates.generated.d.ts.map +1 -1
  49. package/dist/init-templates.generated.js +3 -3
  50. package/dist/init-templates.generated.js.map +1 -1
  51. package/dist/main.d.ts.map +1 -1
  52. package/dist/main.js +5 -5
  53. package/dist/main.js.map +1 -1
  54. package/dist/modes/interactive/components/task-panel.d.ts.map +1 -1
  55. package/dist/modes/interactive/components/task-panel.js +7 -13
  56. package/dist/modes/interactive/components/task-panel.js.map +1 -1
  57. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  58. package/dist/modes/interactive/interactive-mode.js +1 -1
  59. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  60. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  61. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  62. package/examples/extensions/sandbox/package.json +1 -1
  63. package/examples/extensions/with-deps/package.json +1 -1
  64. package/package.json +4 -4
  65. package/templates/agents/general-purpose.md +1 -1
@@ -12,11 +12,14 @@
12
12
  */
13
13
  import { Text } from "@kolisachint/hoocode-tui";
14
14
  import { Type } from "typebox";
15
- import { TASK_TOOL_NAME } from "../agent-frontmatter.js";
15
+ import { getAgentDir } from "../../config.js";
16
+ import { EXECUTE_TASK_TOOL_NAME, MODEL_INHERIT } from "../agent-frontmatter.js";
16
17
  import { loadAgentRegistry } from "../agent-registry.js";
17
18
  import { defineTool } from "../extensions/types.js";
19
+ import { resolveModelReference } from "../model-categories.js";
18
20
  import { getProviderExhaustion } from "../provider-health.js";
19
21
  import { SessionManager } from "../session-manager.js";
22
+ import { SettingsManager } from "../settings-manager.js";
20
23
  import { delegateAllowList, isDelegateAllowed } from "../subagent-depth.js";
21
24
  import { getSubagentPool } from "../subagent-pool-instance.js";
22
25
  import { taskStore } from "../task-store.js";
@@ -58,10 +61,10 @@ function describeAvailableAgents(cwd) {
58
61
  return "(no agents available)";
59
62
  return agents.map((a) => `- ${a.name}: ${summarizeAgentDescription(a.description)}`).join("\n");
60
63
  }
61
- /** System prompt appendix for the main session when the Task tool is enabled.
64
+ /** System prompt appendix for the main session when the ExecuteTask tool is enabled.
62
65
  * Instructs the parent agent on when and how to delegate effectively. */
63
66
  export function buildTaskMainPrompt(cwd = process.cwd()) {
64
- return `You have access to the **Task** tool. Use it to delegate self-contained tasks to specialized subagents that run in their own isolated context and return only their final answer.
67
+ return `You have access to the **ExecuteTask** tool. Use it to delegate self-contained tasks to specialized subagents that run in their own isolated context and return only their final answer.
65
68
 
66
69
  Available agents (choose one via \`subagent_type\`):
67
70
  ${describeAvailableAgents(cwd)}
@@ -72,14 +75,20 @@ When to delegate:
72
75
  3. The task is a discrete unit (explore one module, run one test file, review one PR, fix one isolated bug).
73
76
  4. You need to run a long command or test suite and wait for its output without blocking your own reasoning.
74
77
 
78
+ Model categories:
79
+ - \`complexity: "fast\`\` — quick reads, simple lookups, grep/find operations
80
+ - \`complexity: "standard\`\` — multi-file edits, moderate reasoning, test runs
81
+ - \`complexity: "capable\`\` — deep architecture changes, complex refactors, full PRs
82
+ If omitted, the agent's default model is used.
83
+
75
84
  Guidelines:
76
85
  - Choose the agent whose description best matches the task.
77
86
  - Make every task specific and self-contained. The subagent cannot see this conversation; pass all necessary context (files, constraints, prior findings) in \`prompt\`.
78
87
  - Do NOT delegate tasks that require tight back-and-forth with your current reasoning, or edits to files you are actively reasoning about.
79
88
  - The subagent returns ONLY its final answer. Its intermediate reasoning, tool calls, and output are hidden from you.
80
89
  - Delegate proactively when work is self-contained or parallelizable: multi-step investigation, read-only exploration (use \`explore\`), research before changes (use \`plan\`), drafting a standalone file/section, or running a long command/test suite. Dispatch independent subtasks in the same turn. Handle only trivial single-step edits or tightly interactive back-and-forth inline.
81
- - Some agents are configured to run in the background (non-blocking). For those, the Task call does not block your turn: you keep reasoning and producing output while the subagent runs, and its final answer is delivered to you automatically as a follow-up message once it finishes. You do not need to poll for it.
82
- - To continue a previous subagent (for example one that returned partial results), call Task again with \`resume_task_id\` set to its task_id; it resumes with its full prior transcript and \`prompt\` is your follow-up.`;
90
+ - All ExecuteTask calls run as background tasks (non-blocking). The agent loop continues while the subagent runs. Results arrive as follow-up messages automatically. Use TaskOutput to poll for results while a subagent is running.
91
+ - To continue a previous subagent (for example one that returned partial results), call ExecuteTask again with \`resume_task_id\` set to its task_id; it resumes with its full prior transcript and \`prompt\` is your follow-up.`;
83
92
  }
84
93
  const taskParams = Type.Object({
85
94
  description: Type.String({
@@ -91,8 +100,14 @@ const taskParams = Type.Object({
91
100
  subagent_type: Type.String({
92
101
  description: "The name of the specialized agent to delegate to. Must be one of the available agents.",
93
102
  }),
103
+ item_id: Type.Optional(Type.Number({
104
+ description: "Optional. References a TodoWrite item id to link this dispatch to a plan item. The task panel shows the linkage.",
105
+ })),
106
+ complexity: Type.Optional(Type.Union([Type.Literal("fast"), Type.Literal("standard"), Type.Literal("capable")], {
107
+ description: "Model category: fast (quick reads/lookups), standard (multi-file edits), capable (deep architecture). Omit to use the agent's default model.",
108
+ })),
94
109
  resume_task_id: Type.Optional(Type.String({
95
- description: "Optional. To continue a previous subagent run, pass its task_id (returned by an earlier Task or TaskOutput call). The subagent resumes with its full prior transcript and `prompt` is your follow-up instruction.",
110
+ description: "Optional. To continue a previous subagent run, pass its task_id (returned by an earlier ExecuteTask or TaskOutput call). The subagent resumes with its full prior transcript and `prompt` is your follow-up instruction.",
96
111
  })),
97
112
  });
98
113
  /**
@@ -109,23 +124,25 @@ function summarize(task) {
109
124
  name = `${name.slice(0, 59)}…`;
110
125
  return name;
111
126
  }
112
- /** Create the Task tool definition. Registered as a customTool when enabled. */
113
- export function createTaskToolDefinition(cwd = process.cwd()) {
127
+ /** Create the ExecuteTask tool definition. Registered as a customTool when enabled. */
128
+ export function createExecuteTaskToolDefinition(cwd = process.cwd()) {
114
129
  const agentList = describeAvailableAgents(cwd);
115
- // Agents whose definitions opt into background execution. The agent loop reads
116
- // the tool's `background` flag per call and, for these, runs the dispatch
117
- // detached: the parent keeps reasoning and the subagent's answer is injected as
118
- // a follow-up message when it finishes (no polling needed).
119
- const backgroundAgents = collectBackgroundAgentNames(cwd);
130
+ // All ExecuteTask calls run as background tools. The agent loop runs the
131
+ // dispatch detached: the parent keeps reasoning and the subagent's answer is
132
+ // injected as a follow-up message when it finishes. TaskOutput can poll for
133
+ // results while the subagent runs.
120
134
  return defineTool({
121
- name: TASK_TOOL_NAME,
122
- label: TASK_TOOL_NAME,
123
- background: (toolCall) => backgroundAgents.has(String(toolCall.arguments?.subagent_type ?? "")),
135
+ name: EXECUTE_TASK_TOOL_NAME,
136
+ label: EXECUTE_TASK_TOOL_NAME,
137
+ background: () => true,
124
138
  description: [
125
139
  "Delegate a focused task to a specialized subagent that runs in a fresh, isolated context (it cannot see this conversation).",
126
140
  "Select the agent via `subagent_type`; pass everything it needs via `prompt`. The subagent returns only its final answer.",
127
141
  "Available agents:",
128
142
  agentList,
143
+ "Model categories: fast (quick reads/lookups), standard (multi-file edits), capable (deep architecture). Omit to use agent default.",
144
+ "All ExecuteTask calls run as background tasks. The agent loop continues while the subagent runs. Results arrive as follow-up messages.",
145
+ "Use TaskOutput to poll for results while a subagent is running.",
129
146
  "WHEN TO USE: (1) self-contained work where you only need the final result;",
130
147
  "(2) parallel investigation/edits without losing your reasoning chain;",
131
148
  "(3) a discrete unit (explore one module, run one test file, review one PR, fix one isolated bug, write docs);",
@@ -219,6 +236,22 @@ export function createTaskToolDefinition(cwd = process.cwd()) {
219
236
  // the call with a placeholder, and injects the answer below as a follow-up
220
237
  // message when it resolves. Foreground agents block the turn as usual.
221
238
  taskStore.update(task.id, { status: "in_progress" });
239
+ // Resolve model: complexity category > agent definition default > parent model
240
+ let resolvedModel = ctx.model?.id;
241
+ if (params.complexity) {
242
+ // Model category from ExecuteTask's complexity parameter
243
+ const settingsManager = SettingsManager.create(ctx.cwd, getAgentDir());
244
+ const globalSettings = settingsManager.getGlobalSettings();
245
+ const projectSettings = settingsManager.getProjectSettings();
246
+ const settings = { ...globalSettings, ...projectSettings };
247
+ const categoryModel = resolveModelReference(params.complexity, settings);
248
+ if (categoryModel)
249
+ resolvedModel = categoryModel;
250
+ }
251
+ else if (def.model && def.model !== MODEL_INHERIT) {
252
+ // Agent definition's default model (fallback)
253
+ resolvedModel = def.model;
254
+ }
222
255
  // Fork agents inherit the parent's conversation via a forked session.
223
256
  const forkSessionFile = def.fork
224
257
  ? resolveForkSessionFile(def, ctx.sessionManager?.getSessionFile(), ctx.cwd)
@@ -227,7 +260,7 @@ export function createTaskToolDefinition(cwd = process.cwd()) {
227
260
  const dispatchResult = await pool.dispatch(params.prompt, {
228
261
  forceAgent: params.subagent_type,
229
262
  context: "",
230
- model: ctx.model?.id,
263
+ model: resolvedModel,
231
264
  provider: ctx.model?.provider,
232
265
  sessionFile: forkSessionFile,
233
266
  });
@@ -273,15 +306,6 @@ export function resolveForkSessionFile(def, parentSessionPath, cwd) {
273
306
  function registerSubagentDispatch(type) {
274
307
  taskStore.upsertAgent({ id: type, name: type, role: "subagent", kind: "subagent", state: "running" });
275
308
  }
276
- /** Names of agents configured to run in the background (non-blocking). */
277
- function collectBackgroundAgentNames(cwd) {
278
- const names = new Set();
279
- for (const agent of loadAgentRegistry({ cwd }).list()) {
280
- if (agent.background)
281
- names.add(agent.name);
282
- }
283
- return names;
284
- }
285
309
  /**
286
310
  * Merge a child subagent's task subtree into the parent's task store, rooting
287
311
  * each top-level node under the dispatching task (`parentTaskId`). Recurses so a
@@ -292,15 +316,17 @@ function collectBackgroundAgentNames(cwd) {
292
316
  function mergeChildTaskTree(nodes, parentTaskId) {
293
317
  if (!nodes)
294
318
  return;
295
- for (const node of nodes) {
296
- const created = taskStore.create(node.title, {
297
- source: node.source,
298
- subagentMode: node.subagentMode,
299
- parentTaskId,
300
- });
301
- taskStore.update(created.id, { status: node.status, usage: node.usage });
302
- mergeChildTaskTree(node.children, created.id);
303
- }
319
+ taskStore.batch(() => {
320
+ for (const node of nodes) {
321
+ const created = taskStore.create(node.title, {
322
+ source: node.source,
323
+ subagentMode: node.subagentMode,
324
+ parentTaskId,
325
+ });
326
+ taskStore.update(created.id, { status: node.status, usage: node.usage });
327
+ mergeChildTaskTree(node.children, created.id);
328
+ }
329
+ });
304
330
  }
305
331
  /** Extract the final answer from a finished dispatch, updating the task panel. */
306
332
  function finalizeDispatchResult(dispatchResult, subagentType, taskStoreId, resumeHandle) {
@@ -362,23 +388,34 @@ export function createTaskOutputToolDefinition() {
362
388
  label: "TaskOutput",
363
389
  description: [
364
390
  "Check the status of a background subagent and collect its final answer once it finishes.",
365
- "Pass the task_id returned by a background Task call. While the subagent runs this reports its status; once complete it returns only the subagent's final answer.",
391
+ "Pass the task_id returned by a background ExecuteTask call. While the subagent runs this reports its status; once complete it returns only the subagent's final answer.",
366
392
  ].join("\n"),
367
393
  promptSnippet: "check status / collect the result of a background subagent",
368
394
  parameters: taskOutputParams,
369
395
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
370
396
  const pool = getSubagentPool(ctx.cwd);
371
397
  const status = pool.get_status(params.task_id);
398
+ // If the task is still running, wait for it to finish (with a timeout)
399
+ // instead of asking the model to poll. This eliminates the extra LLM
400
+ // round-trip that polling would require.
372
401
  if (status === "running" || status === "queued") {
373
- return {
374
- content: [
375
- {
376
- type: "text",
377
- text: `Subagent task "${params.task_id}" is ${status}. Call TaskOutput again later to collect its result.`,
378
- },
379
- ],
380
- details: { task_id: params.task_id, status, ok: true },
381
- };
402
+ const TASK_OUTPUT_TIMEOUT_MS = 120_000;
403
+ const result = await Promise.race([
404
+ pool.wait_for_completion(params.task_id),
405
+ new Promise((resolve) => setTimeout(() => resolve(undefined), TASK_OUTPUT_TIMEOUT_MS)),
406
+ ]);
407
+ if (!result) {
408
+ return {
409
+ content: [
410
+ {
411
+ type: "text",
412
+ text: `Subagent task "${params.task_id}" is still ${pool.get_status(params.task_id)}. Timed out after ${TASK_OUTPUT_TIMEOUT_MS / 1000}s.`,
413
+ },
414
+ ],
415
+ details: { task_id: params.task_id, status: pool.get_status(params.task_id), ok: true },
416
+ };
417
+ }
418
+ return formatTaskOutputResult(result, params.task_id);
382
419
  }
383
420
  if (status === "unknown") {
384
421
  return {
@@ -395,16 +432,7 @@ export function createTaskOutputToolDefinition() {
395
432
  if (!result) {
396
433
  throw new Error(`No result available for task "${params.task_id}" (status: ${status}). It may not exist or its result was already collected.`);
397
434
  }
398
- if (!result.ok) {
399
- const reason = result.error ?? (result.status ? `subagent ${result.status}` : status);
400
- throw new Error(`Background subagent "${params.task_id}" failed: ${reason}`);
401
- }
402
- const resultData = result.result_data;
403
- const answer = resultData?.summary || "(subagent returned no output)";
404
- return {
405
- content: [{ type: "text", text: answer }],
406
- details: { task_id: params.task_id, status: result.status ?? "complete", ok: true },
407
- };
435
+ return formatTaskOutputResult(result, params.task_id);
408
436
  },
409
437
  renderCall(args, theme) {
410
438
  const text = theme.fg("toolTitle", theme.bold("TaskOutput ")) + theme.fg("dim", String(args.task_id ?? ""));
@@ -412,4 +440,17 @@ export function createTaskOutputToolDefinition() {
412
440
  },
413
441
  });
414
442
  }
443
+ /** Format a completed subagent result for TaskOutput. */
444
+ function formatTaskOutputResult(result, taskId) {
445
+ if (!result.ok) {
446
+ const reason = result.error ?? (result.status ? `subagent ${result.status}` : "unknown error");
447
+ throw new Error(`Background subagent "${taskId}" failed: ${reason}`);
448
+ }
449
+ const resultData = result.result_data;
450
+ const answer = resultData?.summary || "(subagent returned no output)";
451
+ return {
452
+ content: [{ type: "text", text: answer }],
453
+ details: { task_id: taskId, status: result.status ?? "complete", ok: true },
454
+ };
455
+ }
415
456
  //# sourceMappingURL=subagent.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"subagent.js","sourceRoot":"","sources":["../../../src/core/tools/subagent.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Task tool: delegate a focused task to a specialized subagent.\n *\n * Mirrors the Claude Code `Task` tool. The parent agent decides *when* to\n * delegate based on each agent's `description` (there is no deterministic gate)\n * and selects *which* agent via `subagent_type`. The chosen agent runs in a\n * fresh, isolated child process (SubagentPool) and only its final answer is\n * returned to the parent.\n *\n * It is an optional, opt-in tool (enabled via --enable-subagents or the\n * `enableSubagent` setting); see buildSessionOptions in main.ts.\n */\n\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { type AgentDefinition, TASK_TOOL_NAME } from \"../agent-frontmatter.js\";\nimport { loadAgentRegistry } from \"../agent-registry.js\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { defineTool } from \"../extensions/types.js\";\nimport { getProviderExhaustion } from \"../provider-health.js\";\nimport { SessionManager } from \"../session-manager.js\";\nimport { delegateAllowList, isDelegateAllowed } from \"../subagent-depth.js\";\nimport type { TaskResult } from \"../subagent-pool.js\";\nimport { getSubagentPool } from \"../subagent-pool-instance.js\";\nimport type { SubagentResultFile, SubagentTaskNode } from \"../subagent-result.js\";\nimport { taskStore } from \"../task-store.js\";\n\n/**\n * Condense a (possibly multi-line, bulleted) agent description into a single\n * useful one-liner for the agent picker list.\n *\n * Built-in agent descriptions open with a boilerplate header (\"Use this\n * subagent ONLY when:\") followed by \"when to use\" bullets and a \"DO NOT use\"\n * section. Taking the first line alone yields that identical header for every\n * agent, so instead surface the first meaningful bullets (or the first prose\n * line) from the positive \"when to use\" region.\n */\nexport function summarizeAgentDescription(description: string): string {\n\tconst lines = description\n\t\t.split(\"\\n\")\n\t\t.map((line) => line.trim())\n\t\t.filter((line) => line.length > 0);\n\tif (lines.length === 0) return \"\";\n\n\t// Keep only the positive region: everything before a \"DO NOT use\" section.\n\tconst stop = lines.findIndex((line) => /^(do\\s*not|don'?t|avoid)\\b/i.test(line));\n\tconst region = stop === -1 ? lines : lines.slice(0, stop);\n\n\t// Drop a leading header line (e.g. \"Use this subagent ONLY when:\").\n\tconst body = region.length > 1 && region[0]!.endsWith(\":\") ? region.slice(1) : region;\n\n\tconst stripBullet = (line: string) => line.replace(/^[-*\\u2022]\\s+/, \"\").trim();\n\tconst bullets = body\n\t\t.filter((line) => /^[-*\\u2022]\\s+/.test(line))\n\t\t.map(stripBullet)\n\t\t.filter((line) => line.length > 0);\n\n\tconst summary = bullets.length > 0 ? bullets.slice(0, 3).join(\"; \") : (body[0] ?? lines[0] ?? \"\").replace(/:$/, \"\");\n\n\tconst MAX = 200;\n\treturn summary.length > MAX ? `${summary.slice(0, MAX - 1).trimEnd()}\\u2026` : summary;\n}\n\n/** Render the available agents as a \"- name: description\" list for prompts. */\nfunction describeAvailableAgents(cwd: string): string {\n\tconst agents = loadAgentRegistry({ cwd }).list();\n\tif (agents.length === 0) return \"(no agents available)\";\n\treturn agents.map((a) => `- ${a.name}: ${summarizeAgentDescription(a.description)}`).join(\"\\n\");\n}\n\n/** System prompt appendix for the main session when the Task tool is enabled.\n * Instructs the parent agent on when and how to delegate effectively. */\nexport function buildTaskMainPrompt(cwd: string = process.cwd()): string {\n\treturn `You have access to the **Task** tool. Use it to delegate self-contained tasks to specialized subagents that run in their own isolated context and return only their final answer.\n\nAvailable agents (choose one via \\`subagent_type\\`):\n${describeAvailableAgents(cwd)}\n\nWhen to delegate:\n1. The work is self-contained and you only need the final result, not intermediate steps.\n2. You want to investigate or edit something in parallel without losing your current context or reasoning chain.\n3. The task is a discrete unit (explore one module, run one test file, review one PR, fix one isolated bug).\n4. You need to run a long command or test suite and wait for its output without blocking your own reasoning.\n\nGuidelines:\n- Choose the agent whose description best matches the task.\n- Make every task specific and self-contained. The subagent cannot see this conversation; pass all necessary context (files, constraints, prior findings) in \\`prompt\\`.\n- Do NOT delegate tasks that require tight back-and-forth with your current reasoning, or edits to files you are actively reasoning about.\n- The subagent returns ONLY its final answer. Its intermediate reasoning, tool calls, and output are hidden from you.\n- Delegate proactively when work is self-contained or parallelizable: multi-step investigation, read-only exploration (use \\`explore\\`), research before changes (use \\`plan\\`), drafting a standalone file/section, or running a long command/test suite. Dispatch independent subtasks in the same turn. Handle only trivial single-step edits or tightly interactive back-and-forth inline.\n- Some agents are configured to run in the background (non-blocking). For those, the Task call does not block your turn: you keep reasoning and producing output while the subagent runs, and its final answer is delivered to you automatically as a follow-up message once it finishes. You do not need to poll for it.\n- To continue a previous subagent (for example one that returned partial results), call Task again with \\`resume_task_id\\` set to its task_id; it resumes with its full prior transcript and \\`prompt\\` is your follow-up.`;\n}\n\nconst taskParams = Type.Object({\n\tdescription: Type.String({\n\t\tdescription: \"A short (3-5 word) description of the task, shown in the task panel.\",\n\t}),\n\tprompt: Type.String({\n\t\tdescription:\n\t\t\t\"The full, self-contained task for the subagent. It cannot see this conversation, so include all needed context, files, and constraints.\",\n\t}),\n\tsubagent_type: Type.String({\n\t\tdescription: \"The name of the specialized agent to delegate to. Must be one of the available agents.\",\n\t}),\n\tresume_task_id: Type.Optional(\n\t\tType.String({\n\t\t\tdescription:\n\t\t\t\t\"Optional. To continue a previous subagent run, pass its task_id (returned by an earlier Task or TaskOutput call). The subagent resumes with its full prior transcript and `prompt` is your follow-up instruction.\",\n\t\t}),\n\t),\n});\n\ntype TaskParams = Static<typeof taskParams>;\n\nexport interface TaskToolDetails {\n\tsubagent_type: string;\n\tok: boolean;\n\terror?: string;\n\ttaskId: number;\n\t/** Pool-level task id usable for resume/polling. */\n\tpoolTaskId?: string;\n\t/** True when dispatched as a non-blocking background task. */\n\tbackground?: boolean;\n}\n\nexport interface TaskOutputDetails {\n\ttask_id: string;\n\tstatus: string;\n\tok: boolean;\n}\n\n/**\n * A short, human-readable task name for the task panel: the first line limited\n * to ~8 words so it stays glanceable. A character cap guards a single long word.\n */\nfunction summarize(task: string): string {\n\tconst firstLine = (task.trim().split(\"\\n\")[0] ?? \"\").trim();\n\tif (!firstLine) return \"(task)\";\n\tconst words = firstLine.split(/\\s+/);\n\tlet name = words.length > 8 ? `${words.slice(0, 8).join(\" \")}…` : firstLine;\n\tif (name.length > 60) name = `${name.slice(0, 59)}…`;\n\treturn name;\n}\n\n/** Create the Task tool definition. Registered as a customTool when enabled. */\nexport function createTaskToolDefinition(cwd: string = process.cwd()): ToolDefinition {\n\tconst agentList = describeAvailableAgents(cwd);\n\t// Agents whose definitions opt into background execution. The agent loop reads\n\t// the tool's `background` flag per call and, for these, runs the dispatch\n\t// detached: the parent keeps reasoning and the subagent's answer is injected as\n\t// a follow-up message when it finishes (no polling needed).\n\tconst backgroundAgents = collectBackgroundAgentNames(cwd);\n\treturn defineTool<typeof taskParams, TaskToolDetails>({\n\t\tname: TASK_TOOL_NAME,\n\t\tlabel: TASK_TOOL_NAME,\n\t\tbackground: (toolCall) => backgroundAgents.has(String(toolCall.arguments?.subagent_type ?? \"\")),\n\t\tdescription: [\n\t\t\t\"Delegate a focused task to a specialized subagent that runs in a fresh, isolated context (it cannot see this conversation).\",\n\t\t\t\"Select the agent via `subagent_type`; pass everything it needs via `prompt`. The subagent returns only its final answer.\",\n\t\t\t\"Available agents:\",\n\t\t\tagentList,\n\t\t\t\"WHEN TO USE: (1) self-contained work where you only need the final result;\",\n\t\t\t\"(2) parallel investigation/edits without losing your reasoning chain;\",\n\t\t\t\"(3) a discrete unit (explore one module, run one test file, review one PR, fix one isolated bug, write docs);\",\n\t\t\t\"(4) a long command or test suite you want to run without blocking your reasoning.\",\n\t\t\t\"Do NOT use for tasks needing tight back-and-forth with your current reasoning, or edits to files you are actively reasoning about.\",\n\t\t\t\"Delegate proactively for self-contained or parallelizable work; handle only trivial single-step or tightly interactive work inline.\",\n\t\t].join(\"\\n\"),\n\t\tpromptSnippet: \"delegate a self-contained task to a specialized subagent (choose via subagent_type)\",\n\t\tparameters: taskParams,\n\n\t\tasync execute(_toolCallId, params: TaskParams, _signal, _onUpdate, ctx) {\n\t\t\tconst pool = getSubagentPool(ctx.cwd);\n\n\t\t\t// Pre-flight: if the inherited provider recently exhausted its quota (the\n\t\t\t// parent's own turn failed with a usage/rate-limit error that did not\n\t\t\t// recover), skip the spawn. Subagents run on the same provider, so this\n\t\t\t// would only burn another failed attempt. The signal self-expires and is\n\t\t\t// cleared on the next successful response.\n\t\t\tconst provider = ctx.model?.provider;\n\t\t\tconst exhaustion = provider ? getProviderExhaustion(provider) : undefined;\n\t\t\tif (exhaustion) {\n\t\t\t\tconst skipped = taskStore.create(params.description?.trim() || summarize(params.prompt), {\n\t\t\t\t\tsource: \"subagent\",\n\t\t\t\t\tsubagentMode: params.subagent_type,\n\t\t\t\t\tagent: params.subagent_type,\n\t\t\t\t});\n\t\t\t\ttaskStore.update(skipped.id, { status: \"failed\", note: `${provider} exhausted` });\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext:\n\t\t\t\t\t\t\t\t`Did not dispatch subagent \"${params.subagent_type}\": the \"${provider}\" provider appears ` +\n\t\t\t\t\t\t\t\t`exhausted or rate-limited (this session just failed with: ${exhaustion.message}). ` +\n\t\t\t\t\t\t\t\t`Subagents run on the same provider, so dispatching would fail too. Wait for the quota to ` +\n\t\t\t\t\t\t\t\t`reset or switch model/provider, then retry — or complete the work directly in this session.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { subagent_type: params.subagent_type, ok: false, taskId: skipped.id },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Scoped delegation: a delegating agent may be restricted to certain subagent\n\t\t\t// types (its `delegate: <types>` frontmatter). The root is unrestricted.\n\t\t\tif (!isDelegateAllowed(params.subagent_type)) {\n\t\t\t\tconst allowed = delegateAllowList()?.join(\", \") ?? \"\";\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`This agent may not delegate to \"${params.subagent_type}\". Allowed subagent types: ${allowed || \"(none)\"}.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Resume path: continue a previously dispatched subagent with a follow-up\n\t\t\t// prompt, reusing its persisted session (full prior transcript).\n\t\t\tconst resumeId = params.resume_task_id?.trim();\n\t\t\tif (resumeId) {\n\t\t\t\tconst summary = params.description?.trim() || summarize(params.prompt);\n\t\t\t\tconst task = taskStore.create(summary, {\n\t\t\t\t\tsource: \"subagent\",\n\t\t\t\t\tsubagentMode: params.subagent_type,\n\t\t\t\t\tagent: params.subagent_type,\n\t\t\t\t});\n\t\t\t\tregisterSubagentDispatch(params.subagent_type);\n\t\t\t\ttaskStore.update(task.id, { status: \"in_progress\" });\n\t\t\t\ttry {\n\t\t\t\t\tconst dispatchResult = await pool.resume(resumeId, params.prompt, {\n\t\t\t\t\t\tmodel: ctx.model?.id,\n\t\t\t\t\t\tprovider: ctx.model?.provider,\n\t\t\t\t\t});\n\t\t\t\t\t// The session lives under the original task id; keep it as the resume handle.\n\t\t\t\t\treturn finalizeDispatchResult(dispatchResult, params.subagent_type, task.id, resumeId);\n\t\t\t\t} catch (error) {\n\t\t\t\t\ttaskStore.update(task.id, { status: \"failed\" });\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// The model has already decided to delegate and which agent to use; honor\n\t\t\t// it. Validate the requested agent against the registry (no routing gate).\n\t\t\tconst registry = loadAgentRegistry({ cwd: ctx.cwd });\n\t\t\tconst def = registry.get(params.subagent_type);\n\t\t\tif (!def) {\n\t\t\t\tconst available = registry\n\t\t\t\t\t.list()\n\t\t\t\t\t.map((a) => a.name)\n\t\t\t\t\t.join(\", \");\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Unknown subagent_type: \"${params.subagent_type}\". Available agents: ${available || \"(none)\"}.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst summary = params.description?.trim() || summarize(params.prompt);\n\t\t\tconst task = taskStore.create(summary, {\n\t\t\t\tsource: \"subagent\",\n\t\t\t\tsubagentMode: params.subagent_type,\n\t\t\t\tagent: params.subagent_type,\n\t\t\t});\n\t\t\tregisterSubagentDispatch(params.subagent_type);\n\n\t\t\t// Always dispatch and await the subagent's full result here. Background\n\t\t\t// agents (def.background) are made non-blocking by the agent loop via this\n\t\t\t// tool's `background` flag: the loop runs this execute() detached, answers\n\t\t\t// the call with a placeholder, and injects the answer below as a follow-up\n\t\t\t// message when it resolves. Foreground agents block the turn as usual.\n\t\t\ttaskStore.update(task.id, { status: \"in_progress\" });\n\t\t\t// Fork agents inherit the parent's conversation via a forked session.\n\t\t\tconst forkSessionFile = def.fork\n\t\t\t\t? resolveForkSessionFile(def, ctx.sessionManager?.getSessionFile(), ctx.cwd)\n\t\t\t\t: undefined;\n\t\t\ttry {\n\t\t\t\tconst dispatchResult = await pool.dispatch(params.prompt, {\n\t\t\t\t\tforceAgent: params.subagent_type,\n\t\t\t\t\tcontext: \"\",\n\t\t\t\t\tmodel: ctx.model?.id,\n\t\t\t\t\tprovider: ctx.model?.provider,\n\t\t\t\t\tsessionFile: forkSessionFile,\n\t\t\t\t});\n\t\t\t\treturn finalizeDispatchResult(dispatchResult, params.subagent_type, task.id, dispatchResult.task_id);\n\t\t\t} catch (error) {\n\t\t\t\ttaskStore.update(task.id, { status: \"failed\" });\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\n\t\trenderCall(args, theme) {\n\t\t\tconst type = args.subagent_type ?? \"agent\";\n\t\t\tconst preview = summarize(args.description ?? args.prompt ?? \"\");\n\t\t\tconst text =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"Agent \")) +\n\t\t\t\ttheme.fg(\"accent\", `[${type}]`) +\n\t\t\t\ttheme.fg(\"dim\", ` ${preview}`);\n\t\t\treturn new Text(text, 0, 0);\n\t\t},\n\t});\n}\n\n/**\n * For a `fork: true` agent, fork the parent's session so the subagent inherits the\n * full parent conversation (and its prompt cache) instead of starting fresh. Returns\n * the forked session file to dispatch the child with, or undefined to fall back to a\n * fresh session (non-fork agent, no parent session, or an empty/invalid source).\n */\nexport function resolveForkSessionFile(\n\tdef: Pick<AgentDefinition, \"fork\">,\n\tparentSessionPath: string | undefined,\n\tcwd: string,\n): string | undefined {\n\tif (!def.fork || !parentSessionPath) return undefined;\n\ttry {\n\t\treturn SessionManager.forkFrom(parentSessionPath, cwd).getSessionFile();\n\t} catch {\n\t\t// Empty/invalid parent session: fall back to a fresh subagent session.\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Register the dispatched agent in the task store's roster so the task pane's\n * grouped views (subagents/teams) can draw a group header for it. Upsert keeps\n * accumulated stats across re-dispatches of the same agent type.\n */\nfunction registerSubagentDispatch(type: string): void {\n\ttaskStore.upsertAgent({ id: type, name: type, role: \"subagent\", kind: \"subagent\", state: \"running\" });\n}\n\n/** Names of agents configured to run in the background (non-blocking). */\nfunction collectBackgroundAgentNames(cwd: string): Set<string> {\n\tconst names = new Set<string>();\n\tfor (const agent of loadAgentRegistry({ cwd }).list()) {\n\t\tif (agent.background) names.add(agent.name);\n\t}\n\treturn names;\n}\n\n/**\n * Merge a child subagent's task subtree into the parent's task store, rooting\n * each top-level node under the dispatching task (`parentTaskId`). Recurses so a\n * subagent that itself delegated shows its nested work — the subtree the child\n * could not surface across the process boundary on its own. Each node is its own\n * task (no key-by-type collapse), preserving the order the child created them.\n */\nfunction mergeChildTaskTree(nodes: readonly SubagentTaskNode[] | undefined, parentTaskId: number): void {\n\tif (!nodes) return;\n\tfor (const node of nodes) {\n\t\tconst created = taskStore.create(node.title, {\n\t\t\tsource: node.source,\n\t\t\tsubagentMode: node.subagentMode,\n\t\t\tparentTaskId,\n\t\t});\n\t\ttaskStore.update(created.id, { status: node.status, usage: node.usage });\n\t\tmergeChildTaskTree(node.children, created.id);\n\t}\n}\n\n/** Extract the final answer from a finished dispatch, updating the task panel. */\nfunction finalizeDispatchResult(\n\tdispatchResult: TaskResult,\n\tsubagentType: string,\n\ttaskStoreId: number,\n\tresumeHandle: string | undefined,\n): { content: Array<{ type: \"text\"; text: string }>; details: TaskToolDetails } {\n\tconst result = dispatchResult.result;\n\tconst resultData = result?.result_data as SubagentResultFile | undefined;\n\tconst usage = resultData?.usage;\n\n\t// Merge the child's own task subtree under the dispatching task so nested\n\t// delegation (depth >= 2) is visible in the subagents lens's task tree.\n\tmergeChildTaskTree(resultData?.task_tree, taskStoreId);\n\n\t// Roll the agent's per-run usage into its roster stats so the grouped views'\n\t// header carries the agent's own token/cost totals.\n\tif (usage) {\n\t\ttaskStore.addAgentStats(subagentType, { input: usage.input, output: usage.output, cost: usage.cost });\n\t}\n\n\tif (!result || !result.ok) {\n\t\t// Signal failure by throwing: the agent loop derives a tool's error state\n\t\t// from a thrown error, not from a returned flag.\n\t\tconst failNote = result?.usedInheritedModelFallback ? \"inherited-model retry failed\" : undefined;\n\t\ttaskStore.update(taskStoreId, { status: \"failed\", usage, note: failNote });\n\t\ttaskStore.patchAgent(subagentType, { state: \"failed\" });\n\t\tconst reason = result?.error ?? (result?.status ? `subagent ${result.status}` : \"unknown error\");\n\t\tconst stderr = result?.stderr?.trim();\n\t\tthrow new Error(`Subagent (${subagentType}) failed: ${reason}${stderr ? `\\nstderr: ${stderr.slice(-500)}` : \"\"}`);\n\t}\n\n\t// Leave the task in the store with its final status; it stays visible in the\n\t// task panel until the next user message arrives. Surface a ⚠ cue when the run\n\t// fell back to the inherited model rather than emitting a chat message.\n\tconst fallbackNote = dispatchResult.result?.usedInheritedModelFallback ? \"ran on inherited model\" : undefined;\n\ttaskStore.update(taskStoreId, { status: \"done\", usage, note: fallbackNote });\n\t// Parallel dispatches share one roster entry per agent type: stay `running`\n\t// while a sibling task is still live, settle to `done` otherwise.\n\tconst siblingLive = taskStore\n\t\t.list()\n\t\t.some((t) => t.agent === subagentType && (t.status === \"in_progress\" || t.status === \"pending\"));\n\ttaskStore.patchAgent(subagentType, { state: siblingLive ? \"running\" : \"done\" });\n\tlet answer = resultData?.summary || \"(subagent returned no output)\";\n\t// Partial results are resumable; surface the handle so the parent can continue.\n\tif (result.status === \"partial\" && resumeHandle) {\n\t\tanswer += `\\n\\n[Partial result. To continue this subagent, call Task again with resume_task_id=\"${resumeHandle}\".]`;\n\t}\n\treturn {\n\t\tcontent: [{ type: \"text\", text: answer }],\n\t\tdetails: { subagent_type: subagentType, ok: true, taskId: taskStoreId, poolTaskId: resumeHandle },\n\t};\n}\n\nconst taskOutputParams = Type.Object({\n\ttask_id: Type.String({\n\t\tdescription: \"The task_id of a background (or previously dispatched) subagent, as returned by the Task tool.\",\n\t}),\n});\n\ntype TaskOutputParams = Static<typeof taskOutputParams>;\n\n/**\n * TaskOutput tool: poll a background subagent and collect its final answer.\n * Returns the current status while running, or the subagent's final answer once\n * complete. Registered alongside the Task tool when subagents are enabled.\n */\nexport function createTaskOutputToolDefinition(): ToolDefinition {\n\treturn defineTool<typeof taskOutputParams, TaskOutputDetails>({\n\t\tname: \"TaskOutput\",\n\t\tlabel: \"TaskOutput\",\n\t\tdescription: [\n\t\t\t\"Check the status of a background subagent and collect its final answer once it finishes.\",\n\t\t\t\"Pass the task_id returned by a background Task call. While the subagent runs this reports its status; once complete it returns only the subagent's final answer.\",\n\t\t].join(\"\\n\"),\n\t\tpromptSnippet: \"check status / collect the result of a background subagent\",\n\t\tparameters: taskOutputParams,\n\n\t\tasync execute(_toolCallId, params: TaskOutputParams, _signal, _onUpdate, ctx) {\n\t\t\tconst pool = getSubagentPool(ctx.cwd);\n\t\t\tconst status = pool.get_status(params.task_id);\n\t\t\tif (status === \"running\" || status === \"queued\") {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `Subagent task \"${params.task_id}\" is ${status}. Call TaskOutput again later to collect its result.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { task_id: params.task_id, status, ok: true },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (status === \"unknown\") {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `No result available for task \"${params.task_id}\" (status: unknown). It may not exist or its result was already collected.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { task_id: params.task_id, status, ok: false },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst result = pool.collect(params.task_id);\n\t\t\tif (!result) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`No result available for task \"${params.task_id}\" (status: ${status}). It may not exist or its result was already collected.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (!result.ok) {\n\t\t\t\tconst reason = result.error ?? (result.status ? `subagent ${result.status}` : status);\n\t\t\t\tthrow new Error(`Background subagent \"${params.task_id}\" failed: ${reason}`);\n\t\t\t}\n\t\t\tconst resultData = result.result_data as SubagentResultFile | undefined;\n\t\t\tconst answer = resultData?.summary || \"(subagent returned no output)\";\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: answer }],\n\t\t\t\tdetails: { task_id: params.task_id, status: result.status ?? \"complete\", ok: true },\n\t\t\t};\n\t\t},\n\n\t\trenderCall(args, theme) {\n\t\t\tconst text = theme.fg(\"toolTitle\", theme.bold(\"TaskOutput \")) + theme.fg(\"dim\", String(args.task_id ?? \"\"));\n\t\t\treturn new Text(text, 0, 0);\n\t\t},\n\t});\n}\n"]}
1
+ {"version":3,"file":"subagent.js","sourceRoot":"","sources":["../../../src/core/tools/subagent.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Task tool: delegate a focused task to a specialized subagent.\n *\n * Mirrors the Claude Code `Task` tool. The parent agent decides *when* to\n * delegate based on each agent's `description` (there is no deterministic gate)\n * and selects *which* agent via `subagent_type`. The chosen agent runs in a\n * fresh, isolated child process (SubagentPool) and only its final answer is\n * returned to the parent.\n *\n * It is an optional, opt-in tool (enabled via --enable-subagents or the\n * `enableSubagent` setting); see buildSessionOptions in main.ts.\n */\n\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { getAgentDir } from \"../../config.js\";\nimport { type AgentDefinition, EXECUTE_TASK_TOOL_NAME, MODEL_INHERIT } from \"../agent-frontmatter.js\";\nimport { loadAgentRegistry } from \"../agent-registry.js\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { defineTool } from \"../extensions/types.js\";\nimport { resolveModelReference } from \"../model-categories.js\";\nimport { getProviderExhaustion } from \"../provider-health.js\";\nimport { SessionManager } from \"../session-manager.js\";\nimport { SettingsManager } from \"../settings-manager.js\";\nimport { delegateAllowList, isDelegateAllowed } from \"../subagent-depth.js\";\nimport type { SubagentResult, TaskResult } from \"../subagent-pool.js\";\nimport { getSubagentPool } from \"../subagent-pool-instance.js\";\nimport type { SubagentResultFile, SubagentTaskNode } from \"../subagent-result.js\";\nimport { taskStore } from \"../task-store.js\";\n\n/**\n * Condense a (possibly multi-line, bulleted) agent description into a single\n * useful one-liner for the agent picker list.\n *\n * Built-in agent descriptions open with a boilerplate header (\"Use this\n * subagent ONLY when:\") followed by \"when to use\" bullets and a \"DO NOT use\"\n * section. Taking the first line alone yields that identical header for every\n * agent, so instead surface the first meaningful bullets (or the first prose\n * line) from the positive \"when to use\" region.\n */\nexport function summarizeAgentDescription(description: string): string {\n\tconst lines = description\n\t\t.split(\"\\n\")\n\t\t.map((line) => line.trim())\n\t\t.filter((line) => line.length > 0);\n\tif (lines.length === 0) return \"\";\n\n\t// Keep only the positive region: everything before a \"DO NOT use\" section.\n\tconst stop = lines.findIndex((line) => /^(do\\s*not|don'?t|avoid)\\b/i.test(line));\n\tconst region = stop === -1 ? lines : lines.slice(0, stop);\n\n\t// Drop a leading header line (e.g. \"Use this subagent ONLY when:\").\n\tconst body = region.length > 1 && region[0]!.endsWith(\":\") ? region.slice(1) : region;\n\n\tconst stripBullet = (line: string) => line.replace(/^[-*\\u2022]\\s+/, \"\").trim();\n\tconst bullets = body\n\t\t.filter((line) => /^[-*\\u2022]\\s+/.test(line))\n\t\t.map(stripBullet)\n\t\t.filter((line) => line.length > 0);\n\n\tconst summary = bullets.length > 0 ? bullets.slice(0, 3).join(\"; \") : (body[0] ?? lines[0] ?? \"\").replace(/:$/, \"\");\n\n\tconst MAX = 200;\n\treturn summary.length > MAX ? `${summary.slice(0, MAX - 1).trimEnd()}\\u2026` : summary;\n}\n\n/** Render the available agents as a \"- name: description\" list for prompts. */\nfunction describeAvailableAgents(cwd: string): string {\n\tconst agents = loadAgentRegistry({ cwd }).list();\n\tif (agents.length === 0) return \"(no agents available)\";\n\treturn agents.map((a) => `- ${a.name}: ${summarizeAgentDescription(a.description)}`).join(\"\\n\");\n}\n\n/** System prompt appendix for the main session when the ExecuteTask tool is enabled.\n * Instructs the parent agent on when and how to delegate effectively. */\nexport function buildTaskMainPrompt(cwd: string = process.cwd()): string {\n\treturn `You have access to the **ExecuteTask** tool. Use it to delegate self-contained tasks to specialized subagents that run in their own isolated context and return only their final answer.\n\nAvailable agents (choose one via \\`subagent_type\\`):\n${describeAvailableAgents(cwd)}\n\nWhen to delegate:\n1. The work is self-contained and you only need the final result, not intermediate steps.\n2. You want to investigate or edit something in parallel without losing your current context or reasoning chain.\n3. The task is a discrete unit (explore one module, run one test file, review one PR, fix one isolated bug).\n4. You need to run a long command or test suite and wait for its output without blocking your own reasoning.\n\nModel categories:\n- \\`complexity: \"fast\\`\\` — quick reads, simple lookups, grep/find operations\n- \\`complexity: \"standard\\`\\` — multi-file edits, moderate reasoning, test runs\n- \\`complexity: \"capable\\`\\` — deep architecture changes, complex refactors, full PRs\nIf omitted, the agent's default model is used.\n\nGuidelines:\n- Choose the agent whose description best matches the task.\n- Make every task specific and self-contained. The subagent cannot see this conversation; pass all necessary context (files, constraints, prior findings) in \\`prompt\\`.\n- Do NOT delegate tasks that require tight back-and-forth with your current reasoning, or edits to files you are actively reasoning about.\n- The subagent returns ONLY its final answer. Its intermediate reasoning, tool calls, and output are hidden from you.\n- Delegate proactively when work is self-contained or parallelizable: multi-step investigation, read-only exploration (use \\`explore\\`), research before changes (use \\`plan\\`), drafting a standalone file/section, or running a long command/test suite. Dispatch independent subtasks in the same turn. Handle only trivial single-step edits or tightly interactive back-and-forth inline.\n- All ExecuteTask calls run as background tasks (non-blocking). The agent loop continues while the subagent runs. Results arrive as follow-up messages automatically. Use TaskOutput to poll for results while a subagent is running.\n- To continue a previous subagent (for example one that returned partial results), call ExecuteTask again with \\`resume_task_id\\` set to its task_id; it resumes with its full prior transcript and \\`prompt\\` is your follow-up.`;\n}\n\nconst taskParams = Type.Object({\n\tdescription: Type.String({\n\t\tdescription: \"A short (3-5 word) description of the task, shown in the task panel.\",\n\t}),\n\tprompt: Type.String({\n\t\tdescription:\n\t\t\t\"The full, self-contained task for the subagent. It cannot see this conversation, so include all needed context, files, and constraints.\",\n\t}),\n\tsubagent_type: Type.String({\n\t\tdescription: \"The name of the specialized agent to delegate to. Must be one of the available agents.\",\n\t}),\n\titem_id: Type.Optional(\n\t\tType.Number({\n\t\t\tdescription:\n\t\t\t\t\"Optional. References a TodoWrite item id to link this dispatch to a plan item. The task panel shows the linkage.\",\n\t\t}),\n\t),\n\tcomplexity: Type.Optional(\n\t\tType.Union([Type.Literal(\"fast\"), Type.Literal(\"standard\"), Type.Literal(\"capable\")], {\n\t\t\tdescription:\n\t\t\t\t\"Model category: fast (quick reads/lookups), standard (multi-file edits), capable (deep architecture). Omit to use the agent's default model.\",\n\t\t}),\n\t),\n\tresume_task_id: Type.Optional(\n\t\tType.String({\n\t\t\tdescription:\n\t\t\t\t\"Optional. To continue a previous subagent run, pass its task_id (returned by an earlier ExecuteTask or TaskOutput call). The subagent resumes with its full prior transcript and `prompt` is your follow-up instruction.\",\n\t\t}),\n\t),\n});\n\ntype TaskParams = Static<typeof taskParams>;\n\nexport interface TaskToolDetails {\n\tsubagent_type: string;\n\tok: boolean;\n\terror?: string;\n\ttaskId: number;\n\t/** Pool-level task id usable for resume/polling. */\n\tpoolTaskId?: string;\n\t/** True when dispatched as a non-blocking background task. */\n\tbackground?: boolean;\n}\n\nexport interface TaskOutputDetails {\n\ttask_id: string;\n\tstatus: string;\n\tok: boolean;\n}\n\n/**\n * A short, human-readable task name for the task panel: the first line limited\n * to ~8 words so it stays glanceable. A character cap guards a single long word.\n */\nfunction summarize(task: string): string {\n\tconst firstLine = (task.trim().split(\"\\n\")[0] ?? \"\").trim();\n\tif (!firstLine) return \"(task)\";\n\tconst words = firstLine.split(/\\s+/);\n\tlet name = words.length > 8 ? `${words.slice(0, 8).join(\" \")}…` : firstLine;\n\tif (name.length > 60) name = `${name.slice(0, 59)}…`;\n\treturn name;\n}\n\n/** Create the ExecuteTask tool definition. Registered as a customTool when enabled. */\nexport function createExecuteTaskToolDefinition(cwd: string = process.cwd()): ToolDefinition {\n\tconst agentList = describeAvailableAgents(cwd);\n\t// All ExecuteTask calls run as background tools. The agent loop runs the\n\t// dispatch detached: the parent keeps reasoning and the subagent's answer is\n\t// injected as a follow-up message when it finishes. TaskOutput can poll for\n\t// results while the subagent runs.\n\treturn defineTool<typeof taskParams, TaskToolDetails>({\n\t\tname: EXECUTE_TASK_TOOL_NAME,\n\t\tlabel: EXECUTE_TASK_TOOL_NAME,\n\t\tbackground: () => true,\n\t\tdescription: [\n\t\t\t\"Delegate a focused task to a specialized subagent that runs in a fresh, isolated context (it cannot see this conversation).\",\n\t\t\t\"Select the agent via `subagent_type`; pass everything it needs via `prompt`. The subagent returns only its final answer.\",\n\t\t\t\"Available agents:\",\n\t\t\tagentList,\n\t\t\t\"Model categories: fast (quick reads/lookups), standard (multi-file edits), capable (deep architecture). Omit to use agent default.\",\n\t\t\t\"All ExecuteTask calls run as background tasks. The agent loop continues while the subagent runs. Results arrive as follow-up messages.\",\n\t\t\t\"Use TaskOutput to poll for results while a subagent is running.\",\n\t\t\t\"WHEN TO USE: (1) self-contained work where you only need the final result;\",\n\t\t\t\"(2) parallel investigation/edits without losing your reasoning chain;\",\n\t\t\t\"(3) a discrete unit (explore one module, run one test file, review one PR, fix one isolated bug, write docs);\",\n\t\t\t\"(4) a long command or test suite you want to run without blocking your reasoning.\",\n\t\t\t\"Do NOT use for tasks needing tight back-and-forth with your current reasoning, or edits to files you are actively reasoning about.\",\n\t\t\t\"Delegate proactively for self-contained or parallelizable work; handle only trivial single-step or tightly interactive work inline.\",\n\t\t].join(\"\\n\"),\n\t\tpromptSnippet: \"delegate a self-contained task to a specialized subagent (choose via subagent_type)\",\n\t\tparameters: taskParams,\n\n\t\tasync execute(_toolCallId, params: TaskParams, _signal, _onUpdate, ctx) {\n\t\t\tconst pool = getSubagentPool(ctx.cwd);\n\n\t\t\t// Pre-flight: if the inherited provider recently exhausted its quota (the\n\t\t\t// parent's own turn failed with a usage/rate-limit error that did not\n\t\t\t// recover), skip the spawn. Subagents run on the same provider, so this\n\t\t\t// would only burn another failed attempt. The signal self-expires and is\n\t\t\t// cleared on the next successful response.\n\t\t\tconst provider = ctx.model?.provider;\n\t\t\tconst exhaustion = provider ? getProviderExhaustion(provider) : undefined;\n\t\t\tif (exhaustion) {\n\t\t\t\tconst skipped = taskStore.create(params.description?.trim() || summarize(params.prompt), {\n\t\t\t\t\tsource: \"subagent\",\n\t\t\t\t\tsubagentMode: params.subagent_type,\n\t\t\t\t\tagent: params.subagent_type,\n\t\t\t\t});\n\t\t\t\ttaskStore.update(skipped.id, { status: \"failed\", note: `${provider} exhausted` });\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext:\n\t\t\t\t\t\t\t\t`Did not dispatch subagent \"${params.subagent_type}\": the \"${provider}\" provider appears ` +\n\t\t\t\t\t\t\t\t`exhausted or rate-limited (this session just failed with: ${exhaustion.message}). ` +\n\t\t\t\t\t\t\t\t`Subagents run on the same provider, so dispatching would fail too. Wait for the quota to ` +\n\t\t\t\t\t\t\t\t`reset or switch model/provider, then retry — or complete the work directly in this session.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { subagent_type: params.subagent_type, ok: false, taskId: skipped.id },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Scoped delegation: a delegating agent may be restricted to certain subagent\n\t\t\t// types (its `delegate: <types>` frontmatter). The root is unrestricted.\n\t\t\tif (!isDelegateAllowed(params.subagent_type)) {\n\t\t\t\tconst allowed = delegateAllowList()?.join(\", \") ?? \"\";\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`This agent may not delegate to \"${params.subagent_type}\". Allowed subagent types: ${allowed || \"(none)\"}.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Resume path: continue a previously dispatched subagent with a follow-up\n\t\t\t// prompt, reusing its persisted session (full prior transcript).\n\t\t\tconst resumeId = params.resume_task_id?.trim();\n\t\t\tif (resumeId) {\n\t\t\t\tconst summary = params.description?.trim() || summarize(params.prompt);\n\t\t\t\tconst task = taskStore.create(summary, {\n\t\t\t\t\tsource: \"subagent\",\n\t\t\t\t\tsubagentMode: params.subagent_type,\n\t\t\t\t\tagent: params.subagent_type,\n\t\t\t\t});\n\t\t\t\tregisterSubagentDispatch(params.subagent_type);\n\t\t\t\ttaskStore.update(task.id, { status: \"in_progress\" });\n\t\t\t\ttry {\n\t\t\t\t\tconst dispatchResult = await pool.resume(resumeId, params.prompt, {\n\t\t\t\t\t\tmodel: ctx.model?.id,\n\t\t\t\t\t\tprovider: ctx.model?.provider,\n\t\t\t\t\t});\n\t\t\t\t\t// The session lives under the original task id; keep it as the resume handle.\n\t\t\t\t\treturn finalizeDispatchResult(dispatchResult, params.subagent_type, task.id, resumeId);\n\t\t\t\t} catch (error) {\n\t\t\t\t\ttaskStore.update(task.id, { status: \"failed\" });\n\t\t\t\t\tthrow error;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// The model has already decided to delegate and which agent to use; honor\n\t\t\t// it. Validate the requested agent against the registry (no routing gate).\n\t\t\tconst registry = loadAgentRegistry({ cwd: ctx.cwd });\n\t\t\tconst def = registry.get(params.subagent_type);\n\t\t\tif (!def) {\n\t\t\t\tconst available = registry\n\t\t\t\t\t.list()\n\t\t\t\t\t.map((a) => a.name)\n\t\t\t\t\t.join(\", \");\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Unknown subagent_type: \"${params.subagent_type}\". Available agents: ${available || \"(none)\"}.`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst summary = params.description?.trim() || summarize(params.prompt);\n\t\t\tconst task = taskStore.create(summary, {\n\t\t\t\tsource: \"subagent\",\n\t\t\t\tsubagentMode: params.subagent_type,\n\t\t\t\tagent: params.subagent_type,\n\t\t\t});\n\t\t\tregisterSubagentDispatch(params.subagent_type);\n\n\t\t\t// Always dispatch and await the subagent's full result here. Background\n\t\t\t// agents (def.background) are made non-blocking by the agent loop via this\n\t\t\t// tool's `background` flag: the loop runs this execute() detached, answers\n\t\t\t// the call with a placeholder, and injects the answer below as a follow-up\n\t\t\t// message when it resolves. Foreground agents block the turn as usual.\n\t\t\ttaskStore.update(task.id, { status: \"in_progress\" });\n\n\t\t\t// Resolve model: complexity category > agent definition default > parent model\n\t\t\tlet resolvedModel = ctx.model?.id;\n\t\t\tif (params.complexity) {\n\t\t\t\t// Model category from ExecuteTask's complexity parameter\n\t\t\t\tconst settingsManager = SettingsManager.create(ctx.cwd, getAgentDir());\n\t\t\t\tconst globalSettings = settingsManager.getGlobalSettings();\n\t\t\t\tconst projectSettings = settingsManager.getProjectSettings();\n\t\t\t\tconst settings = { ...globalSettings, ...projectSettings };\n\t\t\t\tconst categoryModel = resolveModelReference(params.complexity, settings);\n\t\t\t\tif (categoryModel) resolvedModel = categoryModel;\n\t\t\t} else if (def.model && def.model !== MODEL_INHERIT) {\n\t\t\t\t// Agent definition's default model (fallback)\n\t\t\t\tresolvedModel = def.model;\n\t\t\t}\n\n\t\t\t// Fork agents inherit the parent's conversation via a forked session.\n\t\t\tconst forkSessionFile = def.fork\n\t\t\t\t? resolveForkSessionFile(def, ctx.sessionManager?.getSessionFile(), ctx.cwd)\n\t\t\t\t: undefined;\n\t\t\ttry {\n\t\t\t\tconst dispatchResult = await pool.dispatch(params.prompt, {\n\t\t\t\t\tforceAgent: params.subagent_type,\n\t\t\t\t\tcontext: \"\",\n\t\t\t\t\tmodel: resolvedModel,\n\t\t\t\t\tprovider: ctx.model?.provider,\n\t\t\t\t\tsessionFile: forkSessionFile,\n\t\t\t\t});\n\t\t\t\treturn finalizeDispatchResult(dispatchResult, params.subagent_type, task.id, dispatchResult.task_id);\n\t\t\t} catch (error) {\n\t\t\t\ttaskStore.update(task.id, { status: \"failed\" });\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t},\n\n\t\trenderCall(args, theme) {\n\t\t\tconst type = args.subagent_type ?? \"agent\";\n\t\t\tconst preview = summarize(args.description ?? args.prompt ?? \"\");\n\t\t\tconst text =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"Agent \")) +\n\t\t\t\ttheme.fg(\"accent\", `[${type}]`) +\n\t\t\t\ttheme.fg(\"dim\", ` ${preview}`);\n\t\t\treturn new Text(text, 0, 0);\n\t\t},\n\t});\n}\n\n/**\n * For a `fork: true` agent, fork the parent's session so the subagent inherits the\n * full parent conversation (and its prompt cache) instead of starting fresh. Returns\n * the forked session file to dispatch the child with, or undefined to fall back to a\n * fresh session (non-fork agent, no parent session, or an empty/invalid source).\n */\nexport function resolveForkSessionFile(\n\tdef: Pick<AgentDefinition, \"fork\">,\n\tparentSessionPath: string | undefined,\n\tcwd: string,\n): string | undefined {\n\tif (!def.fork || !parentSessionPath) return undefined;\n\ttry {\n\t\treturn SessionManager.forkFrom(parentSessionPath, cwd).getSessionFile();\n\t} catch {\n\t\t// Empty/invalid parent session: fall back to a fresh subagent session.\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Register the dispatched agent in the task store's roster so the task pane's\n * grouped views (subagents/teams) can draw a group header for it. Upsert keeps\n * accumulated stats across re-dispatches of the same agent type.\n */\nfunction registerSubagentDispatch(type: string): void {\n\ttaskStore.upsertAgent({ id: type, name: type, role: \"subagent\", kind: \"subagent\", state: \"running\" });\n}\n\n/**\n * Merge a child subagent's task subtree into the parent's task store, rooting\n * each top-level node under the dispatching task (`parentTaskId`). Recurses so a\n * subagent that itself delegated shows its nested work — the subtree the child\n * could not surface across the process boundary on its own. Each node is its own\n * task (no key-by-type collapse), preserving the order the child created them.\n */\nfunction mergeChildTaskTree(nodes: readonly SubagentTaskNode[] | undefined, parentTaskId: number): void {\n\tif (!nodes) return;\n\ttaskStore.batch(() => {\n\t\tfor (const node of nodes) {\n\t\t\tconst created = taskStore.create(node.title, {\n\t\t\t\tsource: node.source,\n\t\t\t\tsubagentMode: node.subagentMode,\n\t\t\t\tparentTaskId,\n\t\t\t});\n\t\t\ttaskStore.update(created.id, { status: node.status, usage: node.usage });\n\t\t\tmergeChildTaskTree(node.children, created.id);\n\t\t}\n\t});\n}\n\n/** Extract the final answer from a finished dispatch, updating the task panel. */\nfunction finalizeDispatchResult(\n\tdispatchResult: TaskResult,\n\tsubagentType: string,\n\ttaskStoreId: number,\n\tresumeHandle: string | undefined,\n): { content: Array<{ type: \"text\"; text: string }>; details: TaskToolDetails } {\n\tconst result = dispatchResult.result;\n\tconst resultData = result?.result_data as SubagentResultFile | undefined;\n\tconst usage = resultData?.usage;\n\n\t// Merge the child's own task subtree under the dispatching task so nested\n\t// delegation (depth >= 2) is visible in the subagents lens's task tree.\n\tmergeChildTaskTree(resultData?.task_tree, taskStoreId);\n\n\t// Roll the agent's per-run usage into its roster stats so the grouped views'\n\t// header carries the agent's own token/cost totals.\n\tif (usage) {\n\t\ttaskStore.addAgentStats(subagentType, { input: usage.input, output: usage.output, cost: usage.cost });\n\t}\n\n\tif (!result || !result.ok) {\n\t\t// Signal failure by throwing: the agent loop derives a tool's error state\n\t\t// from a thrown error, not from a returned flag.\n\t\tconst failNote = result?.usedInheritedModelFallback ? \"inherited-model retry failed\" : undefined;\n\t\ttaskStore.update(taskStoreId, { status: \"failed\", usage, note: failNote });\n\t\ttaskStore.patchAgent(subagentType, { state: \"failed\" });\n\t\tconst reason = result?.error ?? (result?.status ? `subagent ${result.status}` : \"unknown error\");\n\t\tconst stderr = result?.stderr?.trim();\n\t\tthrow new Error(`Subagent (${subagentType}) failed: ${reason}${stderr ? `\\nstderr: ${stderr.slice(-500)}` : \"\"}`);\n\t}\n\n\t// Leave the task in the store with its final status; it stays visible in the\n\t// task panel until the next user message arrives. Surface a ⚠ cue when the run\n\t// fell back to the inherited model rather than emitting a chat message.\n\tconst fallbackNote = dispatchResult.result?.usedInheritedModelFallback ? \"ran on inherited model\" : undefined;\n\ttaskStore.update(taskStoreId, { status: \"done\", usage, note: fallbackNote });\n\t// Parallel dispatches share one roster entry per agent type: stay `running`\n\t// while a sibling task is still live, settle to `done` otherwise.\n\tconst siblingLive = taskStore\n\t\t.list()\n\t\t.some((t) => t.agent === subagentType && (t.status === \"in_progress\" || t.status === \"pending\"));\n\ttaskStore.patchAgent(subagentType, { state: siblingLive ? \"running\" : \"done\" });\n\tlet answer = resultData?.summary || \"(subagent returned no output)\";\n\t// Partial results are resumable; surface the handle so the parent can continue.\n\tif (result.status === \"partial\" && resumeHandle) {\n\t\tanswer += `\\n\\n[Partial result. To continue this subagent, call Task again with resume_task_id=\"${resumeHandle}\".]`;\n\t}\n\treturn {\n\t\tcontent: [{ type: \"text\", text: answer }],\n\t\tdetails: { subagent_type: subagentType, ok: true, taskId: taskStoreId, poolTaskId: resumeHandle },\n\t};\n}\n\nconst taskOutputParams = Type.Object({\n\ttask_id: Type.String({\n\t\tdescription: \"The task_id of a background (or previously dispatched) subagent, as returned by the Task tool.\",\n\t}),\n});\n\ntype TaskOutputParams = Static<typeof taskOutputParams>;\n\n/**\n * TaskOutput tool: poll a background subagent and collect its final answer.\n * Returns the current status while running, or the subagent's final answer once\n * complete. Registered alongside the Task tool when subagents are enabled.\n */\nexport function createTaskOutputToolDefinition(): ToolDefinition {\n\treturn defineTool<typeof taskOutputParams, TaskOutputDetails>({\n\t\tname: \"TaskOutput\",\n\t\tlabel: \"TaskOutput\",\n\t\tdescription: [\n\t\t\t\"Check the status of a background subagent and collect its final answer once it finishes.\",\n\t\t\t\"Pass the task_id returned by a background ExecuteTask call. While the subagent runs this reports its status; once complete it returns only the subagent's final answer.\",\n\t\t].join(\"\\n\"),\n\t\tpromptSnippet: \"check status / collect the result of a background subagent\",\n\t\tparameters: taskOutputParams,\n\n\t\tasync execute(_toolCallId, params: TaskOutputParams, _signal, _onUpdate, ctx) {\n\t\t\tconst pool = getSubagentPool(ctx.cwd);\n\t\t\tconst status = pool.get_status(params.task_id);\n\n\t\t\t// If the task is still running, wait for it to finish (with a timeout)\n\t\t\t// instead of asking the model to poll. This eliminates the extra LLM\n\t\t\t// round-trip that polling would require.\n\t\t\tif (status === \"running\" || status === \"queued\") {\n\t\t\t\tconst TASK_OUTPUT_TIMEOUT_MS = 120_000;\n\t\t\t\tconst result = await Promise.race([\n\t\t\t\t\tpool.wait_for_completion(params.task_id),\n\t\t\t\t\tnew Promise<undefined>((resolve) => setTimeout(() => resolve(undefined), TASK_OUTPUT_TIMEOUT_MS)),\n\t\t\t\t]);\n\t\t\t\tif (!result) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcontent: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\t\ttext: `Subagent task \"${params.task_id}\" is still ${pool.get_status(params.task_id)}. Timed out after ${TASK_OUTPUT_TIMEOUT_MS / 1000}s.`,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tdetails: { task_id: params.task_id, status: pool.get_status(params.task_id), ok: true },\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn formatTaskOutputResult(result, params.task_id);\n\t\t\t}\n\n\t\t\tif (status === \"unknown\") {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `No result available for task \"${params.task_id}\" (status: unknown). It may not exist or its result was already collected.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { task_id: params.task_id, status, ok: false },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst result = pool.collect(params.task_id);\n\t\t\tif (!result) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`No result available for task \"${params.task_id}\" (status: ${status}). It may not exist or its result was already collected.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn formatTaskOutputResult(result, params.task_id);\n\t\t},\n\n\t\trenderCall(args, theme) {\n\t\t\tconst text = theme.fg(\"toolTitle\", theme.bold(\"TaskOutput \")) + theme.fg(\"dim\", String(args.task_id ?? \"\"));\n\t\t\treturn new Text(text, 0, 0);\n\t\t},\n\t});\n}\n\n/** Format a completed subagent result for TaskOutput. */\nfunction formatTaskOutputResult(\n\tresult: SubagentResult,\n\ttaskId: string,\n): { content: Array<{ type: \"text\"; text: string }>; details: TaskOutputDetails } {\n\tif (!result.ok) {\n\t\tconst reason = result.error ?? (result.status ? `subagent ${result.status}` : \"unknown error\");\n\t\tthrow new Error(`Background subagent \"${taskId}\" failed: ${reason}`);\n\t}\n\tconst resultData = result.result_data as SubagentResultFile | undefined;\n\tconst answer = resultData?.summary || \"(subagent returned no output)\";\n\treturn {\n\t\tcontent: [{ type: \"text\" as const, text: answer }],\n\t\tdetails: { task_id: taskId, status: result.status ?? \"complete\", ok: true },\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"todo.d.ts","sourceRoot":"","sources":["../../../src/core/tools/todo.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAoCzE,MAAM,WAAW,gBAAgB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CAClB;AAyBD,qFAAqF;AACrF,wBAAgB,6BAA6B,IAAI,cAAc,CAoE9D","sourcesContent":["/**\n * TodoWrite tool: let the main agent maintain a visible todo list for the\n * current task.\n *\n * hoocode already has all the infrastructure this needs — the task store models\n * `{ title, status }` items with a per-turn lifecycle, and the TUI task panel\n * renders them. The only missing piece was a tool the model can call; this is\n * that thin adapter over `taskStore`.\n *\n * Semantics mirror Claude Code's TodoWrite: each call sends the FULL list and\n * REPLACES the previous one. Because the store is incremental (numeric ids), we\n * reconcile the incoming list against the existing main-agent tasks by position:\n * update items that are still there, create new ones, and drop the tail that was\n * removed. Reconciling (rather than clear-and-recreate) keeps ids stable so the\n * panel does not flicker and in-progress rows stay put.\n *\n * It is an optional, opt-in tool (enabled via the `enableTodoWrite` setting) and\n * is never registered inside a spawned subagent, so a subagent's todos cannot\n * leak into the parent's \"main\" task group.\n */\n\nimport { type Static, Type } from \"typebox\";\nimport { TODO_WRITE_TOOL_NAME } from \"../agent-frontmatter.js\";\nimport { defineTool, type ToolDefinition } from \"../extensions/types.js\";\nimport { type Task, type TaskStatus, taskOwnerId, taskStore } from \"../task-store.js\";\n\nconst todoStatusSchema = Type.Union([Type.Literal(\"pending\"), Type.Literal(\"in_progress\"), Type.Literal(\"completed\")], {\n\tdescription: \"pending = not started, in_progress = actively being worked on, completed = finished.\",\n});\n\nconst todoItemSchema = Type.Object(\n\t{\n\t\tcontent: Type.String({\n\t\t\tdescription: \"The task, in imperative form (e.g. 'Add tests for the parser').\",\n\t\t}),\n\t\tstatus: todoStatusSchema,\n\t\tactiveForm: Type.Optional(\n\t\t\tType.String({\n\t\t\t\tdescription:\n\t\t\t\t\t\"Optional present-tense form shown while the item is in_progress (e.g. 'Adding tests for the parser').\",\n\t\t\t}),\n\t\t),\n\t},\n\t{ additionalProperties: false },\n);\n\nconst todoWriteParams = Type.Object(\n\t{\n\t\ttodos: Type.Array(todoItemSchema, {\n\t\t\tdescription:\n\t\t\t\t\"The complete todo list. This REPLACES the previous list on every call, so always send every item with its current status — omitting an item removes it.\",\n\t\t}),\n\t},\n\t{ additionalProperties: false },\n);\n\ntype TodoWriteParams = Static<typeof todoWriteParams>;\ntype IncomingStatus = TodoWriteParams[\"todos\"][number][\"status\"];\n\nexport interface TodoWriteDetails {\n\ttotal: number;\n\tpending: number;\n\tinProgress: number;\n\tcompleted: number;\n}\n\n/** Map the model-facing status vocabulary onto the task store's. */\nfunction toTaskStatus(status: IncomingStatus): TaskStatus {\n\treturn status === \"completed\" ? \"done\" : status;\n}\n\nconst STATUS_GLYPH: Record<TaskStatus, string> = {\n\tpending: \"[ ]\",\n\tin_progress: \"[~]\",\n\tdone: \"[x]\",\n\tfailed: \"[!]\",\n};\n\n/** Title to display: the active-form while in progress, otherwise the content. */\nfunction displayTitle(item: TodoWriteParams[\"todos\"][number]): string {\n\tif (item.status === \"in_progress\" && item.activeForm?.trim()) return item.activeForm.trim();\n\treturn item.content.trim();\n}\n\n/** Current main-agent tasks (source unset), in stable creation order. */\nfunction mainTasks(): Task[] {\n\treturn taskStore.list().filter((t) => taskOwnerId(t) === \"main\");\n}\n\n/** Create the TodoWrite tool definition. Registered as a customTool when enabled. */\nexport function createTodoWriteToolDefinition(): ToolDefinition {\n\treturn defineTool<typeof todoWriteParams, TodoWriteDetails>({\n\t\tname: TODO_WRITE_TOOL_NAME,\n\t\tlabel: TODO_WRITE_TOOL_NAME,\n\t\tdescription: [\n\t\t\t\"Maintain a structured todo list for the current task, shown live in the task panel.\",\n\t\t\t\"Use it PROACTIVELY: at the start of any multi-step or non-trivial task, write the full plan as todos before you begin, then keep it current as you work.\",\n\t\t\t\"Mark exactly ONE item in_progress at a time, and flip an item to completed immediately after finishing it — do not batch completions or leave finished work marked in_progress.\",\n\t\t\t\"Each call sends the FULL list and REPLACES the previous one — always include every item with its current status; omitting an item removes it.\",\n\t\t\t\"Skip it only for trivial, single-step tasks where a list adds no value. When in doubt on multi-step work, use it — it keeps you from losing track of steps.\",\n\t\t].join(\"\\n\"),\n\t\tpromptSnippet:\n\t\t\t\"Plan and track multi-step work as a live todo list (use proactively; replaces the whole list each call)\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use TodoWrite proactively for any multi-step or non-trivial task: write the plan as todos up front, keep exactly one item in_progress, and mark items completed immediately as you finish them.\",\n\t\t\t\"TodoWrite replaces the entire list each call — always send all items with their current status.\",\n\t\t\t\"Skip TodoWrite for trivial single-step tasks where a checklist adds no value.\",\n\t\t],\n\t\tparameters: todoWriteParams,\n\t\tasync execute(_toolCallId, params: TodoWriteParams) {\n\t\t\tconst todos = params.todos ?? [];\n\t\t\tconst existing = mainTasks();\n\n\t\t\t// Reconcile by position: update kept items, create new ones, remove the tail.\n\t\t\tfor (let i = 0; i < todos.length; i++) {\n\t\t\t\tconst item = todos[i]!;\n\t\t\t\tconst status = toTaskStatus(item.status);\n\t\t\t\tconst title = displayTitle(item);\n\t\t\t\tconst current = existing[i];\n\t\t\t\tif (current) {\n\t\t\t\t\ttaskStore.update(current.id, { title, status });\n\t\t\t\t} else {\n\t\t\t\t\tconst created = taskStore.create(title);\n\t\t\t\t\ttaskStore.update(created.id, { status });\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (let i = todos.length; i < existing.length; i++) {\n\t\t\t\ttaskStore.remove(existing[i]!.id);\n\t\t\t}\n\n\t\t\tconst counts = todos.reduce(\n\t\t\t\t(acc, t) => {\n\t\t\t\t\tif (t.status === \"in_progress\") acc.inProgress++;\n\t\t\t\t\telse if (t.status === \"completed\") acc.completed++;\n\t\t\t\t\telse acc.pending++;\n\t\t\t\t\treturn acc;\n\t\t\t\t},\n\t\t\t\t{ pending: 0, inProgress: 0, completed: 0 },\n\t\t\t);\n\n\t\t\tconst lines = todos.map((t) => `${STATUS_GLYPH[toTaskStatus(t.status)]} ${displayTitle(t)}`);\n\t\t\tconst header =\n\t\t\t\ttodos.length === 0\n\t\t\t\t\t? \"Todo list cleared.\"\n\t\t\t\t\t: `Todos updated (${counts.inProgress} in progress, ${counts.pending} pending, ${counts.completed} completed):`;\n\t\t\tconst text = todos.length === 0 ? header : `${header}\\n${lines.join(\"\\n\")}`;\n\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text }],\n\t\t\t\tdetails: {\n\t\t\t\t\ttotal: todos.length,\n\t\t\t\t\tpending: counts.pending,\n\t\t\t\t\tinProgress: counts.inProgress,\n\t\t\t\t\tcompleted: counts.completed,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t});\n}\n"]}
1
+ {"version":3,"file":"todo.d.ts","sourceRoot":"","sources":["../../../src/core/tools/todo.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AA0CzE,MAAM,WAAW,gBAAgB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CAClB;AA2BD,qFAAqF;AACrF,wBAAgB,6BAA6B,IAAI,cAAc,CAuE9D","sourcesContent":["/**\n * TodoWrite tool: let the main agent maintain a visible todo list for the\n * current task.\n *\n * hoocode already has all the infrastructure this needs — the task store models\n * `{ title, status }` items with a per-turn lifecycle, and the TUI task panel\n * renders them. The only missing piece was a tool the model can call; this is\n * that thin adapter over `taskStore`.\n *\n * Semantics mirror Claude Code's TodoWrite: each call sends the FULL list and\n * REPLACES the previous one. Because the store is incremental (numeric ids), we\n * reconcile the incoming list against the existing main-agent tasks by position:\n * update items that are still there, create new ones, and drop the tail that was\n * removed. Reconciling (rather than clear-and-recreate) keeps ids stable so the\n * panel does not flicker and in-progress rows stay put.\n *\n * It is an optional, opt-in tool (enabled via the `enableTodoWrite` setting) and\n * is never registered inside a spawned subagent, so a subagent's todos cannot\n * leak into the parent's \"main\" task group.\n */\n\nimport { type Static, Type } from \"typebox\";\nimport { TODO_WRITE_TOOL_NAME } from \"../agent-frontmatter.js\";\nimport { defineTool, type ToolDefinition } from \"../extensions/types.js\";\nimport { type Task, type TaskStatus, taskStore } from \"../task-store.js\";\n\nconst todoStatusSchema = Type.Union([Type.Literal(\"pending\"), Type.Literal(\"in_progress\"), Type.Literal(\"completed\")], {\n\tdescription: \"pending = not started, in_progress = actively being worked on, completed = finished.\",\n});\n\nconst todoItemSchema = Type.Object(\n\t{\n\t\tcontent: Type.String({\n\t\t\tdescription: \"The task, in imperative form (e.g. 'Add tests for the parser').\",\n\t\t}),\n\t\tstatus: todoStatusSchema,\n\t\tactiveForm: Type.Optional(\n\t\t\tType.String({\n\t\t\t\tdescription:\n\t\t\t\t\t\"Optional present-tense form shown while the item is in_progress (e.g. 'Adding tests for the parser').\",\n\t\t\t}),\n\t\t),\n\t\tcomplexity: Type.Optional(\n\t\t\tType.Union([Type.Literal(\"fast\"), Type.Literal(\"standard\"), Type.Literal(\"capable\")], {\n\t\t\t\tdescription:\n\t\t\t\t\t\"Model category for ExecuteTask dispatch: fast (quick reads), standard (multi-file edits), capable (deep architecture). Optional.\",\n\t\t\t}),\n\t\t),\n\t},\n\t{ additionalProperties: false },\n);\n\nconst todoWriteParams = Type.Object(\n\t{\n\t\ttodos: Type.Array(todoItemSchema, {\n\t\t\tdescription:\n\t\t\t\t\"The complete todo list. This REPLACES the previous list on every call, so always send every item with its current status — omitting an item removes it.\",\n\t\t}),\n\t},\n\t{ additionalProperties: false },\n);\n\ntype TodoWriteParams = Static<typeof todoWriteParams>;\ntype IncomingStatus = TodoWriteParams[\"todos\"][number][\"status\"];\n\nexport interface TodoWriteDetails {\n\ttotal: number;\n\tpending: number;\n\tinProgress: number;\n\tcompleted: number;\n}\n\n/** Map the model-facing status vocabulary onto the task store's. */\nfunction toTaskStatus(status: IncomingStatus): TaskStatus {\n\treturn status === \"completed\" ? \"done\" : status;\n}\n\nconst STATUS_GLYPH: Record<TaskStatus, string> = {\n\tpending: \"[ ]\",\n\tin_progress: \"[~]\",\n\tdone: \"[x]\",\n\tfailed: \"[!]\",\n};\n\n/** Title to display: the active-form while in progress, otherwise the content. */\nfunction displayTitle(item: TodoWriteParams[\"todos\"][number]): string {\n\tif (item.status === \"in_progress\" && item.activeForm?.trim()) return item.activeForm.trim();\n\treturn item.content.trim();\n}\n\n/** Current main-agent tasks (source unset, not delegated/MCP), in stable creation order. */\nfunction mainTasks(): Task[] {\n\treturn taskStore\n\t\t.list()\n\t\t.filter((t) => t.source === undefined && t.agent === undefined && t.parentTaskId === undefined);\n}\n\n/** Create the TodoWrite tool definition. Registered as a customTool when enabled. */\nexport function createTodoWriteToolDefinition(): ToolDefinition {\n\treturn defineTool<typeof todoWriteParams, TodoWriteDetails>({\n\t\tname: TODO_WRITE_TOOL_NAME,\n\t\tlabel: TODO_WRITE_TOOL_NAME,\n\t\tdescription: [\n\t\t\t\"Maintain a structured todo list for the current task, shown live in the task panel.\",\n\t\t\t\"Use it PROACTIVELY: at the start of any multi-step or non-trivial task, write the full plan as todos before you begin, then keep it current as you work.\",\n\t\t\t\"Mark exactly ONE item in_progress at a time, and flip an item to completed immediately after finishing it — do not batch completions or leave finished work marked in_progress.\",\n\t\t\t\"Each call sends the FULL list and REPLACES the previous one — always include every item with its current status; omitting an item removes it.\",\n\t\t\t\"Skip it only for trivial, single-step tasks where a list adds no value. When in doubt on multi-step work, use it — it keeps you from losing track of steps.\",\n\t\t].join(\"\\n\"),\n\t\tpromptSnippet:\n\t\t\t\"Plan and track multi-step work as a live todo list (use proactively; replaces the whole list each call)\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use TodoWrite proactively for any multi-step or non-trivial task: write the plan as todos up front, keep exactly one item in_progress, and mark items completed immediately as you finish them.\",\n\t\t\t\"TodoWrite replaces the entire list each call — always send all items with their current status.\",\n\t\t\t\"Skip TodoWrite for trivial single-step tasks where a checklist adds no value.\",\n\t\t],\n\t\tparameters: todoWriteParams,\n\t\tasync execute(_toolCallId, params: TodoWriteParams) {\n\t\t\tconst todos = params.todos ?? [];\n\t\t\tconst existing = mainTasks();\n\n\t\t\t// Batch all mutations so the TUI renders once, not per-item.\n\t\t\ttaskStore.batch(() => {\n\t\t\t\t// Reconcile by position: update kept items, create new ones, remove the tail.\n\t\t\t\tfor (let i = 0; i < todos.length; i++) {\n\t\t\t\t\tconst item = todos[i]!;\n\t\t\t\t\tconst status = toTaskStatus(item.status);\n\t\t\t\t\tconst title = displayTitle(item);\n\t\t\t\t\tconst current = existing[i];\n\t\t\t\t\tif (current) {\n\t\t\t\t\t\ttaskStore.update(current.id, { title, status });\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst created = taskStore.create(title);\n\t\t\t\t\t\ttaskStore.update(created.id, { status });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (let i = todos.length; i < existing.length; i++) {\n\t\t\t\t\ttaskStore.remove(existing[i]!.id);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tconst counts = todos.reduce(\n\t\t\t\t(acc, t) => {\n\t\t\t\t\tif (t.status === \"in_progress\") acc.inProgress++;\n\t\t\t\t\telse if (t.status === \"completed\") acc.completed++;\n\t\t\t\t\telse acc.pending++;\n\t\t\t\t\treturn acc;\n\t\t\t\t},\n\t\t\t\t{ pending: 0, inProgress: 0, completed: 0 },\n\t\t\t);\n\n\t\t\tconst lines = todos.map((t) => `${STATUS_GLYPH[toTaskStatus(t.status)]} ${displayTitle(t)}`);\n\t\t\tconst header =\n\t\t\t\ttodos.length === 0\n\t\t\t\t\t? \"Todo list cleared.\"\n\t\t\t\t\t: `Todos updated (${counts.inProgress} in progress, ${counts.pending} pending, ${counts.completed} completed):`;\n\t\t\tconst text = todos.length === 0 ? header : `${header}\\n${lines.join(\"\\n\")}`;\n\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text }],\n\t\t\t\tdetails: {\n\t\t\t\t\ttotal: todos.length,\n\t\t\t\t\tpending: counts.pending,\n\t\t\t\t\tinProgress: counts.inProgress,\n\t\t\t\t\tcompleted: counts.completed,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t});\n}\n"]}
@@ -21,7 +21,7 @@
21
21
  import { Type } from "typebox";
22
22
  import { TODO_WRITE_TOOL_NAME } from "../agent-frontmatter.js";
23
23
  import { defineTool } from "../extensions/types.js";
24
- import { taskOwnerId, taskStore } from "../task-store.js";
24
+ import { taskStore } from "../task-store.js";
25
25
  const todoStatusSchema = Type.Union([Type.Literal("pending"), Type.Literal("in_progress"), Type.Literal("completed")], {
26
26
  description: "pending = not started, in_progress = actively being worked on, completed = finished.",
27
27
  });
@@ -33,6 +33,9 @@ const todoItemSchema = Type.Object({
33
33
  activeForm: Type.Optional(Type.String({
34
34
  description: "Optional present-tense form shown while the item is in_progress (e.g. 'Adding tests for the parser').",
35
35
  })),
36
+ complexity: Type.Optional(Type.Union([Type.Literal("fast"), Type.Literal("standard"), Type.Literal("capable")], {
37
+ description: "Model category for ExecuteTask dispatch: fast (quick reads), standard (multi-file edits), capable (deep architecture). Optional.",
38
+ })),
36
39
  }, { additionalProperties: false });
37
40
  const todoWriteParams = Type.Object({
38
41
  todos: Type.Array(todoItemSchema, {
@@ -55,9 +58,11 @@ function displayTitle(item) {
55
58
  return item.activeForm.trim();
56
59
  return item.content.trim();
57
60
  }
58
- /** Current main-agent tasks (source unset), in stable creation order. */
61
+ /** Current main-agent tasks (source unset, not delegated/MCP), in stable creation order. */
59
62
  function mainTasks() {
60
- return taskStore.list().filter((t) => taskOwnerId(t) === "main");
63
+ return taskStore
64
+ .list()
65
+ .filter((t) => t.source === undefined && t.agent === undefined && t.parentTaskId === undefined);
61
66
  }
62
67
  /** Create the TodoWrite tool definition. Registered as a customTool when enabled. */
63
68
  export function createTodoWriteToolDefinition() {
@@ -81,23 +86,26 @@ export function createTodoWriteToolDefinition() {
81
86
  async execute(_toolCallId, params) {
82
87
  const todos = params.todos ?? [];
83
88
  const existing = mainTasks();
84
- // Reconcile by position: update kept items, create new ones, remove the tail.
85
- for (let i = 0; i < todos.length; i++) {
86
- const item = todos[i];
87
- const status = toTaskStatus(item.status);
88
- const title = displayTitle(item);
89
- const current = existing[i];
90
- if (current) {
91
- taskStore.update(current.id, { title, status });
89
+ // Batch all mutations so the TUI renders once, not per-item.
90
+ taskStore.batch(() => {
91
+ // Reconcile by position: update kept items, create new ones, remove the tail.
92
+ for (let i = 0; i < todos.length; i++) {
93
+ const item = todos[i];
94
+ const status = toTaskStatus(item.status);
95
+ const title = displayTitle(item);
96
+ const current = existing[i];
97
+ if (current) {
98
+ taskStore.update(current.id, { title, status });
99
+ }
100
+ else {
101
+ const created = taskStore.create(title);
102
+ taskStore.update(created.id, { status });
103
+ }
92
104
  }
93
- else {
94
- const created = taskStore.create(title);
95
- taskStore.update(created.id, { status });
105
+ for (let i = todos.length; i < existing.length; i++) {
106
+ taskStore.remove(existing[i].id);
96
107
  }
97
- }
98
- for (let i = todos.length; i < existing.length; i++) {
99
- taskStore.remove(existing[i].id);
100
- }
108
+ });
101
109
  const counts = todos.reduce((acc, t) => {
102
110
  if (t.status === "in_progress")
103
111
  acc.inProgress++;