@selesai/code 0.5.29 → 0.6.1

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 (83) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +1 -1
  3. package/dist/core/system-prompt.d.ts.map +1 -1
  4. package/dist/core/system-prompt.js +18 -0
  5. package/dist/core/system-prompt.js.map +1 -1
  6. package/dist/core/system-prompt.test.d.ts +2 -0
  7. package/dist/core/system-prompt.test.d.ts.map +1 -0
  8. package/dist/core/system-prompt.test.js +89 -0
  9. package/dist/core/system-prompt.test.js.map +1 -0
  10. package/dist/defaults/models.json +13 -45
  11. package/dist/defaults/settings.json +1 -2
  12. package/dist/extensions/copy-turn.test.ts +131 -0
  13. package/dist/extensions/copy-turn.ts +6 -1
  14. package/dist/extensions/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
  15. package/dist/extensions/package.json +0 -1
  16. package/dist/extensions/pi-subagents/CHANGELOG.md +3 -0
  17. package/dist/extensions/pi-subagents/README.md +27 -32
  18. package/dist/extensions/pi-subagents/agents/architect.md +4 -4
  19. package/dist/extensions/pi-subagents/agents/builder.md +5 -4
  20. package/dist/extensions/pi-subagents/agents/commentator.md +3 -2
  21. package/dist/extensions/pi-subagents/agents/explorer.md +3 -2
  22. package/dist/extensions/pi-subagents/agents/recapper.md +3 -2
  23. package/dist/extensions/pi-subagents/agents/researcher.md +4 -3
  24. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +2 -0
  25. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +10 -9
  26. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +12 -11
  27. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +10 -11
  28. package/dist/extensions/pi-subagents/src/agents/agent-management.ts +56 -9
  29. package/dist/extensions/pi-subagents/src/agents/task-aware-routing.ts +125 -0
  30. package/dist/extensions/pi-subagents/src/api/preflight.ts +1 -1
  31. package/dist/extensions/pi-subagents/src/extension/index.ts +5 -1
  32. package/dist/extensions/pi-subagents/src/extension/schemas.ts +2 -2
  33. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +24 -7
  34. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +23 -5
  35. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +27 -1
  36. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +64 -6
  37. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +16 -1
  38. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +72 -18
  39. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +19 -5
  40. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +127 -31
  41. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +4 -6
  42. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +63 -9
  43. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +21 -0
  44. package/dist/extensions/pi-subagents/src/shared/types.ts +41 -2
  45. package/dist/extensions/pi-subagents/src/shared/utils.ts +29 -1
  46. package/dist/extensions/pi-subagents/src/slash/delegation-adapters.ts +5 -1
  47. package/dist/extensions/pi-subagents/src/tui/render.ts +28 -6
  48. package/dist/extensions/pi-subagents/test/e2e/real-session-subagent.test.ts +111 -6
  49. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +74 -43
  50. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +36 -21
  51. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +5 -3
  52. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +20 -8
  53. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +14 -7
  54. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +81 -5
  55. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +49 -10
  56. package/dist/extensions/pi-subagents/test/support/real-session-runner.ts +18 -2
  57. package/dist/extensions/pi-subagents/test/unit/agent-disabled.test.ts +1 -1
  58. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +70 -6
  59. package/dist/extensions/pi-subagents/test/unit/agent-management.test.ts +161 -1
  60. package/dist/extensions/pi-subagents/test/unit/builtin-agent-documentation.test.ts +63 -0
  61. package/dist/extensions/pi-subagents/test/unit/capability-ceiling-agent-allowlist.test.ts +34 -0
  62. package/dist/extensions/pi-subagents/test/unit/delegation-api.test.ts +24 -0
  63. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +6 -1
  64. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +29 -0
  65. package/dist/extensions/pi-subagents/test/unit/preflight.test.ts +2 -0
  66. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +12 -0
  67. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +91 -1
  68. package/dist/extensions/pi-subagents/test/unit/task-aware-routing.test.ts +213 -0
  69. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +23 -1
  70. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +60 -9
  71. package/dist/skills/ponytail/SKILL.md +1 -3
  72. package/docs/plans/subagent-delegation/phase-0-correctness.md +265 -0
  73. package/docs/plans/subagent-delegation/phase-1-behavioral-contract.md +486 -0
  74. package/docs/plans/subagent-delegation/phase-2-context-controls.md +282 -0
  75. package/docs/plans/subagent-delegation/phase-3-advisory-routing.md +362 -0
  76. package/docs/plans/subagent-delegation/phase-4-optional-enforcement.md +381 -0
  77. package/package.json +2 -2
  78. package/dist/extensions/caveman/caveman-instructions.cjs +0 -11
  79. package/dist/extensions/caveman/index.js +0 -118
  80. package/dist/extensions/caveman/package.json +0 -8
  81. package/dist/extensions/caveman/test/extension.test.js +0 -203
  82. package/dist/extensions/caveman/test/helpers.test.js +0 -58
  83. package/dist/skills/caveman/SKILL.md +0 -50
@@ -80,7 +80,7 @@ interface AsyncResultPayload {
80
80
  totalCost?: { inputTokens: number; outputTokens: number; costUsd: number };
81
81
  usageBudget?: UsageBudgetState;
82
82
  checkpoint?: { name?: string; status?: string };
83
- results: Array<{ agent?: string; launchContractDigest?: string; launchResolvedExtensions?: LaunchResolvedExtensions; runtimeAcknowledgedExtensions?: RuntimeAcknowledgedExtensions; output?: string; outputState?: "present" | "absent" | "unknown"; success?: boolean; error?: string; protocolError?: { code?: string; stream?: string; limitBytes?: number; observedBytes?: number }; timedOut?: boolean; stopped?: boolean; turnBudget?: { maxTurns: number; graceTurns: number; outcome: string; turnCount: number; wrapUpRequestedAtTurn?: number; terminationDeferredAtTurn?: number; exceededAtTurn?: number }; turnBudgetExceeded?: boolean; wrapUpRequested?: boolean; model?: string; attemptedModels?: string[]; modelAttempts?: Array<{ success?: boolean; error?: string }>; totalCost?: { inputTokens: number; outputTokens: number; costUsd: number }; structuredOutput?: unknown; agentContract?: { version: 1 }; execution?: { status?: string; success?: boolean; exitCode?: number }; effects?: { fileMutation?: { status?: string; expected?: boolean; attempted?: boolean } }; intercomTarget?: string; acceptance?: { status?: string; effectiveAcceptance?: { level?: string }; childReport?: unknown; runtimeChecks?: Array<{ id?: string; status?: string; message?: string }> }; artifactPaths?: { outputPath?: string; inputPath?: string; metadataPath?: string }; capabilityCeiling?: { version?: number; allowedTools?: string[]; denyExtensions?: boolean; sources?: string[] }; capabilityAudit?: { effectiveTools?: string[]; removedTools?: string[]; extensionsDenied?: boolean } }>;
83
+ results: Array<{ agent?: string; launchContractDigest?: string; launchResolvedExtensions?: LaunchResolvedExtensions; runtimeAcknowledgedExtensions?: RuntimeAcknowledgedExtensions; output?: string; outputPath?: string; outputState?: "present" | "absent" | "unknown"; success?: boolean; error?: string; protocolError?: { code?: string; stream?: string; limitBytes?: number; observedBytes?: number }; timedOut?: boolean; stopped?: boolean; turnBudget?: { maxTurns: number; graceTurns: number; outcome: string; turnCount: number; wrapUpRequestedAtTurn?: number; terminationDeferredAtTurn?: number; exceededAtTurn?: number }; turnBudgetExceeded?: boolean; wrapUpRequested?: boolean; model?: string; attemptedModels?: string[]; modelAttempts?: Array<{ success?: boolean; error?: string }>; totalCost?: { inputTokens: number; outputTokens: number; costUsd: number }; structuredOutput?: unknown; agentContract?: { version: 1 }; execution?: { status?: string; success?: boolean; exitCode?: number }; effects?: { fileMutation?: { status?: string; expected?: boolean; attempted?: boolean } }; intercomTarget?: string; acceptance?: { status?: string; effectiveAcceptance?: { level?: string }; childReport?: unknown; runtimeChecks?: Array<{ id?: string; status?: string; message?: string }> }; artifactPaths?: { outputPath?: string; inputPath?: string; metadataPath?: string }; capabilityCeiling?: { version?: number; allowedTools?: string[]; denyExtensions?: boolean; sources?: string[] }; capabilityAudit?: { effectiveTools?: string[]; removedTools?: string[]; extensionsDenied?: boolean } }>;
84
84
  outputs?: Record<string, { text?: string; structured?: unknown }>;
85
85
  workflowGraph?: { nodes?: Array<{ kind?: string; label?: string; phase?: string; status?: string; acceptanceStatus?: string; error?: string; outputName?: string; structured?: boolean; children?: Array<{ label?: string; outputName?: string; itemKey?: string; status?: string; acceptanceStatus?: string; error?: string }> }> };
86
86
  parallelHandoff?: { version?: number; path?: string; groupCount?: number; childCount?: number; changedPatches?: number; cleanupState?: string };
@@ -453,6 +453,18 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
453
453
  return JSON.parse(fs.readFileSync(resultPath, "utf-8")) as AsyncResultPayload;
454
454
  }
455
455
 
456
+ /**
457
+ * Reference-first async child assertion: the result payload carries the
458
+ * saved-output reference; the full text is read from the durable output path.
459
+ */
460
+ function assertAsyncChildOutput(payload: AsyncResultPayload, index: number, expected: string): void {
461
+ const child = payload.results[index];
462
+ assert.ok(child, `expected async child ${index}`);
463
+ assert.match(child.output ?? "", /Output saved to: /);
464
+ assert.ok(child.outputPath, `expected a durable output path for child ${index}`);
465
+ assert.equal(fs.readFileSync(child.outputPath, "utf-8"), expected);
466
+ }
467
+
456
468
  function launchProtocolTest(id: string): void {
457
469
  executeAsyncSingle(id, {
458
470
  agent: "worker",
@@ -480,7 +492,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
480
492
  launchProtocolTest(id);
481
493
  const payload = await readAsyncPayload(id);
482
494
  assert.equal(payload.success, true);
483
- assert.equal(payload.results[0]?.output, "你好 from fragmented async JSON");
495
+ assertAsyncChildOutput(payload, 0, "你好 from fragmented async JSON");
484
496
  });
485
497
 
486
498
  it("persists absent output provenance when async lifecycle text is synthetic", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
@@ -500,7 +512,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
500
512
  const payload = await readAsyncPayload(id);
501
513
  assert.equal(payload.success, false);
502
514
  assert.equal(payload.results[0]?.outputState, "present");
503
- assert.equal(payload.results[0]?.output, "usable partial answer");
515
+ assertAsyncChildOutput(payload, 0, "usable partial answer");
504
516
  });
505
517
 
506
518
  it("matches preflight launch digest in equivalent foreground and async execution", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
@@ -512,11 +524,14 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
512
524
  fs.writeFileSync(agentPath, `---\nname: ${agentName}\ndescription: Contract comparison worker\n---\n`, "utf-8");
513
525
  const discovered = discoverAgents(tempDir).agents.find((agent) => agent.name === agentName);
514
526
  assert.ok(discovered, "expected temporary agent definition to be discovered");
515
- const preflight = await resolveSubagentLaunchContract({ agent: agentName, cwd: tempDir, task, turnBudget, runId: "contract-preflight" });
527
+ // Stable explicit output keeps the preflight launch contract equivalent to
528
+ // both execution paths (generated per-run paths would differ by design).
529
+ const contractOutputPath = path.join(tempDir, "contract-output.md");
530
+ const preflight = await resolveSubagentLaunchContract({ agent: agentName, cwd: tempDir, task, turnBudget, runId: "contract-preflight", output: contractOutputPath });
516
531
  assert.equal(preflight.ok, true);
517
532
 
518
533
  mockPi.onCall({ output: "foreground contract comparison" });
519
- const foreground = await runSync(tempDir, [discovered], agentName, task, { runId: "contract-foreground", acceptance: false, turnBudget });
534
+ const foreground = await runSync(tempDir, [discovered], agentName, task, { runId: "contract-foreground", acceptance: false, turnBudget, outputPath: contractOutputPath });
520
535
  assert.equal(foreground.exitCode, 0);
521
536
  assert.equal(foreground.launchContractDigest, preflight.contract.launchContractDigest);
522
537
 
@@ -525,6 +540,8 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
525
540
  const launch = executeAsyncSingle(asyncId, {
526
541
  agent: agentName,
527
542
  task,
543
+ output: contractOutputPath,
544
+ outputMode: "inline",
528
545
  agentConfig: discovered,
529
546
  ctx: { pi: { events: { emit() {} } }, cwd: tempDir, currentSessionId: "session-1" },
530
547
  artifactConfig: { enabled: false, includeInput: false, includeOutput: false, includeJsonl: false, includeMetadata: false, cleanupDays: 7 },
@@ -721,7 +738,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
721
738
 
722
739
  const launch = await executor.execute(
723
740
  "async-session-artifact-dir",
724
- { agent: "worker", task: "Write async session artifacts", async: true, runId: "async-session-artifacts", acceptance: false },
741
+ { agent: "worker", task: "Write async session artifacts", async: true, runId: "async-session-artifacts", acceptance: false, artifacts: true },
725
742
  new AbortController().signal,
726
743
  undefined,
727
744
  ctx,
@@ -829,7 +846,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
829
846
  launchProtocolTest(id);
830
847
  const payload = await readAsyncPayload(id);
831
848
  assert.equal(payload.success, true);
832
- assert.equal(payload.results[0]?.output, "settled async response");
849
+ assertAsyncChildOutput(payload, 0, "settled async response");
833
850
  assert.ok(Date.now() - startedAt >= 1200, "background runner must not terminate during the retry delay");
834
851
  });
835
852
 
@@ -841,7 +858,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
841
858
  const payload = await readAsyncPayload(id);
842
859
  assert.equal(payload.success, true);
843
860
  assert.equal(payload.results[0]?.error, undefined);
844
- assert.equal(payload.results[0]?.output, "settled async without a terminal assistant stop");
861
+ assertAsyncChildOutput(payload, 0, "settled async without a terminal assistant stop");
845
862
  assert.ok(Date.now() - startedAt < 4000, "agent_settled should trigger bounded child cleanup");
846
863
  });
847
864
 
@@ -872,7 +889,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
872
889
  assert.match(call.args.at(-1) ?? "", /\{outputs\.name\}/);
873
890
  const payload = await readAsyncPayload(id);
874
891
  assert.equal(payload.success, true);
875
- assert.equal(payload.results[0]?.output, "OK");
892
+ assertAsyncChildOutput(payload, 0, "OK");
876
893
  });
877
894
 
878
895
  it("spawns the async runner with node when process.execPath is not node", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
@@ -903,7 +920,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
903
920
  const resultPath = await waitForAsyncResultFile(id, 30_000);
904
921
  const payload = JSON.parse(fs.readFileSync(resultPath, "utf-8")) as AsyncResultPayload;
905
922
  assert.equal(payload.success, true);
906
- assert.equal(payload.results[0]?.output, "non-node exec async done");
923
+ assertAsyncChildOutput(payload, 0, "non-node exec async done");
907
924
  } finally {
908
925
  process.execPath = originalExecPath;
909
926
  }
@@ -937,7 +954,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
937
954
  const resultPath = await waitForAsyncResultFile(id, 10_000);
938
955
  const payload = JSON.parse(fs.readFileSync(resultPath, "utf-8")) as AsyncResultPayload;
939
956
  assert.equal(payload.success, true);
940
- assert.equal(payload.results[0]?.output, "stale node exec async done");
957
+ assertAsyncChildOutput(payload, 0, "stale node exec async done");
941
958
  } finally {
942
959
  process.execPath = originalExecPath;
943
960
  }
@@ -1178,8 +1195,11 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
1178
1195
  assert.equal(payload.turnBudget?.turnCount, 2);
1179
1196
  assert.equal(payload.results[0]?.wrapUpRequested, true);
1180
1197
  assert.equal(payload.results[0]?.turnBudget?.turnCount, 2);
1181
- assert.match(payload.results[0]?.output ?? "", /Turn budget wrap-up was requested after 1 assistant turn/);
1182
- assert.match(payload.results[0]?.output ?? "", /final wrapped output/);
1198
+ // Reference-first delivery: the saved-output reference replaces inline prose;
1199
+ // the wrap-up note and raw output stay visible through status/result fields
1200
+ // and the persisted result file.
1201
+ assert.match(payload.results[0]?.output ?? "", /Output saved to: /);
1202
+ assertAsyncChildOutput(payload, 0, "final wrapped output");
1183
1203
  assert.equal(status.wrapUpRequested, true);
1184
1204
  assert.equal(status.turnBudgetExceeded, undefined);
1185
1205
  assert.equal(status.steps?.[0]?.wrapUpRequested, true);
@@ -1218,8 +1238,9 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
1218
1238
  assert.equal(payload.turnBudget?.turnCount, 3);
1219
1239
  assert.equal(payload.turnBudget?.exceededAtTurn, 3);
1220
1240
  assert.equal(payload.results[0]?.turnBudgetExceeded, true);
1221
- assert.match(payload.results[0]?.output ?? "", /Partial output before turn-budget abort:/);
1222
- assert.match(payload.results[0]?.output ?? "", /safe assistant boundary after tool work/);
1241
+ assert.match(payload.error ?? "", /Subagent exceeded turn budget|turn budget/i);
1242
+ assert.match(payload.results[0]?.output ?? "", /Output saved to: /);
1243
+ assertAsyncChildOutput(payload, 0, "safe assistant boundary after tool work");
1223
1244
  assert.equal(status.state, "failed");
1224
1245
  assert.equal(status.turnBudgetExceeded, true);
1225
1246
  assert.equal(status.steps?.[0]?.turnBudgetExceeded, true);
@@ -1272,7 +1293,8 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
1272
1293
  assert.equal(payload.turnBudget?.outcome, "exceeded");
1273
1294
  assert.equal(payload.turnBudget?.turnCount, 2);
1274
1295
  assert.equal(payload.results[0]?.turnBudgetExceeded, true);
1275
- assert.match(payload.results[0]?.output ?? "", /safe assistant boundary reached/);
1296
+ assert.match(payload.results[0]?.output ?? "", /Output saved to: /);
1297
+ assertAsyncChildOutput(payload, 0, "safe assistant boundary reached");
1276
1298
  assert.equal(status.state, "failed");
1277
1299
  assert.equal(status.turnBudgetExceeded, true);
1278
1300
  assert.equal(status.steps?.[0]?.turnBudget?.outcome, "exceeded");
@@ -1564,6 +1586,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
1564
1586
  tasks: [{ agent: "builder", task: "Do async work", output: "async-top-output.md", reads: ["input.md"] }],
1565
1587
  async: true,
1566
1588
  clarify: false,
1589
+ artifacts: true,
1567
1590
  },
1568
1591
  new AbortController().signal,
1569
1592
  undefined,
@@ -1622,7 +1645,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
1622
1645
  ];
1623
1646
  const launch = await executor.execute(
1624
1647
  `async-inherited-output-${outputOverride === true ? "true" : "omitted"}`,
1625
- { tasks, async: true, clarify: false },
1648
+ { tasks, async: true, clarify: false, artifacts: true },
1626
1649
  new AbortController().signal,
1627
1650
  undefined,
1628
1651
  makeMinimalCtx(tempDir),
@@ -1631,8 +1654,8 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
1631
1654
  assert.equal(launch.isError, undefined);
1632
1655
  const payload = await readAsyncPayload(launch.details?.asyncId as string);
1633
1656
  assert.equal(payload.success, true);
1634
- assert.equal(payload.results[0]?.output?.split("\n\nOutput saved to:")[0], "first async report");
1635
- assert.equal(payload.results[1]?.output?.split("\n\nOutput saved to:")[0], "second async report");
1657
+ assertAsyncChildOutput(payload, 0, "first async report");
1658
+ assertAsyncChildOutput(payload, 1, "second async report");
1636
1659
  const outputDir = path.join(tempDir, ".pi-subagents", "artifacts", "outputs", launch.details?.asyncId as string);
1637
1660
  const authoritativePaths = [
1638
1661
  path.join(outputDir, "parallel-0", "0-worker", "context.md"),
@@ -1694,6 +1717,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
1694
1717
  ],
1695
1718
  async: true,
1696
1719
  clarify: false,
1720
+ artifacts: true,
1697
1721
  },
1698
1722
  new AbortController().signal,
1699
1723
  undefined,
@@ -1932,13 +1956,13 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
1932
1956
  const payload = JSON.parse(fs.readFileSync(resultPath, "utf-8")) as AsyncResultPayload;
1933
1957
  const status = JSON.parse(fs.readFileSync(path.join(ASYNC_DIR, id, "status.json"), "utf-8")) as AsyncStatusPayload;
1934
1958
  assert.equal(payload.success, true);
1935
- assert.deepEqual(payload.results.map((entry) => entry.output), [
1936
- "Scout A async findings",
1937
- "Scout B async findings",
1938
- "Async funnel synthesis",
1939
- "Async reviewer A done",
1940
- "Async reviewer B done",
1941
- ]);
1959
+ // Reference-first chain delivery: every child result carries the saved-output
1960
+ // reference; full text is read from each durable output path.
1961
+ assertAsyncChildOutput(payload, 0, "Scout A async findings");
1962
+ assertAsyncChildOutput(payload, 1, "Scout B async findings");
1963
+ assertAsyncChildOutput(payload, 2, "Async funnel synthesis");
1964
+ assertAsyncChildOutput(payload, 3, "Async reviewer A done");
1965
+ assertAsyncChildOutput(payload, 4, "Async reviewer B done");
1942
1966
  assert.deepEqual(status.steps?.map((step) => step.status), ["complete", "complete", "complete", "complete", "complete"]);
1943
1967
  assert.deepEqual(status.parallelGroups, [
1944
1968
  { start: 0, count: 2, stepIndex: 0 },
@@ -1946,11 +1970,14 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
1946
1970
  ]);
1947
1971
  const funnelTask = readMockPiArgsMatching(mockPi, "Synthesize:").at(-1) ?? "";
1948
1972
  assert.match(funnelTask, /=== Parallel Task 1 \(scout-a\) ===/);
1949
- assert.match(funnelTask, /Scout A async findings/);
1950
1973
  assert.match(funnelTask, /=== Parallel Task 2 \(scout-b\) ===/);
1951
- assert.match(funnelTask, /Scout B async findings/);
1952
- assert.match(readMockPiArgsMatching(mockPi, "Review funnel A:").at(-1) ?? "", /Review funnel A:\nAsync funnel synthesis/);
1953
- assert.match(readMockPiArgsMatching(mockPi, "Review funnel B:").at(-1) ?? "", /Review funnel B:\nAsync funnel synthesis/);
1974
+ // Chain handoff stays reference-first: the funnel consumes the saved-output
1975
+ // references and reads the named paths instead of re-inlined child prose.
1976
+ assert.match(funnelTask, /Output saved to: /);
1977
+ assert.doesNotMatch(funnelTask, /Scout A async findings/);
1978
+ assert.doesNotMatch(funnelTask, /Scout B async findings/);
1979
+ assert.match(readMockPiArgsMatching(mockPi, "Review funnel A:").at(-1) ?? "", /Review funnel A:\nOutput saved to: /);
1980
+ assert.match(readMockPiArgsMatching(mockPi, "Review funnel B:").at(-1) ?? "", /Review funnel B:\nOutput saved to: /);
1954
1981
  assert.equal(payload.workflowGraph?.nodes?.[0]?.kind, "parallel-group");
1955
1982
  assert.equal(payload.workflowGraph?.nodes?.[0]?.status, "completed");
1956
1983
  assert.equal(payload.workflowGraph?.nodes?.[1]?.kind, "step");
@@ -2341,7 +2368,10 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
2341
2368
  const expectedConsumerTarget = `subagent-consumer-${id}-4`;
2342
2369
  assert.equal(payload.success, true);
2343
2370
  assert.equal(payload.results[3]?.intercomTarget, expectedConsumerTarget);
2344
- assert.deepEqual(JSON.parse(payload.results[3]?.output ?? "{}"), { SELESAI_SUBAGENT_INTERCOM_SESSION_NAME: expectedConsumerTarget });
2371
+ const consumerChild = payload.results[3];
2372
+ assert.ok(consumerChild?.outputPath, "expected a durable output path for the consumer child");
2373
+ assert.match(consumerChild.output ?? "", /Output saved to: /);
2374
+ assert.deepEqual(JSON.parse(fs.readFileSync(consumerChild.outputPath, "utf-8")), { SELESAI_SUBAGENT_INTERCOM_SESSION_NAME: expectedConsumerTarget });
2345
2375
  });
2346
2376
 
2347
2377
  it("async dynamic pre-spawn failures persist failed graph status and error", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
@@ -2428,6 +2458,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
2428
2458
  async: true,
2429
2459
  clarify: false,
2430
2460
  worktree: true,
2461
+ artifacts: true,
2431
2462
  },
2432
2463
  new AbortController().signal,
2433
2464
  undefined,
@@ -2632,7 +2663,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
2632
2663
  assert.equal(payload.results[0]?.model, "openai/gpt-5-mini:high");
2633
2664
  assert.deepEqual(payload.results[0]?.attemptedModels, ["openai/gpt-5-mini:high"]);
2634
2665
  assert.deepEqual(payload.results[0]?.modelAttempts?.map((attempt) => attempt.success), [false, true]);
2635
- assert.match(payload.results[0]?.output ?? "", /\[startup-retry\].*Recovered asynchronously after startup race/s);
2666
+ assertAsyncChildOutput(payload, 0, "Recovered asynchronously after startup race");
2636
2667
  assert.equal(mockPi.callCount(), 2);
2637
2668
  });
2638
2669
 
@@ -2679,7 +2710,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
2679
2710
  const payload = JSON.parse(fs.readFileSync(await waitForAsyncResultFile(id), "utf-8"));
2680
2711
  assert.equal(payload.success, true);
2681
2712
  assert.deepEqual(payload.results[0].attemptedModels, ["openai/gpt-5-mini:high", "anthropic/claude-sonnet-4:low"]);
2682
- assert.match(payload.results[0].output ?? "", /Recovered after stream failure/);
2713
+ assertAsyncChildOutput(payload, 0, "Recovered after stream failure");
2683
2714
  assert.equal(mockPi.callCount(), 2);
2684
2715
  });
2685
2716
 
@@ -2820,7 +2851,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
2820
2851
  const payload = JSON.parse(fs.readFileSync(resultPath, "utf-8")) as AsyncResultPayload;
2821
2852
  assert.equal(payload.success, true);
2822
2853
  assert.equal(payload.results[0]?.model, "anthropic/claude-sonnet-4");
2823
- assert.match(payload.results[0]?.output ?? "", /Recovered asynchronously from empty output/);
2854
+ assertAsyncChildOutput(payload, 0, "Recovered asynchronously from empty output");
2824
2855
  assert.match(payload.results[0]?.modelAttempts?.[0]?.error ?? "", /no output/i);
2825
2856
  assert.deepEqual(payload.results[0]?.modelAttempts?.map((attempt) => attempt.success), [false, true]);
2826
2857
  assert.equal(mockPi.callCount(), 2);
@@ -2960,7 +2991,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
2960
2991
  assert.equal(payload.exitCode, 0);
2961
2992
  assert.equal(payload.results[0]?.success, true);
2962
2993
  assert.equal(payload.results[0]?.error, undefined);
2963
- assert.equal(payload.results[0]?.output, "Recovered asynchronously");
2994
+ assertAsyncChildOutput(payload, 0, "Recovered asynchronously");
2964
2995
  const statusPayload = JSON.parse(fs.readFileSync(path.join(asyncDir, "status.json"), "utf-8")) as AsyncStatusPayload;
2965
2996
  assert.equal(statusPayload.state, "complete");
2966
2997
  assert.equal(statusPayload.steps?.[0]?.status, "complete");
@@ -3364,7 +3395,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
3364
3395
  assert.equal(payload.success, true);
3365
3396
  assert.equal(payload.exitCode, 0);
3366
3397
  assert.equal(payload.results[0].success, true);
3367
- assert.equal(payload.results[0].output, "cold start test after patch");
3398
+ assertAsyncChildOutput(payload, 0, "cold start test after patch");
3368
3399
 
3369
3400
  const eventsPath = path.join(ASYNC_DIR, id, "events.jsonl");
3370
3401
  const eventsText = fs.readFileSync(eventsPath, "utf-8");
@@ -4070,7 +4101,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
4070
4101
  const payload = JSON.parse(fs.readFileSync(resultPath, "utf-8")) as AsyncResultPayload;
4071
4102
  assert.ok(elapsed < 6000, `unconfigured watchdog status should not delay async final drain, took ${elapsed}ms`);
4072
4103
  assert.equal(payload.success, true);
4073
- assert.equal(payload.results[0]?.output, "async-done-without-watchdog-config");
4104
+ assertAsyncChildOutput(payload, 0, "async-done-without-watchdog-config");
4074
4105
  assert.equal((payload.results[0] as { watchdog?: unknown }).watchdog, undefined);
4075
4106
  });
4076
4107
  });
@@ -4105,7 +4136,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
4105
4136
  assert.ok(elapsed >= 1200, `watchdog settlement should delay async final drain, took ${elapsed}ms`);
4106
4137
  assert.ok(elapsed < 9000, `settled watchdog should still allow async cleanup, took ${elapsed}ms`);
4107
4138
  assert.equal(payload.success, true);
4108
- assert.equal(payload.results[0]?.output, "async-done-before-watchdog");
4139
+ assertAsyncChildOutput(payload, 0, "async-done-before-watchdog");
4109
4140
  assert.equal((payload.results[0] as { watchdog?: { phase?: string } }).watchdog?.phase, "idle");
4110
4141
  });
4111
4142
  });
@@ -4136,7 +4167,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
4136
4167
  const payload = JSON.parse(fs.readFileSync(resultPath, "utf-8")) as AsyncResultPayload;
4137
4168
  assert.ok(elapsed < 6000, `watchdog tail fallback should not hang async final drain, took ${elapsed}ms`);
4138
4169
  assert.equal(payload.success, true);
4139
- assert.equal(payload.results[0]?.output, "async-done-before-watchdog-timeout");
4170
+ assertAsyncChildOutput(payload, 0, "async-done-before-watchdog-timeout");
4140
4171
  const watchdog = (payload.results[0] as { watchdog?: { phase?: string; timedOut?: boolean } }).watchdog;
4141
4172
  assert.equal(watchdog?.phase, "stale");
4142
4173
  assert.equal(watchdog?.timedOut, true);
@@ -4187,7 +4218,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
4187
4218
  assert.equal(payload.success, true);
4188
4219
  assert.equal(payload.exitCode, 0);
4189
4220
  assert.equal(payload.results[0].success, true);
4190
- assert.equal(payload.results[0].output, "async-done-before-drain");
4221
+ assertAsyncChildOutput(payload, 0, "async-done-before-drain");
4191
4222
  });
4192
4223
 
4193
4224
  it("background forced drain after empty terminal assistant output is cleanup success", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
@@ -4223,7 +4254,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
4223
4254
  assert.equal(payload.success, true);
4224
4255
  assert.equal(payload.exitCode, 0);
4225
4256
  assert.equal(payload.results[0].success, true);
4226
- assert.equal(payload.results[0].output, "");
4257
+ assert.match(payload.results[0].output ?? "", /Output saved to: /);
4227
4258
  });
4228
4259
 
4229
4260
  it("background final-drain cleanup preserves explicit assistant errors", { skip: !isAsyncAvailable() ? "jiti not available" : undefined }, async () => {
@@ -4596,7 +4627,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
4596
4627
  const resultPath = await waitForAsyncResultFile(id, 10_000);
4597
4628
  const payload = JSON.parse(fs.readFileSync(resultPath, "utf-8")) as AsyncResultPayload;
4598
4629
  assert.equal(payload.success, true);
4599
- assert.equal(payload.results[0]?.output, "Done after noisy stream");
4630
+ assertAsyncChildOutput(payload, 0, "Done after noisy stream");
4600
4631
 
4601
4632
  const eventsText = fs.readFileSync(path.join(asyncDir, "events.jsonl"), "utf-8");
4602
4633
  assert.doesNotMatch(eventsText, /"type":"message_update"/);
@@ -4675,7 +4706,7 @@ describe("async execution utilities", { skip: !available ? "pi packages not avai
4675
4706
 
4676
4707
  const payload = JSON.parse(fs.readFileSync(resultPath, "utf-8"));
4677
4708
  assert.equal(payload.success, true);
4678
- assert.equal(payload.results[0].output, "Done streaming");
4709
+ assertAsyncChildOutput(payload, 0, "Done streaming");
4679
4710
 
4680
4711
  const status = JSON.parse(fs.readFileSync(path.join(asyncDir, "status.json"), "utf-8"));
4681
4712
  assert.deepEqual(status.steps[0].recentTools.map((tool: { tool: string; args: string }) => ({ tool: tool.tool, args: tool.args })), [{ tool: "bash", args: "ls" }]);
@@ -367,8 +367,9 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
367
367
  assert.doesNotMatch(firstTaskArg, /\[Write to:|Write your findings to exactly this path/);
368
368
  assert.ok(result.details.results[0]?.savedOutputPath);
369
369
  assert.equal(fs.readFileSync(result.details.results[0].savedOutputPath, "utf-8"), "full chain output\nwith details");
370
- assert.match(result.details.results[0]?.finalOutput ?? "", /Output saved to:/);
371
- assert.doesNotMatch(result.details.results[0]?.finalOutput ?? "", /full chain output/);
370
+ assert.equal(result.details.results[0]?.finalOutput, undefined);
371
+ assert.match(result.details.results[0]?.outputReference?.message ?? "", /Output saved to:/);
372
+ assert.doesNotMatch(result.details.results[0]?.outputReference?.message ?? "", /full chain output/);
372
373
  const secondTaskArg = readCallArgs(1).at(-1) ?? "";
373
374
  assert.match(secondTaskArg, /Output saved to:/);
374
375
  assert.match(secondTaskArg, /2 lines/);
@@ -404,7 +405,8 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
404
405
  );
405
406
 
406
407
  assert.ok(!result.isError, `chain should succeed: ${JSON.stringify(result.content)}`);
407
- assert.match(result.details.results[0]?.finalOutput ?? "", /Output saved to:/);
408
+ assert.equal(result.details.results[0]?.finalOutput, undefined);
409
+ assert.match(result.details.results[0]?.outputReference?.message ?? "", /Output saved to:/);
408
410
  assert.equal(result.details.results[0]?.acceptance?.status, "checked");
409
411
  assert.ok(result.details.results[0]?.acceptance?.childReport);
410
412
 
@@ -630,10 +632,13 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
630
632
 
631
633
  assert.ok(!result.isError);
632
634
  const step2Task = result.details.results[1].task;
635
+ // Reference-first handoff: {previous} carries the saved-output reference and
636
+ // the step reads the named path instead of re-inlined prose.
633
637
  assert.ok(
634
- step2Task.includes("MARKER_ABC_123"),
635
- `step 2 task should contain step 1 output via {previous}: ${step2Task.slice(0, 200)}`,
638
+ step2Task.includes("Output saved to:"),
639
+ `step 2 task should contain the saved-output reference via {previous}: ${step2Task.slice(0, 200)}`,
636
640
  );
641
+ assert.doesNotMatch(step2Task, /MARKER_ABC_123/);
637
642
  });
638
643
 
639
644
  it("passes named sequential outputs through {outputs.name}", async () => {
@@ -652,7 +657,8 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
652
657
  );
653
658
 
654
659
  assert.ok(!result.isError);
655
- assert.match(readCallArgs(1).at(-1) ?? "", /CTX_123/);
660
+ assert.match(readCallArgs(1).at(-1) ?? "", /Output saved to: /);
661
+ assert.doesNotMatch(readCallArgs(1).at(-1) ?? "", /CTX_123/);
656
662
  assert.equal(result.details.workflowGraph?.nodes[0]?.outputName, "contextOutput");
657
663
  });
658
664
 
@@ -692,9 +698,10 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
692
698
  assert.match(readCallArgs(1).at(-1) ?? "", /Review src\/a\.ts/);
693
699
  assert.match(readCallArgs(2).at(-1) ?? "", /Review src\/b\.ts/);
694
700
  assert.match(readCallArgs(3).at(-1) ?? "", /"key":"src\/a\.ts"/);
695
- const collected = result.details.outputs?.reviews?.structured as Array<{ key: string; structured: unknown }>;
696
- assert.deepEqual(collected.map((item) => item.key), ["src/a.ts", "src/b.ts"]);
697
- assert.deepEqual(collected.map((item) => item.structured), [{ ok: "a" }, { ok: "b" }]);
701
+ // Terminal details strip chain outputs text/structured; bindings remain
702
+ // reference-first via {outputs.name} and the workflow graph keeps item keys.
703
+ assert.equal(result.details.outputs?.reviews?.text, "");
704
+ assert.equal(result.details.outputs?.reviews?.structured, undefined);
698
705
  const dynamicNode = result.details.workflowGraph?.nodes[1];
699
706
  assert.equal(dynamicNode?.kind, "dynamic-parallel-group");
700
707
  assert.deepEqual(dynamicNode?.children?.map((child) => child.itemKey), ["src/a.ts", "src/b.ts"]);
@@ -868,7 +875,7 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
868
875
  { agent: "scout", task: "Return targets", as: "targets", outputSchema: { type: "object" } },
869
876
  {
870
877
  expand: { from: { output: "targets", path: "/items" }, key: "/path", maxItems: 4 },
871
- parallel: { agent: "reviewer", task: "Review {item.path}", outputMode: "file-only" },
878
+ parallel: { agent: "reviewer", task: "Review {item.path}", output: false, outputMode: "file-only" },
872
879
  collect: { as: "reviews" },
873
880
  },
874
881
  ],
@@ -906,7 +913,8 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
906
913
 
907
914
  assert.ok(!result.isError, `chain should succeed: ${JSON.stringify(result.content)}`);
908
915
  assert.equal(mockPi.callCount(), 2);
909
- assert.deepEqual(result.details.outputs?.reviews?.structured, []);
916
+ assert.equal(result.details.outputs?.reviews?.text, "");
917
+ assert.equal(result.details.outputs?.reviews?.structured, undefined);
910
918
  assert.equal(result.details.workflowGraph?.nodes[1]?.status, "completed");
911
919
  assert.deepEqual(result.details.workflowGraph?.nodes[1]?.children, []);
912
920
  });
@@ -1123,7 +1131,9 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
1123
1131
  assert.equal(result.details.results.length, 2);
1124
1132
  assert.equal(result.details.results[0]?.acceptance?.status, "rejected");
1125
1133
  assert.equal(result.details.results[0]?.exitCode, 0);
1126
- assert.match(result.details.results[1]?.finalOutput ?? "", /Step 2 ran/);
1134
+ assert.equal(result.details.results[1]?.finalOutput, undefined);
1135
+ assert.ok(result.details.results[1]?.savedOutputPath);
1136
+ assert.equal(fs.readFileSync(result.details.results[1]!.savedOutputPath!, "utf-8"), "Step 2 ran");
1127
1137
  });
1128
1138
 
1129
1139
  it("agent contract v1 chain can gate progression on acceptance", async () => {
@@ -1195,7 +1205,8 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
1195
1205
  );
1196
1206
 
1197
1207
  const finalTaskArg = readCallArgs(chainLength - 1).at(-1) ?? "";
1198
- assert.match(finalTaskArg, /step-38-output/);
1208
+ assert.match(finalTaskArg, /Output saved to: /);
1209
+ assert.doesNotMatch(finalTaskArg, /step-38-output/);
1199
1210
  assert.doesNotMatch(finalTaskArg, /step-37-output/);
1200
1211
  assert.match(result.content[0]?.text ?? "", /40 steps/);
1201
1212
  });
@@ -1284,7 +1295,9 @@ describe("chain execution — sequential", { skip: !available ? "pi packages not
1284
1295
  );
1285
1296
 
1286
1297
  assert.ok(!result.isError);
1287
- assert.deepEqual(JSON.parse(result.details.results[0].finalOutput ?? "{}"), {
1298
+ const depthChild = result.details.results[0];
1299
+ assert.ok(depthChild.savedOutputPath);
1300
+ assert.deepEqual(JSON.parse(fs.readFileSync(depthChild.savedOutputPath, "utf-8")), {
1288
1301
  SELESAI_SUBAGENT_DEPTH: "1",
1289
1302
  SELESAI_SUBAGENT_MAX_DEPTH: "1",
1290
1303
  });
@@ -1474,8 +1487,9 @@ describe("chain execution — parallel steps", { skip: !available ? "pi packages
1474
1487
 
1475
1488
  assert.ok(!result.isError);
1476
1489
  const finalTask = readCallArgs(2).at(-1) ?? "";
1477
- assert.match(finalTask, /Alpha named output/);
1478
- assert.match(finalTask, /Beta named output/);
1490
+ assert.match(finalTask, /Output saved to: /);
1491
+ assert.doesNotMatch(finalTask, /Alpha named output/);
1492
+ assert.doesNotMatch(finalTask, /Beta named output/);
1479
1493
  });
1480
1494
 
1481
1495
  it("funnels an initial parallel step through one agent, then fans the funnel output back out", async () => {
@@ -1512,13 +1526,14 @@ describe("chain execution — parallel steps", { skip: !available ? "pi packages
1512
1526
  assert.equal(result.details.totalSteps, 3);
1513
1527
  const funnelTask = readCallArgsMatching("Synthesize:").at(-1) ?? "";
1514
1528
  assert.match(funnelTask, /=== Parallel Task 1 \(scout-a\) ===/);
1515
- assert.match(funnelTask, /Scout A findings/);
1516
1529
  assert.match(funnelTask, /=== Parallel Task 2 \(scout-b\) ===/);
1517
- assert.match(funnelTask, /Scout B findings/);
1530
+ assert.match(funnelTask, /Output saved to: /);
1531
+ assert.doesNotMatch(funnelTask, /Scout A findings/);
1532
+ assert.doesNotMatch(funnelTask, /Scout B findings/);
1518
1533
  const fanoutTaskA = readCallArgsMatching("Review funnel A:").at(-1) ?? "";
1519
1534
  const fanoutTaskB = readCallArgsMatching("Review funnel B:").at(-1) ?? "";
1520
- assert.match(fanoutTaskA, /Review funnel A:\nFunnel synthesis/);
1521
- assert.match(fanoutTaskB, /Review funnel B:\nFunnel synthesis/);
1535
+ assert.match(fanoutTaskA, /Review funnel A:\nOutput saved to: /);
1536
+ assert.match(fanoutTaskB, /Review funnel B:\nOutput saved to: /);
1522
1537
  assert.equal(result.details.workflowGraph?.nodes[0]?.kind, "parallel-group");
1523
1538
  assert.equal(result.details.workflowGraph?.nodes[1]?.kind, "step");
1524
1539
  assert.equal(result.details.workflowGraph?.nodes[2]?.kind, "parallel-group");
@@ -1560,7 +1575,7 @@ describe("chain execution — parallel steps", { skip: !available ? "pi packages
1560
1575
  makeChainParams(
1561
1576
  [{
1562
1577
  parallel: [
1563
- { agent: "reviewer-a", task: "Review A", outputMode: "file-only" },
1578
+ { agent: "reviewer-a", task: "Review A", output: false, outputMode: "file-only" },
1564
1579
  { agent: "reviewer-b", task: "Review B", output: "b.md" },
1565
1580
  ],
1566
1581
  }],
@@ -310,7 +310,8 @@ describe("fork context execution wiring", { skip: !available ? "subagent executo
310
310
 
311
311
  assert.equal(result.isError, undefined);
312
312
  const args = readCallArgs();
313
- assert.ok((args.at(-1) ?? "").startsWith("Task: \n\n## Acceptance Contract"));
313
+ assert.ok((args.at(-1) ?? "").startsWith("Task: \n\n---\n**Output:**"));
314
+ assert.match(args.at(-1) ?? "", /## Acceptance Contract/);
314
315
  });
315
316
 
316
317
  it("does not treat top-level agent as single mode when tasks are present", async () => {
@@ -327,7 +328,8 @@ describe("fork context execution wiring", { skip: !available ? "subagent executo
327
328
 
328
329
  assert.equal(result.isError, undefined);
329
330
  const args = readCallArgs();
330
- assert.ok((args.at(-1) ?? "").startsWith("Task: parallel task\n\n## Acceptance Contract"));
331
+ assert.ok((args.at(-1) ?? "").startsWith("Task: parallel task\n\n---\n**Output:**"));
332
+ assert.match(args.at(-1) ?? "", /## Acceptance Contract/);
331
333
  });
332
334
 
333
335
  it("uses agent defaultContext fork when launch context is omitted", async () => {
@@ -1827,7 +1829,7 @@ describe("fork context execution wiring", { skip: !available ? "subagent executo
1827
1829
  );
1828
1830
 
1829
1831
  assert.equal(result.isError, undefined);
1830
- const args = readAllCallArgs().find((callArgs) => (callArgs.at(-1) ?? "").startsWith(`Task: ${task}\n\n## Acceptance Contract`));
1832
+ const args = readAllCallArgs().find((callArgs) => (callArgs.at(-1) ?? "").startsWith(`Task: ${task}\n\n---\n**Output:**`));
1831
1833
  assert.ok(args, "expected a recorded mock pi call for this test task");
1832
1834
  const modelIndex = args.indexOf("--model");
1833
1835
  assert.notEqual(modelIndex, -1);
@@ -227,10 +227,13 @@ describe("intercom result delivery cutover", { skip: !available ? "executor not
227
227
  assert.match(result.content[0]?.text ?? "", /Delivered single subagent result via intercom\./);
228
228
  assert.doesNotMatch(result.content[0]?.text ?? "", /Full child output from worker/);
229
229
  assert.equal(result.details?.results?.[0]?.finalOutput, undefined);
230
- assert.match(String(payload.message ?? ""), /Full child output from worker/);
230
+ // Reference-first intercom delivery: the child summary is the saved-output
231
+ // reference (error/status first for failed children), never raw child prose.
232
+ assert.match(String(payload.message ?? ""), /Output saved to: /);
233
+ assert.doesNotMatch(String(payload.message ?? ""), /Full child output from worker/);
231
234
  });
232
235
 
233
- it("falls back to legacy foreground output when the bridge is inactive", async () => {
236
+ it("returns the native saved-output receipt when the bridge is inactive", async () => {
234
237
  mockPi.onCall({ output: "Legacy foreground output" });
235
238
  const { executor, events } = makeExecutor({ bridgeMode: "off" });
236
239
 
@@ -243,10 +246,14 @@ describe("intercom result delivery cutover", { skip: !available ? "executor not
243
246
  );
244
247
 
245
248
  assert.equal(events.emitted.some((entry) => entry.channel === "subagent:result-intercom"), false);
246
- assert.match(result.content[0]?.text ?? "", /Legacy foreground output/);
249
+ assert.match(result.content[0]?.text ?? "", /Output saved to: /);
250
+ assert.doesNotMatch(result.content[0]?.text ?? "", /Legacy foreground output/);
251
+ const runId = result.details?.runId;
252
+ assert.ok(runId);
253
+ assert.equal(fs.readFileSync(path.join(tempDir, ".pi-subagents", "artifacts", "outputs", runId, "result.md"), "utf-8"), "Legacy foreground output");
247
254
  });
248
255
 
249
- it("keeps native foreground output without attempting external grouped delivery when disabled", async () => {
256
+ it("keeps the native saved-output receipt without attempting external grouped delivery when disabled", async () => {
250
257
  mockPi.onCall({ output: "Native foreground output" });
251
258
  const { executor, events } = makeExecutor({ resultDelivery: false });
252
259
 
@@ -259,10 +266,11 @@ describe("intercom result delivery cutover", { skip: !available ? "executor not
259
266
  );
260
267
 
261
268
  assert.equal(events.emitted.some((entry) => entry.channel === "subagent:result-intercom"), false);
262
- assert.match(result.content[0]?.text ?? "", /Native foreground output/);
269
+ assert.match(result.content[0]?.text ?? "", /Output saved to: /);
270
+ assert.doesNotMatch(result.content[0]?.text ?? "", /Native foreground output/);
263
271
  });
264
272
 
265
- it("falls back to legacy foreground output when grouped delivery is not acknowledged", async () => {
273
+ it("falls back to the compact native saved-output receipt when grouped delivery is not acknowledged", async () => {
266
274
  mockPi.onCall({ output: "Unacknowledged foreground output" });
267
275
  const { executor, events } = makeExecutor({ acknowledgeResults: false });
268
276
 
@@ -275,7 +283,8 @@ describe("intercom result delivery cutover", { skip: !available ? "executor not
275
283
  );
276
284
 
277
285
  assert.equal(events.emitted.some((entry) => entry.channel === "subagent:result-intercom"), true);
278
- assert.match(result.content[0]?.text ?? "", /Unacknowledged foreground output/);
286
+ assert.match(result.content[0]?.text ?? "", /Output saved to: /);
287
+ assert.doesNotMatch(result.content[0]?.text ?? "", /Unacknowledged foreground output/);
279
288
  });
280
289
 
281
290
  it("top-level parallel runs emit one grouped event containing all children", async () => {
@@ -1250,7 +1259,10 @@ describe("intercom result delivery cutover", { skip: !available ? "executor not
1250
1259
  const payload = completion.payload as { success?: boolean; summary?: string };
1251
1260
  assert.equal(payload.success, false);
1252
1261
  assert.match(payload.summary ?? "", /Acceptance rejected/);
1253
- assert.match(payload.summary ?? "", /final answer with rejected acceptance evidence/);
1262
+ // Reference-first foreground completion: the recovery summary carries the
1263
+ // saved-output reference (with error/status), never raw child prose.
1264
+ assert.match(payload.summary ?? "", /Output saved to: /);
1265
+ assert.doesNotMatch(payload.summary ?? "", /final answer with rejected acceptance evidence/);
1254
1266
 
1255
1267
  const status = await executor.execute(
1256
1268
  "foreground-detached-failed-status",