@kolisachint/hoocode-agent 0.4.13 → 0.4.15

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 (68) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/cli/args.d.ts +2 -0
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +8 -0
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/config.d.ts +8 -0
  7. package/dist/config.d.ts.map +1 -1
  8. package/dist/config.js +12 -0
  9. package/dist/config.js.map +1 -1
  10. package/dist/core/agent-frontmatter.d.ts +107 -0
  11. package/dist/core/agent-frontmatter.d.ts.map +1 -0
  12. package/dist/core/agent-frontmatter.js +189 -0
  13. package/dist/core/agent-frontmatter.js.map +1 -0
  14. package/dist/core/agent-registry.d.ts +52 -0
  15. package/dist/core/agent-registry.d.ts.map +1 -0
  16. package/dist/core/agent-registry.js +131 -0
  17. package/dist/core/agent-registry.js.map +1 -0
  18. package/dist/core/dispatch-evaluator.d.ts +17 -0
  19. package/dist/core/dispatch-evaluator.d.ts.map +1 -1
  20. package/dist/core/dispatch-evaluator.js +44 -10
  21. package/dist/core/dispatch-evaluator.js.map +1 -1
  22. package/dist/core/lifeguard.d.ts.map +1 -1
  23. package/dist/core/lifeguard.js +5 -5
  24. package/dist/core/lifeguard.js.map +1 -1
  25. package/dist/core/output-verifier.d.ts.map +1 -1
  26. package/dist/core/output-verifier.js +2 -2
  27. package/dist/core/output-verifier.js.map +1 -1
  28. package/dist/core/subagent-pool.d.ts +54 -3
  29. package/dist/core/subagent-pool.d.ts.map +1 -1
  30. package/dist/core/subagent-pool.js +152 -62
  31. package/dist/core/subagent-pool.js.map +1 -1
  32. package/dist/core/subagent-result.d.ts +11 -2
  33. package/dist/core/subagent-result.d.ts.map +1 -1
  34. package/dist/core/subagent-result.js +17 -4
  35. package/dist/core/subagent-result.js.map +1 -1
  36. package/dist/core/task-store.d.ts +12 -7
  37. package/dist/core/task-store.d.ts.map +1 -1
  38. package/dist/core/task-store.js +23 -15
  39. package/dist/core/task-store.js.map +1 -1
  40. package/dist/core/token-budget.d.ts.map +1 -1
  41. package/dist/core/token-budget.js +17 -14
  42. package/dist/core/token-budget.js.map +1 -1
  43. package/dist/core/tools/subagent.d.ts +32 -15
  44. package/dist/core/tools/subagent.d.ts.map +1 -1
  45. package/dist/core/tools/subagent.js +236 -112
  46. package/dist/core/tools/subagent.js.map +1 -1
  47. package/dist/main.d.ts.map +1 -1
  48. package/dist/main.js +13 -5
  49. package/dist/main.js.map +1 -1
  50. package/dist/modes/interactive/components/task-panel.d.ts +1 -1
  51. package/dist/modes/interactive/components/task-panel.d.ts.map +1 -1
  52. package/dist/modes/interactive/components/task-panel.js +31 -12
  53. package/dist/modes/interactive/components/task-panel.js.map +1 -1
  54. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  55. package/dist/modes/interactive/components/tool-execution.js +4 -2
  56. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  57. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  58. package/dist/modes/interactive/interactive-mode.js +12 -7
  59. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  60. package/dist/modes/print-mode.d.ts +2 -0
  61. package/dist/modes/print-mode.d.ts.map +1 -1
  62. package/dist/modes/print-mode.js +29 -2
  63. package/dist/modes/print-mode.js.map +1 -1
  64. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  65. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  66. package/examples/extensions/sandbox/package.json +1 -1
  67. package/examples/extensions/with-deps/package.json +1 -1
  68. package/package.json +4 -4
@@ -1,22 +1,36 @@
1
1
  /**
2
- * Subagent tool: delegate a focused task to a fresh, isolated agent loop.
2
+ * Task tool: delegate a focused task to a specialized subagent.
3
3
  *
4
- * The tool registers a task in the shared task store (visible in the task panel),
5
- * runs the subagent to completion, and returns ONLY the subagent's final
6
- * answer. It is an optional, opt-in tool (enabled via --subagent or the
4
+ * Mirrors the Claude Code `Task` tool. The parent agent decides *when* to
5
+ * delegate based on each agent's `description` (there is no deterministic gate)
6
+ * and selects *which* agent via `subagent_type`. The chosen agent runs in a
7
+ * fresh, isolated child process (SubagentPool) and only its final answer is
8
+ * returned to the parent.
9
+ *
10
+ * It is an optional, opt-in tool (enabled via --subagent or the
7
11
  * `enableSubagent` setting); see buildSessionOptions in main.ts.
8
12
  */
9
- /** System prompt appendix for the main session when subagent tooling is enabled.
13
+ import { Text } from "@kolisachint/hoocode-tui";
14
+ import { Type } from "typebox";
15
+ import { loadAgentRegistry } from "../agent-registry.js";
16
+ import { DispatchEvaluator } from "../dispatch-evaluator.js";
17
+ import { defineTool } from "../extensions/types.js";
18
+ import { getSubagentPool } from "../subagent-pool-instance.js";
19
+ import { taskStore } from "../task-store.js";
20
+ /** Render the available agents as a "- name: description" list for prompts. */
21
+ function describeAvailableAgents(cwd) {
22
+ const agents = loadAgentRegistry({ cwd }).list();
23
+ if (agents.length === 0)
24
+ return "(no agents available)";
25
+ return agents.map((a) => `- ${a.name}: ${(a.description.split("\n")[0] ?? "").trim()}`).join("\n");
26
+ }
27
+ /** System prompt appendix for the main session when the Task tool is enabled.
10
28
  * Instructs the parent agent on when and how to delegate effectively. */
11
- export const SUBAGENT_MAIN_PROMPT = `You have access to the **subagent** tool. Use it to delegate self-contained tasks to isolated subagent loops that run with their own context and return only their final answer.
29
+ export function buildTaskMainPrompt(cwd = process.cwd()) {
30
+ 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.
12
31
 
13
- Available subagent modes:
14
- - explore: read-only investigation (read, grep, find, ls, bash).
15
- - edit: make a focused code change (read, edit, write, grep, find, ls, bash).
16
- - test: run tests and report (read, bash, grep, find, ls).
17
- - fix: diagnose and fix a failure (read, edit, write, bash, grep, find, ls).
18
- - review: read-only code review (read, grep, find, ls, bash).
19
- - doc: write documentation, README, or comments (read, write, edit, grep, find, ls, bash).
32
+ Available agents (choose one via \`subagent_type\`):
33
+ ${describeAvailableAgents(cwd)}
20
34
 
21
35
  When to delegate:
22
36
  1. The work is self-contained and you only need the final result, not intermediate steps.
@@ -25,48 +39,31 @@ When to delegate:
25
39
  4. You need to run a long command or test suite and wait for its output without blocking your own reasoning.
26
40
 
27
41
  Guidelines:
28
- - Make every task specific and self-contained. The subagent cannot see this conversation.
29
- - Pass all necessary context (files, constraints, prior findings) via the \`context\` parameter.
30
- - Do NOT delegate tasks that require tight back-and-forth with your current reasoning.
31
- - Do NOT delegate edits to files you are actively reasoning about.
32
- - The subagent returns ONLY its final answer. Intermediate reasoning, tool calls, and output are hidden from you.
33
-
34
- Dispatch evaluator:
35
- - The dispatch evaluator determines if a subagent is needed. Do not spawn subagents directly unless the user explicitly requests it.
36
- - For simple single-file changes (<50 lines, read-only or trivial edit), handle them inline.
37
- - Use force=true to bypass evaluation when you are certain a subagent is required.`;
38
- import { Text } from "@kolisachint/hoocode-tui";
39
- import { Type } from "typebox";
40
- import { DispatchEvaluator } from "../dispatch-evaluator.js";
41
- import { defineTool } from "../extensions/types.js";
42
- import { getSubagentPool } from "../subagent-pool-instance.js";
43
- import { taskStore } from "../task-store.js";
44
- const subagentParams = Type.Object({
45
- task: Type.String({
46
- description: "The task to delegate. Make it specific and self-contained; the subagent cannot see this conversation.",
47
- }),
48
- context: Type.String({
49
- description: 'Context distilled from the conversation the subagent needs (files, constraints, prior findings). Pass "" if none.',
42
+ - Choose the agent whose description best matches the task.
43
+ - Make every task specific and self-contained. The subagent cannot see this conversation; pass all necessary context (files, constraints, prior findings) in \`prompt\`.
44
+ - Do NOT delegate tasks that require tight back-and-forth with your current reasoning, or edits to files you are actively reasoning about.
45
+ - The subagent returns ONLY its final answer. Its intermediate reasoning, tool calls, and output are hidden from you.
46
+ - Default to handling small, quick, or single-file work inline; delegate only self-contained units.
47
+ - Some agents are configured to run in the background (non-blocking). For those, Task returns immediately with a task_id; use the **TaskOutput** tool with that task_id to check status and collect the final answer.
48
+ - 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.`;
49
+ }
50
+ const taskParams = Type.Object({
51
+ description: Type.String({
52
+ description: "A short (3-5 word) description of the task, shown in the task panel.",
50
53
  }),
51
- mode: Type.Union([
52
- Type.Literal("explore"),
53
- Type.Literal("edit"),
54
- Type.Literal("test"),
55
- Type.Literal("fix"),
56
- Type.Literal("review"),
57
- Type.Literal("doc"),
58
- ], {
59
- description: "explore: read-only investigation. edit: make a focused code change. test: run tests and report. fix: diagnose and fix a failure. review: read-only code review. doc: write documentation.",
54
+ prompt: Type.String({
55
+ description: "The full, self-contained task for the subagent. It cannot see this conversation, so include all needed context, files, and constraints.",
60
56
  }),
61
- force: Type.Boolean({
62
- description: "Bypass dispatch evaluation and spawn the subagent directly. Use when you are certain a subagent is required.",
63
- default: false,
57
+ subagent_type: Type.String({
58
+ description: "The name of the specialized agent to delegate to. Must be one of the available agents.",
64
59
  }),
60
+ resume_task_id: Type.Optional(Type.String({
61
+ 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.",
62
+ })),
65
63
  });
66
64
  /**
67
- * A short, human-readable task name for the task panel: the first line of the
68
- * task limited to ~4–8 words so it stays glanceable in the pane. A character cap
69
- * guards against a single very long word.
65
+ * A short, human-readable task name for the task panel: the first line limited
66
+ * to ~8 words so it stays glanceable. A character cap guards a single long word.
70
67
  */
71
68
  function summarize(task) {
72
69
  const firstLine = (task.trim().split("\n")[0] ?? "").trim();
@@ -78,82 +75,104 @@ function summarize(task) {
78
75
  name = `${name.slice(0, 59)}…`;
79
76
  return name;
80
77
  }
81
- /** Quick check: should this task go to a subagent? */
78
+ /** Quick advisory check: would the dispatch evaluator delegate this task?
79
+ * The evaluator is non-blocking; this is exposed for diagnostics/tools only. */
82
80
  export function isSubagentRecommended(task) {
83
- const evaluator = new DispatchEvaluator();
84
- return evaluator.evaluate(task).should_delegate;
81
+ return new DispatchEvaluator().evaluate(task).should_delegate;
85
82
  }
86
- /** Create the subagent tool definition. Registered as a customTool when enabled. */
87
- export function createSubagentToolDefinition() {
83
+ /** Create the Task tool definition. Registered as a customTool when enabled. */
84
+ export function createTaskToolDefinition(cwd = process.cwd()) {
85
+ const agentList = describeAvailableAgents(cwd);
88
86
  return defineTool({
89
- name: "subagent",
90
- label: "Subagent",
87
+ name: "Task",
88
+ label: "Task",
91
89
  description: [
92
- "Delegate a focused task to a subagent that runs in a fresh, isolated context (it cannot see this conversation).",
93
- "Pass everything it needs via `context`. The subagent returns only its final answer.",
94
- "Modes: explore, edit, test, fix, review, doc.",
95
- "WHEN TO USE: (1) The work is self-contained and you do not need to see intermediate steps — only the final result.",
96
- "(2) You want to investigate or edit something in parallel without losing your current context or reasoning chain.",
97
- "(3) The task is a discrete unit (explore one module, run one test file, review one PR, fix one isolated bug, write docs).",
98
- "(4) You need to run a long command or test suite and wait for its output without blocking your own reasoning.",
99
- "Do NOT use for tasks that require tight back-and-forth with your current reasoning or that change files you are actively reasoning about.",
100
- "Use force=true to bypass dispatch evaluation when you are certain a subagent is required.",
101
- ].join(" "),
102
- promptSnippet: "delegate a self-contained task to an isolated subagent (modes: explore/edit/test/fix/review/doc)",
103
- parameters: subagentParams,
90
+ "Delegate a focused task to a specialized subagent that runs in a fresh, isolated context (it cannot see this conversation).",
91
+ "Select the agent via `subagent_type`; pass everything it needs via `prompt`. The subagent returns only its final answer.",
92
+ "Available agents:",
93
+ agentList,
94
+ "WHEN TO USE: (1) self-contained work where you only need the final result;",
95
+ "(2) parallel investigation/edits without losing your reasoning chain;",
96
+ "(3) a discrete unit (explore one module, run one test file, review one PR, fix one isolated bug, write docs);",
97
+ "(4) a long command or test suite you want to run without blocking your reasoning.",
98
+ "Do NOT use for tasks needing tight back-and-forth with your current reasoning, or edits to files you are actively reasoning about.",
99
+ "Prefer handling small, quick, or single-file tasks yourself; delegate only self-contained units of work.",
100
+ ].join("\n"),
101
+ promptSnippet: "delegate a self-contained task to a specialized subagent (choose via subagent_type)",
102
+ parameters: taskParams,
104
103
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
105
- const forcedMode = params.mode;
106
- // Dispatch evaluation: a single evaluator/analysis decides inline vs delegate
107
- // and (when not forced) which mode to use.
108
- const evaluator = new DispatchEvaluator();
109
- const analysis = evaluator.evaluate(params.task);
110
- if (!params.force && !analysis.should_delegate) {
104
+ const pool = getSubagentPool(ctx.cwd);
105
+ // Resume path: continue a previously dispatched subagent with a follow-up
106
+ // prompt, reusing its persisted session (full prior transcript).
107
+ const resumeId = params.resume_task_id?.trim();
108
+ if (resumeId) {
109
+ const summary = params.description?.trim() || summarize(params.prompt);
110
+ const task = taskStore.create(summary, { subagentMode: params.subagent_type });
111
+ taskStore.update(task.id, { status: "in_progress" });
112
+ try {
113
+ const dispatchResult = await pool.resume(resumeId, params.prompt, {
114
+ model: ctx.model?.id,
115
+ provider: ctx.model?.provider,
116
+ });
117
+ // The session lives under the original task id; keep it as the resume handle.
118
+ return finalizeForegroundResult(dispatchResult, params.subagent_type, task.id, resumeId);
119
+ }
120
+ catch (error) {
121
+ taskStore.update(task.id, { status: "failed" });
122
+ throw error;
123
+ }
124
+ }
125
+ // The model has already decided to delegate and which agent to use; honor
126
+ // it. Validate the requested agent against the registry (no routing gate).
127
+ const registry = loadAgentRegistry({ cwd: ctx.cwd });
128
+ const def = registry.get(params.subagent_type);
129
+ if (!def) {
130
+ const available = registry
131
+ .list()
132
+ .map((a) => a.name)
133
+ .join(", ");
134
+ throw new Error(`Unknown subagent_type: "${params.subagent_type}". Available agents: ${available || "(none)"}.`);
135
+ }
136
+ const summary = params.description?.trim() || summarize(params.prompt);
137
+ const task = taskStore.create(summary, { subagentMode: params.subagent_type });
138
+ // Background agents: dispatch detached and return a handle immediately so
139
+ // the parent keeps reasoning. The parent polls via the TaskOutput tool.
140
+ if (def.background) {
141
+ taskStore.update(task.id, { status: "in_progress" });
142
+ const dispatched = pool.dispatchDetached(params.prompt, {
143
+ forceAgent: params.subagent_type,
144
+ context: "",
145
+ model: ctx.model?.id,
146
+ provider: ctx.model?.provider,
147
+ });
148
+ const poolTaskId = dispatched.task_id;
149
+ if (poolTaskId)
150
+ trackBackgroundTask(pool, poolTaskId, task.id);
111
151
  return {
112
152
  content: [
113
153
  {
114
154
  type: "text",
115
- text: `Task is simple enough for inline handling. Reason: ${analysis.reason}. Use force=true for subagent override.`,
155
+ text: `Background subagent (${params.subagent_type}) started with task_id "${poolTaskId}". It runs without blocking you. Call the TaskOutput tool with this task_id to check its status and collect the final answer.`,
116
156
  },
117
157
  ],
118
- details: { mode: forcedMode, ok: true, taskId: 0, inline: true },
158
+ details: {
159
+ subagent_type: params.subagent_type,
160
+ ok: true,
161
+ taskId: task.id,
162
+ poolTaskId,
163
+ background: true,
164
+ },
119
165
  };
120
166
  }
121
- const mode = params.force ? forcedMode : (analysis.agent_type ?? "explore");
122
- const summary = summarize(params.task);
123
- const task = taskStore.create(summary, { subagentMode: mode });
124
167
  taskStore.update(task.id, { status: "in_progress" });
125
168
  try {
126
- const pool = getSubagentPool(ctx.cwd);
127
- const dispatchResult = await pool.dispatch(params.task, {
128
- forceAgent: mode,
129
- context: params.context,
169
+ const dispatchResult = await pool.dispatch(params.prompt, {
170
+ forceAgent: params.subagent_type,
171
+ context: "",
130
172
  model: ctx.model?.id,
131
173
  provider: ctx.model?.provider,
132
174
  });
133
- const result = dispatchResult.result;
134
- const resultData = result?.result_data;
135
- const usage = resultData?.usage;
136
- if (!result || !result.ok) {
137
- // Signal failure by throwing: the agent loop derives a tool's error
138
- // state from a thrown error, not from a returned flag.
139
- taskStore.update(task.id, { status: "failed", usage });
140
- const reason = result?.error ??
141
- (result?.budget_exceeded
142
- ? "token budget exceeded before producing a result"
143
- : result?.status
144
- ? `subagent ${result.status}`
145
- : "unknown error");
146
- throw new Error(`Subagent (${mode}) failed: ${reason}`);
147
- }
148
- // Leave the task in the store with its final status. It stays visible in
149
- // the task panel until the next user message arrives (retireFinished is
150
- // called when the user starts the next turn).
151
- taskStore.update(task.id, { status: "done", usage });
152
- const answer = resultData?.summary || "(subagent returned no output)";
153
- return {
154
- content: [{ type: "text", text: answer }],
155
- details: { mode, ok: true, taskId: task.id },
156
- };
175
+ return finalizeForegroundResult(dispatchResult, params.subagent_type, task.id, dispatchResult.task_id);
157
176
  }
158
177
  catch (error) {
159
178
  taskStore.update(task.id, { status: "failed" });
@@ -161,13 +180,118 @@ export function createSubagentToolDefinition() {
161
180
  }
162
181
  },
163
182
  renderCall(args, theme) {
164
- const mode = args.mode ?? "explore";
165
- const preview = summarize(args.task ?? "");
166
- const text = theme.fg("toolTitle", theme.bold("subagent ")) +
167
- theme.fg("accent", `[${mode}]`) +
183
+ const type = args.subagent_type ?? "agent";
184
+ const preview = summarize(args.description ?? args.prompt ?? "");
185
+ const text = theme.fg("toolTitle", theme.bold("Task ")) +
186
+ theme.fg("accent", `[${type}]`) +
168
187
  theme.fg("dim", ` ${preview}`);
169
188
  return new Text(text, 0, 0);
170
189
  },
171
190
  });
172
191
  }
192
+ /** Extract the final answer from a finished dispatch, updating the task panel. */
193
+ function finalizeForegroundResult(dispatchResult, subagentType, taskStoreId, resumeHandle) {
194
+ const result = dispatchResult.result;
195
+ const resultData = result?.result_data;
196
+ const usage = resultData?.usage;
197
+ if (!result || !result.ok) {
198
+ // Signal failure by throwing: the agent loop derives a tool's error state
199
+ // from a thrown error, not from a returned flag.
200
+ taskStore.update(taskStoreId, { status: "failed", usage });
201
+ const reason = result?.error ?? (result?.status ? `subagent ${result.status}` : "unknown error");
202
+ throw new Error(`Subagent (${subagentType}) failed: ${reason}`);
203
+ }
204
+ // Leave the task in the store with its final status; it stays visible in the
205
+ // task panel until the next user message arrives.
206
+ taskStore.update(taskStoreId, { status: "done", usage });
207
+ let answer = resultData?.summary || "(subagent returned no output)";
208
+ // Partial results are resumable; surface the handle so the parent can continue.
209
+ if (result.status === "partial" && resumeHandle) {
210
+ answer += `\n\n[Partial result. To continue this subagent, call Task again with resume_task_id="${resumeHandle}".]`;
211
+ }
212
+ return {
213
+ content: [{ type: "text", text: answer }],
214
+ details: { subagent_type: subagentType, ok: true, taskId: taskStoreId, poolTaskId: resumeHandle },
215
+ };
216
+ }
217
+ /**
218
+ * Keep the task panel in sync for a detached background subagent: when the pool
219
+ * reports the task finished, update the stored task's status and detach.
220
+ */
221
+ function trackBackgroundTask(pool, poolTaskId, taskStoreId) {
222
+ function finish(status) {
223
+ taskStore.update(taskStoreId, { status });
224
+ pool.off("task_done", onDone);
225
+ pool.off("task_failed", onFail);
226
+ pool.off("task_stalled", onFail);
227
+ pool.off("task_timeout", onFail);
228
+ }
229
+ function onDone(data) {
230
+ if (data?.task_id === poolTaskId)
231
+ finish("done");
232
+ }
233
+ function onFail(data) {
234
+ if (data?.task_id === poolTaskId)
235
+ finish("failed");
236
+ }
237
+ pool.on("task_done", onDone);
238
+ pool.on("task_failed", onFail);
239
+ pool.on("task_stalled", onFail);
240
+ pool.on("task_timeout", onFail);
241
+ }
242
+ const taskOutputParams = Type.Object({
243
+ task_id: Type.String({
244
+ description: "The task_id of a background (or previously dispatched) subagent, as returned by the Task tool.",
245
+ }),
246
+ });
247
+ /**
248
+ * TaskOutput tool: poll a background subagent and collect its final answer.
249
+ * Returns the current status while running, or the subagent's final answer once
250
+ * complete. Registered alongside the Task tool when subagents are enabled.
251
+ */
252
+ export function createTaskOutputToolDefinition() {
253
+ return defineTool({
254
+ name: "TaskOutput",
255
+ label: "TaskOutput",
256
+ description: [
257
+ "Check the status of a background subagent and collect its final answer once it finishes.",
258
+ "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.",
259
+ ].join("\n"),
260
+ promptSnippet: "check status / collect the result of a background subagent",
261
+ parameters: taskOutputParams,
262
+ async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
263
+ const pool = getSubagentPool(ctx.cwd);
264
+ const status = pool.get_status(params.task_id);
265
+ if (status === "running" || status === "queued") {
266
+ return {
267
+ content: [
268
+ {
269
+ type: "text",
270
+ text: `Subagent task "${params.task_id}" is ${status}. Call TaskOutput again later to collect its result.`,
271
+ },
272
+ ],
273
+ details: { task_id: params.task_id, status, ok: true },
274
+ };
275
+ }
276
+ const result = pool.collect(params.task_id);
277
+ if (!result) {
278
+ throw new Error(`No result available for task "${params.task_id}" (status: ${status}). It may not exist or its result was already collected.`);
279
+ }
280
+ if (!result.ok) {
281
+ const reason = result.error ?? (result.status ? `subagent ${result.status}` : status);
282
+ throw new Error(`Background subagent "${params.task_id}" failed: ${reason}`);
283
+ }
284
+ const resultData = result.result_data;
285
+ const answer = resultData?.summary || "(subagent returned no output)";
286
+ return {
287
+ content: [{ type: "text", text: answer }],
288
+ details: { task_id: params.task_id, status: result.status ?? "complete", ok: true },
289
+ };
290
+ },
291
+ renderCall(args, theme) {
292
+ const text = theme.fg("toolTitle", theme.bold("TaskOutput ")) + theme.fg("dim", String(args.task_id ?? ""));
293
+ return new Text(text, 0, 0);
294
+ },
295
+ });
296
+ }
173
297
  //# 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 * Subagent tool: delegate a focused task to a fresh, isolated agent loop.\n *\n * The tool registers a task in the shared task store (visible in the task panel),\n * runs the subagent to completion, and returns ONLY the subagent's final\n * answer. It is an optional, opt-in tool (enabled via --subagent or the\n * `enableSubagent` setting); see buildSessionOptions in main.ts.\n */\n\n/** System prompt appendix for the main session when subagent tooling is enabled.\n * Instructs the parent agent on when and how to delegate effectively. */\nexport const SUBAGENT_MAIN_PROMPT = `You have access to the **subagent** tool. Use it to delegate self-contained tasks to isolated subagent loops that run with their own context and return only their final answer.\n\nAvailable subagent modes:\n- explore: read-only investigation (read, grep, find, ls, bash).\n- edit: make a focused code change (read, edit, write, grep, find, ls, bash).\n- test: run tests and report (read, bash, grep, find, ls).\n- fix: diagnose and fix a failure (read, edit, write, bash, grep, find, ls).\n- review: read-only code review (read, grep, find, ls, bash).\n- doc: write documentation, README, or comments (read, write, edit, grep, find, ls, bash).\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- Make every task specific and self-contained. The subagent cannot see this conversation.\n- Pass all necessary context (files, constraints, prior findings) via the \\`context\\` parameter.\n- Do NOT delegate tasks that require tight back-and-forth with your current reasoning.\n- Do NOT delegate edits to files you are actively reasoning about.\n- The subagent returns ONLY its final answer. Intermediate reasoning, tool calls, and output are hidden from you.\n\nDispatch evaluator:\n- The dispatch evaluator determines if a subagent is needed. Do not spawn subagents directly unless the user explicitly requests it.\n- For simple single-file changes (<50 lines, read-only or trivial edit), handle them inline.\n- Use force=true to bypass evaluation when you are certain a subagent is required.`;\n\nimport { Text } from \"@kolisachint/hoocode-tui\";\nimport { type Static, Type } from \"typebox\";\nimport { DispatchEvaluator } from \"../dispatch-evaluator.js\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { defineTool } from \"../extensions/types.js\";\nimport type { SubagentMode } from \"../subagent.js\";\nimport { getSubagentPool } from \"../subagent-pool-instance.js\";\nimport type { SubagentResultFile } from \"../subagent-result.js\";\nimport { taskStore } from \"../task-store.js\";\n\nconst subagentParams = Type.Object({\n\ttask: Type.String({\n\t\tdescription:\n\t\t\t\"The task to delegate. Make it specific and self-contained; the subagent cannot see this conversation.\",\n\t}),\n\tcontext: Type.String({\n\t\tdescription:\n\t\t\t'Context distilled from the conversation the subagent needs (files, constraints, prior findings). Pass \"\" if none.',\n\t}),\n\tmode: Type.Union(\n\t\t[\n\t\t\tType.Literal(\"explore\"),\n\t\t\tType.Literal(\"edit\"),\n\t\t\tType.Literal(\"test\"),\n\t\t\tType.Literal(\"fix\"),\n\t\t\tType.Literal(\"review\"),\n\t\t\tType.Literal(\"doc\"),\n\t\t],\n\t\t{\n\t\t\tdescription:\n\t\t\t\t\"explore: read-only investigation. edit: make a focused code change. test: run tests and report. fix: diagnose and fix a failure. review: read-only code review. doc: write documentation.\",\n\t\t},\n\t),\n\tforce: Type.Boolean({\n\t\tdescription:\n\t\t\t\"Bypass dispatch evaluation and spawn the subagent directly. Use when you are certain a subagent is required.\",\n\t\tdefault: false,\n\t}),\n});\n\ntype SubagentParams = Static<typeof subagentParams>;\n\nexport interface SubagentToolDetails {\n\tmode: SubagentMode;\n\tok: boolean;\n\terror?: string;\n\ttaskId: number;\n\t/** True when the evaluator handled the task inline instead of delegating. */\n\tinline?: boolean;\n}\n\n/**\n * A short, human-readable task name for the task panel: the first line of the\n * task limited to ~4–8 words so it stays glanceable in the pane. A character cap\n * guards against a single very 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/** Quick check: should this task go to a subagent? */\nexport function isSubagentRecommended(task: string): boolean {\n\tconst evaluator = new DispatchEvaluator();\n\treturn evaluator.evaluate(task).should_delegate;\n}\n\n/** Create the subagent tool definition. Registered as a customTool when enabled. */\nexport function createSubagentToolDefinition(): ToolDefinition {\n\treturn defineTool<typeof subagentParams, SubagentToolDetails>({\n\t\tname: \"subagent\",\n\t\tlabel: \"Subagent\",\n\t\tdescription: [\n\t\t\t\"Delegate a focused task to a subagent that runs in a fresh, isolated context (it cannot see this conversation).\",\n\t\t\t\"Pass everything it needs via `context`. The subagent returns only its final answer.\",\n\t\t\t\"Modes: explore, edit, test, fix, review, doc.\",\n\t\t\t\"WHEN TO USE: (1) The work is self-contained and you do not need to see intermediate steps — only the final result.\",\n\t\t\t\"(2) You want to investigate or edit something in parallel without losing your current context or reasoning chain.\",\n\t\t\t\"(3) The task is a discrete unit (explore one module, run one test file, review one PR, fix one isolated bug, write docs).\",\n\t\t\t\"(4) You need to run a long command or test suite and wait for its output without blocking your own reasoning.\",\n\t\t\t\"Do NOT use for tasks that require tight back-and-forth with your current reasoning or that change files you are actively reasoning about.\",\n\t\t\t\"Use force=true to bypass dispatch evaluation when you are certain a subagent is required.\",\n\t\t].join(\" \"),\n\t\tpromptSnippet: \"delegate a self-contained task to an isolated subagent (modes: explore/edit/test/fix/review/doc)\",\n\t\tparameters: subagentParams,\n\n\t\tasync execute(_toolCallId, params: SubagentParams, _signal, _onUpdate, ctx) {\n\t\t\tconst forcedMode = params.mode as SubagentMode;\n\n\t\t\t// Dispatch evaluation: a single evaluator/analysis decides inline vs delegate\n\t\t\t// and (when not forced) which mode to use.\n\t\t\tconst evaluator = new DispatchEvaluator();\n\t\t\tconst analysis = evaluator.evaluate(params.task);\n\t\t\tif (!params.force && !analysis.should_delegate) {\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\",\n\t\t\t\t\t\t\ttext: `Task is simple enough for inline handling. Reason: ${analysis.reason}. Use force=true for subagent override.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: { mode: forcedMode, ok: true, taskId: 0, inline: true },\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst mode: SubagentMode = params.force ? forcedMode : ((analysis.agent_type as SubagentMode) ?? \"explore\");\n\t\t\tconst summary = summarize(params.task);\n\n\t\t\tconst task = taskStore.create(summary, { subagentMode: mode });\n\t\t\ttaskStore.update(task.id, { status: \"in_progress\" });\n\t\t\ttry {\n\t\t\t\tconst pool = getSubagentPool(ctx.cwd);\n\t\t\t\tconst dispatchResult = await pool.dispatch(params.task, {\n\t\t\t\t\tforceAgent: mode,\n\t\t\t\t\tcontext: params.context,\n\t\t\t\t\tmodel: ctx.model?.id,\n\t\t\t\t\tprovider: ctx.model?.provider,\n\t\t\t\t});\n\n\t\t\t\tconst result = dispatchResult.result;\n\t\t\t\tconst resultData = result?.result_data as SubagentResultFile | undefined;\n\t\t\t\tconst usage = resultData?.usage;\n\n\t\t\t\tif (!result || !result.ok) {\n\t\t\t\t\t// Signal failure by throwing: the agent loop derives a tool's error\n\t\t\t\t\t// state from a thrown error, not from a returned flag.\n\t\t\t\t\ttaskStore.update(task.id, { status: \"failed\", usage });\n\t\t\t\t\tconst reason =\n\t\t\t\t\t\tresult?.error ??\n\t\t\t\t\t\t(result?.budget_exceeded\n\t\t\t\t\t\t\t? \"token budget exceeded before producing a result\"\n\t\t\t\t\t\t\t: result?.status\n\t\t\t\t\t\t\t\t? `subagent ${result.status}`\n\t\t\t\t\t\t\t\t: \"unknown error\");\n\t\t\t\t\tthrow new Error(`Subagent (${mode}) failed: ${reason}`);\n\t\t\t\t}\n\n\t\t\t\t// Leave the task in the store with its final status. It stays visible in\n\t\t\t\t// the task panel until the next user message arrives (retireFinished is\n\t\t\t\t// called when the user starts the next turn).\n\t\t\t\ttaskStore.update(task.id, { status: \"done\", usage });\n\t\t\t\tconst answer = resultData?.summary || \"(subagent returned no output)\";\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\", text: answer }],\n\t\t\t\t\tdetails: { mode, ok: true, taskId: task.id },\n\t\t\t\t};\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 mode = args.mode ?? \"explore\";\n\t\t\tconst preview = summarize(args.task ?? \"\");\n\t\t\tconst text =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"subagent \")) +\n\t\t\t\ttheme.fg(\"accent\", `[${mode}]`) +\n\t\t\t\ttheme.fg(\"dim\", ` ${preview}`);\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 --subagent 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 { loadAgentRegistry } from \"../agent-registry.js\";\nimport { DispatchEvaluator } from \"../dispatch-evaluator.js\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { defineTool } from \"../extensions/types.js\";\nimport type { SubagentPool, TaskResult } from \"../subagent-pool.js\";\nimport { getSubagentPool } from \"../subagent-pool-instance.js\";\nimport type { SubagentResultFile } from \"../subagent-result.js\";\nimport { taskStore } from \"../task-store.js\";\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}: ${(a.description.split(\"\\n\")[0] ?? \"\").trim()}`).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- Default to handling small, quick, or single-file work inline; delegate only self-contained units.\n- Some agents are configured to run in the background (non-blocking). For those, Task returns immediately with a task_id; use the **TaskOutput** tool with that task_id to check status and collect the final answer.\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/** Quick advisory check: would the dispatch evaluator delegate this task?\n * The evaluator is non-blocking; this is exposed for diagnostics/tools only. */\nexport function isSubagentRecommended(task: string): boolean {\n\treturn new DispatchEvaluator().evaluate(task).should_delegate;\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\treturn defineTool<typeof taskParams, TaskToolDetails>({\n\t\tname: \"Task\",\n\t\tlabel: \"Task\",\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\"Prefer handling small, quick, or single-file tasks yourself; delegate only self-contained units of work.\",\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// 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, { subagentMode: 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 finalizeForegroundResult(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, { subagentMode: params.subagent_type });\n\n\t\t\t// Background agents: dispatch detached and return a handle immediately so\n\t\t\t// the parent keeps reasoning. The parent polls via the TaskOutput tool.\n\t\t\tif (def.background) {\n\t\t\t\ttaskStore.update(task.id, { status: \"in_progress\" });\n\t\t\t\tconst dispatched = pool.dispatchDetached(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});\n\t\t\t\tconst poolTaskId = dispatched.task_id;\n\t\t\t\tif (poolTaskId) trackBackgroundTask(pool, poolTaskId, task.id);\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: `Background subagent (${params.subagent_type}) started with task_id \"${poolTaskId}\". It runs without blocking you. Call the TaskOutput tool with this task_id to check its status and collect the final answer.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\tdetails: {\n\t\t\t\t\t\tsubagent_type: params.subagent_type,\n\t\t\t\t\t\tok: true,\n\t\t\t\t\t\ttaskId: task.id,\n\t\t\t\t\t\tpoolTaskId,\n\t\t\t\t\t\tbackground: true,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\n\t\t\ttaskStore.update(task.id, { status: \"in_progress\" });\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});\n\t\t\t\treturn finalizeForegroundResult(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(\"Task \")) +\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/** Extract the final answer from a finished dispatch, updating the task panel. */\nfunction finalizeForegroundResult(\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\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\ttaskStore.update(taskStoreId, { status: \"failed\", usage });\n\t\tconst reason = result?.error ?? (result?.status ? `subagent ${result.status}` : \"unknown error\");\n\t\tthrow new Error(`Subagent (${subagentType}) failed: ${reason}`);\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.\n\ttaskStore.update(taskStoreId, { status: \"done\", usage });\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\n/**\n * Keep the task panel in sync for a detached background subagent: when the pool\n * reports the task finished, update the stored task's status and detach.\n */\nfunction trackBackgroundTask(pool: SubagentPool, poolTaskId: string, taskStoreId: number): void {\n\tfunction finish(status: \"done\" | \"failed\"): void {\n\t\ttaskStore.update(taskStoreId, { status });\n\t\tpool.off(\"task_done\", onDone);\n\t\tpool.off(\"task_failed\", onFail);\n\t\tpool.off(\"task_stalled\", onFail);\n\t\tpool.off(\"task_timeout\", onFail);\n\t}\n\tfunction onDone(data: { task_id?: string }): void {\n\t\tif (data?.task_id === poolTaskId) finish(\"done\");\n\t}\n\tfunction onFail(data: { task_id?: string }): void {\n\t\tif (data?.task_id === poolTaskId) finish(\"failed\");\n\t}\n\tpool.on(\"task_done\", onDone);\n\tpool.on(\"task_failed\", onFail);\n\tpool.on(\"task_stalled\", onFail);\n\tpool.on(\"task_timeout\", onFail);\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\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"]}