@narumitw/pi-subagents 0.15.1 → 0.17.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@narumitw/pi-subagents",
3
- "version": "0.15.1",
3
+ "version": "0.17.0",
4
4
  "description": "Pi extension for delegating work to specialized isolated subagents.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/execution.ts CHANGED
@@ -6,17 +6,19 @@ import {
6
6
  type AgentScope,
7
7
  type SubagentThinkingLevel,
8
8
  } from "./agents.js";
9
+ import { DEFAULT_MAX_CONTEXT_BYTES, truncateUtf8 } from "./limits.js";
10
+ import type { SubagentParams } from "./params.js";
9
11
  import {
10
12
  buildFanInContext,
13
+ formatResultFailure,
11
14
  getResultFinalOutput,
15
+ isResultError,
12
16
  mapWithConcurrencyLimit,
13
- runSingleAgent,
14
17
  type OnUpdateCallback,
18
+ runSingleAgent,
15
19
  type SingleResult,
16
20
  type SubagentDetails,
17
21
  } from "./runner.js";
18
- import { DEFAULT_MAX_CONTEXT_BYTES, truncateUtf8 } from "./limits.js";
19
- import type { SubagentParams } from "./params.js";
20
22
  import { readSubagentSettings, resolveSubagentThinkingLevel } from "./settings.js";
21
23
 
22
24
  const MAX_PARALLEL_TASKS = 8;
@@ -225,10 +227,9 @@ export async function executeSubagent(
225
227
  );
226
228
  results.push(result);
227
229
 
228
- const isError =
229
- result.exitCode !== 0 || result.stopReason === "error" || result.stopReason === "aborted";
230
+ const isError = isResultError(result);
230
231
  if (isError) {
231
- const errorMsg = result.errorMessage || result.stderr || getResultFinalOutput(result) || "(no output)";
232
+ const errorMsg = formatResultFailure(result);
232
233
  return {
233
234
  content: [{ type: "text", text: `Chain stopped at step ${i + 1} (${step.agent}): ${errorMsg}` }],
234
235
  details: { ...makeDetails("chain")(results), isError: true },
@@ -285,6 +286,34 @@ export async function executeSubagent(
285
286
  const emitParallelUpdate = () => {
286
287
  status.update(parallelStatus(doneCount, allResults.length, runningCount));
287
288
  if (onUpdate) {
289
+ const aggregator = params.aggregator;
290
+ const pendingAggregator: SingleResult | undefined =
291
+ aggregator && !signal?.aborted && doneCount === allResults.length
292
+ ? {
293
+ agent: aggregator.agent,
294
+ agentSource:
295
+ agents.find((agent) => agent.name === aggregator.agent)?.source ?? "unknown",
296
+ task: aggregator.task,
297
+ exitCode: -1,
298
+ messages: [],
299
+ stderr: "",
300
+ usage: {
301
+ input: 0,
302
+ output: 0,
303
+ cacheRead: 0,
304
+ cacheWrite: 0,
305
+ cost: 0,
306
+ contextTokens: 0,
307
+ turns: 0,
308
+ },
309
+ thinkingLevel: resolveThinkingLevel(
310
+ aggregator.agent,
311
+ aggregator.thinkingLevel,
312
+ ),
313
+ timeoutMs: resolveTimeoutMs(aggregator.agent, aggregator.timeoutMs),
314
+ finalOutput: "",
315
+ }
316
+ : undefined;
288
317
  onUpdate({
289
318
  content: [
290
319
  {
@@ -292,7 +321,7 @@ export async function executeSubagent(
292
321
  text: `Parallel: ${doneCount}/${allResults.length} done, ${runningCount} running...`,
293
322
  },
294
323
  ],
295
- details: makeDetails("parallel")([...allResults]),
324
+ details: makeDetails("parallel")([...allResults], pendingAggregator),
296
325
  });
297
326
  }
298
327
  };
@@ -372,14 +401,16 @@ export async function executeSubagent(
372
401
  );
373
402
  }
374
403
 
375
- const successCount = results.filter((r) => r.exitCode === 0).length;
376
- const summaries = results.map((r) => {
377
- const output = getResultFinalOutput(r);
378
- const error = r.errorMessage || r.stderr.trim();
379
- const summaryText = output || error;
380
- const preview = summaryText.slice(0, 160) + (summaryText.length > 160 ? "..." : "");
381
- return `[${r.agent}] ${r.exitCode === 0 ? "completed" : "failed"}: ${preview || "(no output)"}`;
404
+ const successCount = results.filter((result) => !isResultError(result)).length;
405
+ const summaries = results.map((result) => {
406
+ const failed = isResultError(result);
407
+ const output = getResultFinalOutput(result);
408
+ const error = result.errorMessage || result.stderr.trim();
409
+ const summaryText = failed ? formatResultFailure(result) : output || error;
410
+ const preview = truncateUtf8(summaryText, 160).text;
411
+ return `[${result.agent}] ${failed ? "failed" : "completed"}: ${preview || "(no output)"}`;
382
412
  });
413
+ const aggregatorFailed = aggregatorResult ? isResultError(aggregatorResult) : false;
383
414
  const aggregatorOutput = aggregatorResult ? getResultFinalOutput(aggregatorResult) : "";
384
415
  const aggregatorError = aggregatorResult?.errorMessage || aggregatorResult?.stderr.trim() || "";
385
416
  return {
@@ -387,23 +418,19 @@ export async function executeSubagent(
387
418
  {
388
419
  type: "text",
389
420
  text: aggregatorResult
390
- ? aggregatorOutput || aggregatorError || `(aggregator ${aggregatorResult.agent} produced no output)`
421
+ ? aggregatorFailed
422
+ ? formatResultFailure(aggregatorResult)
423
+ : aggregatorOutput ||
424
+ aggregatorError ||
425
+ `(aggregator ${aggregatorResult.agent} produced no output)`
391
426
  : `Parallel: ${successCount}/${results.length} succeeded\n\n${summaries.join("\n\n")}`,
392
427
  },
393
428
  ],
394
429
  details: {
395
430
  ...makeDetails("parallel")(results, aggregatorResult),
396
- isError: aggregatorResult
397
- ? aggregatorResult.exitCode !== 0 ||
398
- aggregatorResult.stopReason === "error" ||
399
- aggregatorResult.stopReason === "aborted"
400
- : false,
431
+ isError: aggregatorFailed,
401
432
  },
402
- isError: aggregatorResult
403
- ? aggregatorResult.exitCode !== 0 ||
404
- aggregatorResult.stopReason === "error" ||
405
- aggregatorResult.stopReason === "aborted"
406
- : undefined,
433
+ isError: aggregatorResult ? aggregatorFailed : undefined,
407
434
  };
408
435
  } finally {
409
436
  status.clear();
@@ -427,9 +454,9 @@ export async function executeSubagent(
427
454
  onUpdate,
428
455
  makeDetails("single"),
429
456
  );
430
- const isError = result.exitCode !== 0 || result.stopReason === "error" || result.stopReason === "aborted";
457
+ const isError = isResultError(result);
431
458
  if (isError) {
432
- const errorMsg = result.errorMessage || result.stderr || getResultFinalOutput(result) || "(no output)";
459
+ const errorMsg = formatResultFailure(result);
433
460
  return {
434
461
  content: [{ type: "text", text: `Agent ${result.stopReason || "failed"}: ${errorMsg}` }],
435
462
  details: { ...makeDetails("single")([result]), isError: true },