pi-subagents 0.77.0 → 0.79.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.
Files changed (263) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/agents/evidence-auditor.md +1 -0
  3. package/agents/oracle.md +1 -0
  4. package/agents/reviewer.md +1 -0
  5. package/docs/agents.md +4 -2
  6. package/docs/configuration.md +22 -6
  7. package/docs/extension-api.md +9 -1
  8. package/docs/observability.md +11 -3
  9. package/docs/tool-reference.md +14 -3
  10. package/docs/workflows.md +6 -4
  11. package/package.json +1 -1
  12. package/skills/pi-subagents/SKILL.md +2 -1
  13. package/skills/pi-subagents/references/execution-controls.md +2 -0
  14. package/skills/pi-subagents/references/multi-lane-orchestration.md +1 -1
  15. package/src/api/external-runs.d.ts.map +1 -1
  16. package/src/api/external-runs.js +5 -4
  17. package/src/api/external-runs.js.map +1 -1
  18. package/src/api/preflight.js +1 -1
  19. package/src/api/preflight.js.map +1 -1
  20. package/src/extension/active-runs-prompt.d.ts +8 -0
  21. package/src/extension/active-runs-prompt.d.ts.map +1 -0
  22. package/src/extension/active-runs-prompt.js +30 -0
  23. package/src/extension/active-runs-prompt.js.map +1 -0
  24. package/src/extension/config.d.ts.map +1 -1
  25. package/src/extension/config.js +6 -0
  26. package/src/extension/config.js.map +1 -1
  27. package/src/extension/declaration-pinning.d.ts +5 -0
  28. package/src/extension/declaration-pinning.d.ts.map +1 -1
  29. package/src/extension/declaration-pinning.js +24 -3
  30. package/src/extension/declaration-pinning.js.map +1 -1
  31. package/src/extension/index.d.ts +0 -1
  32. package/src/extension/index.d.ts.map +1 -1
  33. package/src/extension/index.js +73 -18
  34. package/src/extension/index.js.map +1 -1
  35. package/src/extension/public-execution.d.ts +1 -0
  36. package/src/extension/public-execution.d.ts.map +1 -1
  37. package/src/extension/public-execution.js +3 -0
  38. package/src/extension/public-execution.js.map +1 -1
  39. package/src/extension/rpc.d.ts.map +1 -1
  40. package/src/extension/rpc.js +5 -3
  41. package/src/extension/rpc.js.map +1 -1
  42. package/src/extension/schemas.d.ts +2 -0
  43. package/src/extension/schemas.d.ts.map +1 -1
  44. package/src/extension/schemas.js +1 -0
  45. package/src/extension/schemas.js.map +1 -1
  46. package/src/extension/tool-activation.d.ts.map +1 -1
  47. package/src/extension/tool-activation.js +25 -6
  48. package/src/extension/tool-activation.js.map +1 -1
  49. package/src/intercom/native-supervisor-channel.d.ts +18 -2
  50. package/src/intercom/native-supervisor-channel.d.ts.map +1 -1
  51. package/src/intercom/native-supervisor-channel.js +130 -15
  52. package/src/intercom/native-supervisor-channel.js.map +1 -1
  53. package/src/runs/background/active-async-capacity.d.ts +2 -1
  54. package/src/runs/background/active-async-capacity.d.ts.map +1 -1
  55. package/src/runs/background/active-async-capacity.js +10 -6
  56. package/src/runs/background/active-async-capacity.js.map +1 -1
  57. package/src/runs/background/async-execution.js +3 -3
  58. package/src/runs/background/async-execution.js.map +1 -1
  59. package/src/runs/background/async-resume.d.ts.map +1 -1
  60. package/src/runs/background/async-resume.js +5 -2
  61. package/src/runs/background/async-resume.js.map +1 -1
  62. package/src/runs/background/async-status-snapshot.d.ts.map +1 -1
  63. package/src/runs/background/async-status-snapshot.js +4 -2
  64. package/src/runs/background/async-status-snapshot.js.map +1 -1
  65. package/src/runs/background/async-status.d.ts.map +1 -1
  66. package/src/runs/background/async-status.js +10 -6
  67. package/src/runs/background/async-status.js.map +1 -1
  68. package/src/runs/background/chain-root-attachment.js +4 -4
  69. package/src/runs/background/chain-root-attachment.js.map +1 -1
  70. package/src/runs/background/control-channel.d.ts +1 -0
  71. package/src/runs/background/control-channel.d.ts.map +1 -1
  72. package/src/runs/background/control-channel.js +27 -3
  73. package/src/runs/background/control-channel.js.map +1 -1
  74. package/src/runs/background/inspect-rpc.d.ts +5 -0
  75. package/src/runs/background/inspect-rpc.d.ts.map +1 -1
  76. package/src/runs/background/inspect-rpc.js +20 -3
  77. package/src/runs/background/inspect-rpc.js.map +1 -1
  78. package/src/runs/background/notify.d.ts +1 -1
  79. package/src/runs/background/notify.d.ts.map +1 -1
  80. package/src/runs/background/notify.js +8 -4
  81. package/src/runs/background/notify.js.map +1 -1
  82. package/src/runs/background/result-delivery-ownership.d.ts +0 -2
  83. package/src/runs/background/result-delivery-ownership.d.ts.map +1 -1
  84. package/src/runs/background/result-delivery-ownership.js +5 -21
  85. package/src/runs/background/result-delivery-ownership.js.map +1 -1
  86. package/src/runs/background/result-files.d.ts +5 -3
  87. package/src/runs/background/result-files.d.ts.map +1 -1
  88. package/src/runs/background/result-files.js +10 -6
  89. package/src/runs/background/result-files.js.map +1 -1
  90. package/src/runs/background/result-watcher.d.ts.map +1 -1
  91. package/src/runs/background/result-watcher.js +15 -8
  92. package/src/runs/background/result-watcher.js.map +1 -1
  93. package/src/runs/background/resume-guidance.d.ts.map +1 -1
  94. package/src/runs/background/resume-guidance.js +3 -2
  95. package/src/runs/background/resume-guidance.js.map +1 -1
  96. package/src/runs/background/run-child-session.d.ts.map +1 -1
  97. package/src/runs/background/run-child-session.js +13 -17
  98. package/src/runs/background/run-child-session.js.map +1 -1
  99. package/src/runs/background/run-status.d.ts.map +1 -1
  100. package/src/runs/background/run-status.js +11 -4
  101. package/src/runs/background/run-status.js.map +1 -1
  102. package/src/runs/background/runner-aliases.d.ts.map +1 -1
  103. package/src/runs/background/runner-aliases.js +11 -8
  104. package/src/runs/background/runner-aliases.js.map +1 -1
  105. package/src/runs/background/subagent-runner.d.ts.map +1 -1
  106. package/src/runs/background/subagent-runner.js +212 -283
  107. package/src/runs/background/subagent-runner.js.map +1 -1
  108. package/src/runs/background/workflow-terminal-proof.d.ts +1 -1
  109. package/src/runs/background/workflow-terminal-proof.d.ts.map +1 -1
  110. package/src/runs/background/workflow-terminal-proof.js +12 -3
  111. package/src/runs/background/workflow-terminal-proof.js.map +1 -1
  112. package/src/runs/foreground/async-dismiss-action.d.ts.map +1 -1
  113. package/src/runs/foreground/async-dismiss-action.js +2 -1
  114. package/src/runs/foreground/async-dismiss-action.js.map +1 -1
  115. package/src/runs/foreground/async-steering-action.d.ts.map +1 -1
  116. package/src/runs/foreground/async-steering-action.js +3 -2
  117. package/src/runs/foreground/async-steering-action.js.map +1 -1
  118. package/src/runs/foreground/async-stop-action.d.ts +1 -0
  119. package/src/runs/foreground/async-stop-action.d.ts.map +1 -1
  120. package/src/runs/foreground/async-stop-action.js +9 -8
  121. package/src/runs/foreground/async-stop-action.js.map +1 -1
  122. package/src/runs/foreground/command-action.d.ts.map +1 -1
  123. package/src/runs/foreground/command-action.js +2 -1
  124. package/src/runs/foreground/command-action.js.map +1 -1
  125. package/src/runs/foreground/execution.d.ts.map +1 -1
  126. package/src/runs/foreground/execution.js +67 -60
  127. package/src/runs/foreground/execution.js.map +1 -1
  128. package/src/runs/foreground/subagent-executor.d.ts +2 -0
  129. package/src/runs/foreground/subagent-executor.d.ts.map +1 -1
  130. package/src/runs/foreground/subagent-executor.js +124 -67
  131. package/src/runs/foreground/subagent-executor.js.map +1 -1
  132. package/src/runs/shared/async-status-projection.d.ts +4 -0
  133. package/src/runs/shared/async-status-projection.d.ts.map +1 -1
  134. package/src/runs/shared/async-status-projection.js +23 -1
  135. package/src/runs/shared/async-status-projection.js.map +1 -1
  136. package/src/runs/shared/child-commands.d.ts +2 -0
  137. package/src/runs/shared/child-commands.d.ts.map +1 -1
  138. package/src/runs/shared/child-commands.js +4 -0
  139. package/src/runs/shared/child-commands.js.map +1 -1
  140. package/src/runs/shared/child-runtime-config.d.ts +6 -0
  141. package/src/runs/shared/child-runtime-config.d.ts.map +1 -1
  142. package/src/runs/shared/child-runtime-config.js +6 -0
  143. package/src/runs/shared/child-runtime-config.js.map +1 -1
  144. package/src/runs/shared/child-session.d.ts +2 -2
  145. package/src/runs/shared/child-session.d.ts.map +1 -1
  146. package/src/runs/shared/child-session.js +104 -42
  147. package/src/runs/shared/child-session.js.map +1 -1
  148. package/src/runs/shared/effective-system-prompt.d.ts +4 -4
  149. package/src/runs/shared/effective-system-prompt.d.ts.map +1 -1
  150. package/src/runs/shared/effective-system-prompt.js +5 -4
  151. package/src/runs/shared/effective-system-prompt.js.map +1 -1
  152. package/src/runs/shared/external-cli-runner.d.ts.map +1 -1
  153. package/src/runs/shared/external-cli-runner.js +3 -2
  154. package/src/runs/shared/external-cli-runner.js.map +1 -1
  155. package/src/runs/shared/long-running-guard.d.ts +3 -1
  156. package/src/runs/shared/long-running-guard.d.ts.map +1 -1
  157. package/src/runs/shared/long-running-guard.js +4 -14
  158. package/src/runs/shared/long-running-guard.js.map +1 -1
  159. package/src/runs/shared/model-resolution-diagnostic.d.ts +7 -5
  160. package/src/runs/shared/model-resolution-diagnostic.d.ts.map +1 -1
  161. package/src/runs/shared/model-resolution-diagnostic.js +13 -10
  162. package/src/runs/shared/model-resolution-diagnostic.js.map +1 -1
  163. package/src/runs/shared/model-resolution.d.ts +5 -1
  164. package/src/runs/shared/model-resolution.d.ts.map +1 -1
  165. package/src/runs/shared/model-resolution.js +8 -1
  166. package/src/runs/shared/model-resolution.js.map +1 -1
  167. package/src/runs/shared/nested-events.d.ts.map +1 -1
  168. package/src/runs/shared/nested-events.js +2 -0
  169. package/src/runs/shared/nested-events.js.map +1 -1
  170. package/src/runs/shared/orca-progress-tabs.js +1 -1
  171. package/src/runs/shared/orca-progress-tabs.js.map +1 -1
  172. package/src/runs/shared/partial-output.d.ts +7 -0
  173. package/src/runs/shared/partial-output.d.ts.map +1 -1
  174. package/src/runs/shared/partial-output.js +7 -0
  175. package/src/runs/shared/partial-output.js.map +1 -1
  176. package/src/runs/shared/run-ownership.d.ts +4 -0
  177. package/src/runs/shared/run-ownership.d.ts.map +1 -0
  178. package/src/runs/shared/run-ownership.js +9 -0
  179. package/src/runs/shared/run-ownership.js.map +1 -0
  180. package/src/runs/shared/single-output.d.ts +11 -1
  181. package/src/runs/shared/single-output.d.ts.map +1 -1
  182. package/src/runs/shared/single-output.js +48 -26
  183. package/src/runs/shared/single-output.js.map +1 -1
  184. package/src/runs/shared/structured-output.d.ts +2 -0
  185. package/src/runs/shared/structured-output.d.ts.map +1 -1
  186. package/src/runs/shared/structured-output.js +9 -0
  187. package/src/runs/shared/structured-output.js.map +1 -1
  188. package/src/runs/shared/subagent-control.d.ts +1 -0
  189. package/src/runs/shared/subagent-control.d.ts.map +1 -1
  190. package/src/runs/shared/subagent-control.js +2 -1
  191. package/src/runs/shared/subagent-control.js.map +1 -1
  192. package/src/runs/shared/subagent-prompt-runtime.d.ts +56 -0
  193. package/src/runs/shared/subagent-prompt-runtime.d.ts.map +1 -1
  194. package/src/runs/shared/subagent-prompt-runtime.js +192 -6
  195. package/src/runs/shared/subagent-prompt-runtime.js.map +1 -1
  196. package/src/runs/shared/tool-budget.js +1 -1
  197. package/src/runs/shared/tool-budget.js.map +1 -1
  198. package/src/shared/child-transcript.js +1 -1
  199. package/src/shared/child-transcript.js.map +1 -1
  200. package/src/shared/extension-context.d.ts +5 -0
  201. package/src/shared/extension-context.d.ts.map +1 -1
  202. package/src/shared/extension-context.js +7 -0
  203. package/src/shared/extension-context.js.map +1 -1
  204. package/src/shared/file-lease.d.ts +7 -1
  205. package/src/shared/file-lease.d.ts.map +1 -1
  206. package/src/shared/file-lease.js +8 -2
  207. package/src/shared/file-lease.js.map +1 -1
  208. package/src/shared/fork-context.d.ts +3 -1
  209. package/src/shared/fork-context.d.ts.map +1 -1
  210. package/src/shared/fork-context.js +23 -13
  211. package/src/shared/fork-context.js.map +1 -1
  212. package/src/shared/parent-wake.d.ts +6 -0
  213. package/src/shared/parent-wake.d.ts.map +1 -1
  214. package/src/shared/parent-wake.js +11 -0
  215. package/src/shared/parent-wake.js.map +1 -1
  216. package/src/shared/session-succession.d.ts +5 -0
  217. package/src/shared/session-succession.d.ts.map +1 -0
  218. package/src/shared/session-succession.js +25 -0
  219. package/src/shared/session-succession.js.map +1 -0
  220. package/src/shared/types.d.ts +22 -9
  221. package/src/shared/types.d.ts.map +1 -1
  222. package/src/shared/types.js +7 -4
  223. package/src/shared/types.js.map +1 -1
  224. package/src/shared/utils.d.ts +13 -0
  225. package/src/shared/utils.d.ts.map +1 -1
  226. package/src/shared/utils.js +19 -0
  227. package/src/shared/utils.js.map +1 -1
  228. package/src/slash/slash-commands.d.ts.map +1 -1
  229. package/src/slash/slash-commands.js +22 -11
  230. package/src/slash/slash-commands.js.map +1 -1
  231. package/src/slash/subagents-admin.d.ts.map +1 -1
  232. package/src/slash/subagents-admin.js +3 -2
  233. package/src/slash/subagents-admin.js.map +1 -1
  234. package/src/tui/fleet-status.d.ts +5 -0
  235. package/src/tui/fleet-status.d.ts.map +1 -1
  236. package/src/tui/fleet-status.js +24 -3
  237. package/src/tui/fleet-status.js.map +1 -1
  238. package/src/tui/fleet.js +2 -2
  239. package/src/tui/fleet.js.map +1 -1
  240. package/src/watchdog/change-signature.d.ts.map +1 -1
  241. package/src/watchdog/change-signature.js +1 -3
  242. package/src/watchdog/change-signature.js.map +1 -1
  243. package/src/watchdog/register-main.js +2 -2
  244. package/src/watchdog/register-main.js.map +1 -1
  245. package/src/watchdog/runtime.d.ts.map +1 -1
  246. package/src/watchdog/runtime.js +3 -5
  247. package/src/watchdog/runtime.js.map +1 -1
  248. package/src/workflows/scripted-workflow.d.ts +1 -1
  249. package/src/workflows/scripted-workflow.d.ts.map +1 -1
  250. package/src/workflows/scripted-workflow.js +13 -4
  251. package/src/workflows/scripted-workflow.js.map +1 -1
  252. package/src/workflows/workflow-child-summary.d.ts +5 -0
  253. package/src/workflows/workflow-child-summary.d.ts.map +1 -1
  254. package/src/workflows/workflow-child-summary.js +10 -0
  255. package/src/workflows/workflow-child-summary.js.map +1 -1
  256. package/src/workflows/workflow-reuse.d.ts +6 -1
  257. package/src/workflows/workflow-reuse.d.ts.map +1 -1
  258. package/src/workflows/workflow-reuse.js +22 -1
  259. package/src/workflows/workflow-reuse.js.map +1 -1
  260. package/src/runs/shared/run-history.d.ts +0 -67
  261. package/src/runs/shared/run-history.d.ts.map +0 -1
  262. package/src/runs/shared/run-history.js +0 -270
  263. package/src/runs/shared/run-history.js.map +0 -1
@@ -10,7 +10,7 @@ import { ensureArtifactsDir, formatOutputArtifactContent, getArtifactPaths, writ
10
10
  import { createChildTranscriptWriter } from "../../shared/child-transcript.js";
11
11
  import { DEFAULT_MAX_OUTPUT, INTERCOM_DETACH_REQUEST_EVENT, INTERCOM_DETACH_RESPONSE_EVENT, truncateOutput, } from "../../shared/types.js";
12
12
  import { DEFAULT_CONTROL_CONFIG, buildControlEvent, claimControlNotification, deriveActivityState, shouldEmitOpenToolAttention, shouldNotifyControlEvent, } from "../shared/subagent-control.js";
13
- import { getFinalOutput, findLatestSessionFile, detectSubagentError, hasEmptyTerminalAssistantResponse, formatEmptyTerminalAssistantResponseError, extractToolArgsPreview, extractTextFromContent, MAX_STREAMED_RECENT_TOOLS, boundStreamedRecentTools, boundStreamedRecentOutput, boundStreamedToolCalls, } from "../../shared/utils.js";
13
+ import { getFinalOutput, findLatestSessionFile, detectSubagentError, hasEmptyTerminalAssistantResponse, formatEmptyTerminalAssistantResponseError, extractToolArgsPreview, assistantMessageError, extractTextFromContent, MAX_STREAMED_RECENT_TOOLS, boundStreamedRecentTools, boundStreamedRecentOutput, boundStreamedToolCalls, } from "../../shared/utils.js";
14
14
  import { resolveSkillsWithFallback } from "../../agents/skills.js";
15
15
  import { createPartialOutputTracker, formatPartialOutput } from "../shared/partial-output.js";
16
16
  import { effectiveToolTimeoutMs, formatToolTimeoutMessage, resolveToolTimeoutMs, toolTimeoutCallKey, toolTimeoutFromEnv } from "../shared/tool-timeout.js";
@@ -18,7 +18,8 @@ import { preflightLaunchCwd } from "../shared/launch-cwd.js";
18
18
  import { createJsonlWriter } from "../../shared/jsonl-writer.js";
19
19
  import { createOrcaProgressTab } from "../shared/orca-progress-tabs.js";
20
20
  import { resolvePermissionRules } from "../shared/permissions.js";
21
- import { applyThinkingSuffix, deriveForkPromptCacheKey } from "../shared/child-tool-plan.js";
21
+ import { applyThinkingSuffix, deriveForkPromptCacheKey, supervisorChannelDir } from "../shared/child-tool-plan.js";
22
+ import { retainsChildCommand } from "../shared/child-commands.js";
22
23
  import { deriveChildSessionName } from "../../shared/child-session-name.js";
23
24
  import { assertAgentAllowedByCapabilityCeiling, intersectSubagentCapabilityCeilings, resolveCurrentSubagentCapabilityCeiling } from "../shared/capability-ceiling.js";
24
25
  import { qualifyModelWithProvider, resolveEffectiveThinking } from "../../shared/model-info.js";
@@ -29,7 +30,7 @@ import { formatChildToolDiagnostic } from "../shared/tool-availability.js";
29
30
  import { formatChildModelResolutionDiagnostic, formatInheritedProviderDiagnostic, isChildModelResolutionFailure } from "../shared/model-resolution-diagnostic.js";
30
31
  import { planAbortRecovery } from "../shared/abort-recovery.js";
31
32
  import { buildTimeoutRecoverySummary, collectTrackedMutationEvidence, snapshotTrackedMutations } from "../shared/mutation-evidence.js";
32
- import { captureSingleOutputSnapshot, extractChildWrittenOutput, finalizeSingleOutput, formatSavedOutputReference, hasSingleOutputChangedSinceSnapshot, resolveSingleOutput, validateFileOnlyOutputMode } from "../shared/single-output.js";
33
+ import { captureSingleOutputSnapshot, extractChildWrittenOutput, finalizeSingleOutput, formatSavedOutputReference, hasSingleOutputChangedSinceSnapshot, isSettlementFatalOutputError, resolveSingleOutput, validateFileOnlyOutputMode } from "../shared/single-output.js";
33
34
  import { formatSubagentModelVerificationError, isContextOverflow, resolveModelSelection, } from "../shared/model-resolution.js";
34
35
  import { createMutatingFailureState, didMutatingToolFail, isMutatingTool, nextLongRunningTrigger, recordMutatingFailure, resetMutatingFailureState, resolveCurrentPath, shouldEscalateMutatingFailures, summarizeRecentMutatingFailures, } from "../shared/long-running-guard.js";
35
36
  import { acceptanceFailureMessage, buildSkippedAcceptanceLedger, captureStagedIndexBaseline, evaluateAcceptance, formatAcceptancePrompt, resolveEffectiveAcceptance, stripAcceptanceReport, validateAcceptanceInput, typedVerifyOutput } from "../shared/acceptance.js";
@@ -485,8 +486,12 @@ async function runSingleAttempt(runtimeCwd, agent, task, model, options, shared)
485
486
  timeoutHardFinishTimer = undefined;
486
487
  }
487
488
  };
489
+ const startup = new AbortController();
488
490
  const abortChild = () => {
489
- if (!session || sessionSettled || lifecycleFinished)
491
+ if (sessionSettled || lifecycleFinished)
492
+ return;
493
+ startup.abort();
494
+ if (!session)
490
495
  return;
491
496
  void session.abort().catch(() => {
492
497
  // The session settles through its prompt promise; abort failures are not separately actionable.
@@ -707,6 +712,9 @@ async function runSingleAttempt(runtimeCwd, agent, task, model, options, shared)
707
712
  return events;
708
713
  };
709
714
  let activeLongRunningNotified = false;
715
+ // Pi's parallel tool execution emits every tool_execution_start before the first result message,
716
+ // so results are matched to their call by toolCallId; the last-started slot covers events without one.
717
+ const pendingToolResultsByCallId = new Map();
710
718
  let pendingToolResult;
711
719
  let activeToolSequence = 0;
712
720
  const activeToolCalls = new Map();
@@ -792,6 +800,7 @@ async function runSingleAttempt(runtimeCwd, agent, task, model, options, shared)
792
800
  toolCount: progress.toolCount,
793
801
  currentTool: input.currentTool ?? progress.currentTool,
794
802
  toolCallId: input.toolCallId,
803
+ hasCommandController: input.hasCommandController,
795
804
  currentToolDurationMs: input.currentToolDurationMs ?? currentToolDurationMs(now),
796
805
  currentPath: input.currentPath ?? progress.currentPath,
797
806
  recentFailureSummary: input.recentFailureSummary,
@@ -846,11 +855,13 @@ async function runSingleAttempt(runtimeCwd, agent, task, model, options, shared)
846
855
  if (toolAttentionTarget) {
847
856
  toolAttentionTarget.attentionEmitted = true;
848
857
  const durationMs = Math.max(0, now - toolAttentionTarget.startedAt);
858
+ const toolCallId = toolAttentionTarget.key.startsWith("id:") ? toolAttentionTarget.key.slice(3) : undefined;
849
859
  return emitNeedsAttention(now, {
850
860
  message: `${agent.name} has had tool '${toolAttentionTarget.tool}' open for ${Math.floor(durationMs / 1000)}s`,
851
861
  reason: "tool_open_threshold",
852
862
  currentTool: toolAttentionTarget.tool,
853
- toolCallId: toolAttentionTarget.key.startsWith("id:") ? toolAttentionTarget.key.slice(3) : undefined,
863
+ toolCallId,
864
+ hasCommandController: Boolean(toolCallId && retainsChildCommand(supervisorChannelDir(options.runId, agent.name, options.index ?? 0), toolCallId)),
854
865
  currentPath: toolAttentionTarget.path,
855
866
  currentToolDurationMs: durationMs,
856
867
  });
@@ -980,10 +991,12 @@ async function runSingleAttempt(runtimeCwd, agent, task, model, options, shared)
980
991
  }
981
992
  progress.toolCount++;
982
993
  if (options.toolBudget) {
983
- result.toolBudget = toolBudgetState(options.toolBudget, progress.toolCount);
994
+ result.toolBudget = toolBudgetState(options.toolBudget, progress.toolCount, result.toolBudget?.blockedTool);
984
995
  }
985
996
  const mutates = isMutatingTool(evt.toolName, toolArgs, agent.mutationTools);
986
997
  pendingToolResult = { tool: evt.toolName ?? "tool", path: activeTool?.path, mutates, startedAt: now };
998
+ if (typeof evt.toolCallId === "string" && evt.toolCallId)
999
+ pendingToolResultsByCallId.set(evt.toolCallId, pendingToolResult);
987
1000
  fireUpdate();
988
1001
  }
989
1002
  if (evt.type === "tool_execution_end") {
@@ -1043,7 +1056,7 @@ async function runSingleAttempt(runtimeCwd, agent, task, model, options, shared)
1043
1056
  }
1044
1057
  }
1045
1058
  if (evt.message.errorMessage)
1046
- assistantError = evt.message.errorMessage;
1059
+ assistantError = assistantMessageError(evt.message);
1047
1060
  else if (hasToolCall && evt.message.stopReason === "toolUse") {
1048
1061
  // A recovered request can finish via a terminating tool, without a text stop.
1049
1062
  assistantError = undefined;
@@ -1062,59 +1075,50 @@ async function runSingleAttempt(runtimeCwd, agent, task, model, options, shared)
1062
1075
  applyChildLifecycle(projectChildLifecycle(evt, true, childLifecycleState));
1063
1076
  }
1064
1077
  }
1065
- updateActivityState(now);
1066
- fireUpdate();
1067
- }
1068
- if (evt.type === "tool_result_end" && evt.message) {
1069
- const toolResultCompletion = {
1070
- toolCallId: evt.message.toolCallId ?? evt.toolCallId,
1071
- toolName: evt.message.toolName ?? evt.toolName,
1072
- };
1073
- clearActiveToolTimeout(toolResultCompletion);
1074
- const endedTool = removeActiveToolCall(toolResultCompletion);
1075
- if (endedTool) {
1076
- progress.recentTools.push({
1077
- tool: endedTool.tool,
1078
- args: endedTool.args,
1079
- endMs: now,
1080
- });
1081
- refreshCurrentTool();
1082
- }
1083
- result.messages.push(evt.message);
1084
- const resultText = extractTextFromContent(evt.message.content);
1085
- // The result event's own tool name is authoritative; the single pending slot can
1086
- // describe a different, overlapping call and serves only as a fallback.
1087
- const blockedTool = (typeof toolResultCompletion.toolName === "string" && toolResultCompletion.toolName.length > 0
1088
- ? toolResultCompletion.toolName
1089
- : undefined) ?? pendingToolResult?.tool;
1090
- if (options.toolBudget && isToolBudgetBlockedMessage(options.toolBudget, resultText, blockedTool)) {
1091
- result.toolBudgetBlocked = true;
1092
- result.toolBudget = toolBudgetState(options.toolBudget, Math.max(progress.toolCount, options.toolBudget.hard + 1), blockedTool);
1093
- }
1094
- appendRecentOutput(progress, resultText.split("\n").slice(-10));
1095
- const toolSnapshot = pendingToolResult;
1096
- pendingToolResult = undefined;
1097
- if (toolSnapshot?.mutates && didMutatingToolFail(resultText)) {
1098
- recordMutatingFailure(mutatingFailures, {
1099
- tool: toolSnapshot.tool,
1100
- path: toolSnapshot.path,
1101
- error: resultText.split("\n").find((line) => line.trim())?.trim().slice(0, 180) ?? "mutating tool failed",
1102
- ts: now,
1103
- }, mutatingFailureWindowMs);
1104
- if (shouldEscalateMutatingFailures(mutatingFailures, controlConfig.failedToolAttemptsBeforeAttention)) {
1105
- emitNeedsAttention(now, {
1106
- message: `${agent.name} needs attention after repeated mutating tool failures`,
1107
- reason: "tool_failures",
1108
- currentTool: toolSnapshot.tool,
1109
- currentPath: toolSnapshot.path,
1110
- currentToolDurationMs: toolSnapshot.startedAt ? Math.max(0, now - toolSnapshot.startedAt) : undefined,
1111
- recentFailureSummary: summarizeRecentMutatingFailures(mutatingFailures),
1112
- });
1078
+ // Pi delivers every tool result, including a call blocked by a tool_call handler, as a
1079
+ // toolResult message after tool_execution_end; it emits no separate result event.
1080
+ if (evt.message.role === "toolResult") {
1081
+ const resultText = extractTextFromContent(evt.message.content);
1082
+ const resultCallId = evt.message.toolCallId;
1083
+ const keyedSnapshot = typeof resultCallId === "string" ? pendingToolResultsByCallId.get(resultCallId) : undefined;
1084
+ if (keyedSnapshot)
1085
+ pendingToolResultsByCallId.delete(resultCallId);
1086
+ const toolSnapshot = keyedSnapshot ?? pendingToolResult;
1087
+ if (!keyedSnapshot || pendingToolResult === keyedSnapshot)
1088
+ pendingToolResult = undefined;
1089
+ // The result message's own tool name is authoritative; the pending snapshot is only a fallback.
1090
+ const resultToolName = evt.message.toolName;
1091
+ const blockedTool = (typeof resultToolName === "string" && resultToolName.length > 0 ? resultToolName : undefined) ?? toolSnapshot?.tool;
1092
+ const budgetBlocked = Boolean(options.toolBudget && isToolBudgetBlockedMessage(options.toolBudget, resultText, blockedTool));
1093
+ if (options.toolBudget && budgetBlocked) {
1094
+ result.toolBudgetBlocked = true;
1095
+ result.toolBudget = toolBudgetState(options.toolBudget, Math.max(progress.toolCount, options.toolBudget.hard + 1), blockedTool);
1096
+ }
1097
+ appendRecentOutput(progress, resultText.split("\n").slice(-10));
1098
+ // A budget block has its own signal; it is not a failing mutation.
1099
+ if (toolSnapshot?.mutates && !budgetBlocked && didMutatingToolFail(evt.message)) {
1100
+ recordMutatingFailure(mutatingFailures, {
1101
+ tool: toolSnapshot.tool,
1102
+ path: toolSnapshot.path,
1103
+ error: resultText.split("\n").find((line) => line.trim())?.trim().slice(0, 180) ?? "mutating tool failed",
1104
+ ts: now,
1105
+ }, mutatingFailureWindowMs);
1106
+ if (shouldEscalateMutatingFailures(mutatingFailures, controlConfig.failedToolAttemptsBeforeAttention)) {
1107
+ emitNeedsAttention(now, {
1108
+ message: `${agent.name} needs attention after repeated mutating tool failures`,
1109
+ reason: "tool_failures",
1110
+ currentTool: toolSnapshot.tool,
1111
+ currentPath: toolSnapshot.path,
1112
+ currentToolDurationMs: toolSnapshot.startedAt ? Math.max(0, now - toolSnapshot.startedAt) : undefined,
1113
+ recentFailureSummary: summarizeRecentMutatingFailures(mutatingFailures),
1114
+ });
1115
+ }
1116
+ }
1117
+ else if (toolSnapshot?.mutates) {
1118
+ resetMutatingFailureState(mutatingFailures);
1113
1119
  }
1114
1120
  }
1115
- else if (toolSnapshot?.mutates) {
1116
- resetMutatingFailureState(mutatingFailures);
1117
- }
1121
+ updateActivityState(now);
1118
1122
  fireUpdate();
1119
1123
  }
1120
1124
  };
@@ -1354,6 +1358,7 @@ async function runSingleAttempt(runtimeCwd, agent, task, model, options, shared)
1354
1358
  void (async () => {
1355
1359
  try {
1356
1360
  const input = createReportedChildSessionInput(launch, shared.transcriptWriter);
1361
+ input.signal = startup.signal;
1357
1362
  const created = await childSessions.create(input);
1358
1363
  if (lifecycleFinished) {
1359
1364
  void created.dispose();
@@ -1541,9 +1546,11 @@ async function runSingleAttempt(runtimeCwd, agent, task, model, options, shared)
1541
1546
  fullOutput = stripAcceptanceReport(resolvedOutput.fullOutput);
1542
1547
  result.savedOutputPath = resolvedOutput.savedPath;
1543
1548
  result.outputSaveError = resolvedOutput.saveError;
1544
- if (resolvedOutput.fatalError) {
1549
+ if (isSettlementFatalOutputError(resolvedOutput, options.outputMode)) {
1545
1550
  result.exitCode = 1;
1546
1551
  result.error = result.error ? `${result.error}\n${resolvedOutput.saveError}` : resolvedOutput.saveError;
1552
+ progress.status = "failed";
1553
+ progress.error = result.error;
1547
1554
  }
1548
1555
  if (resolvedOutput.savedPath) {
1549
1556
  result.outputReference = formatSavedOutputReference(resolvedOutput.savedPath, fullOutput);
@@ -1721,7 +1728,7 @@ async function runSyncCompletionInner(runtimeCwd, agents, agentName, task, optio
1721
1728
  error: "Skills not found: pi-subagents",
1722
1729
  }, options.context));
1723
1730
  }
1724
- const systemPrompt = buildEffectiveSystemPrompt({ agent, resolvedSkills, cwd: skillCwd, ...(options.outputPath ? { outputPath: options.outputPath } : {}) });
1731
+ const systemPrompt = buildEffectiveSystemPrompt({ agent, resolvedSkills, cwd: skillCwd });
1725
1732
  const { model: selectedModel, requestedModel } = resolveModelSelection(options.modelOverride ?? agent.model, options.availableModels, agent.modelProvider ?? options.preferredModelProvider, {
1726
1733
  scope: options.modelScope,
1727
1734
  primaryModelFromParent: options.modelOverrideFromParent,