@bastani/atomic 0.9.12 → 0.9.13-alpha.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 (264) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/builtin/intercom/CHANGELOG.md +6 -0
  3. package/dist/builtin/intercom/README.md +5 -12
  4. package/dist/builtin/intercom/broker/client.ts +11 -2
  5. package/dist/builtin/intercom/contact-supervisor-tool.ts +13 -3
  6. package/dist/builtin/intercom/index-heavy.ts +13 -3
  7. package/dist/builtin/intercom/index.ts +43 -19
  8. package/dist/builtin/intercom/intercom-utils.ts +15 -29
  9. package/dist/builtin/intercom/package.json +1 -1
  10. package/dist/builtin/intercom/source-ownership.ts +9 -12
  11. package/dist/builtin/mcp/CHANGELOG.md +6 -0
  12. package/dist/builtin/mcp/README.md +3 -1
  13. package/dist/builtin/mcp/index.ts +10 -16
  14. package/dist/builtin/mcp/package.json +1 -1
  15. package/dist/builtin/mcp/startup-warmup.ts +20 -8
  16. package/dist/builtin/subagents/CHANGELOG.md +30 -0
  17. package/dist/builtin/subagents/README.md +22 -30
  18. package/dist/builtin/subagents/package.json +1 -1
  19. package/dist/builtin/subagents/src/extension/doctor.ts +1 -1
  20. package/dist/builtin/subagents/src/extension/fanout-child.ts +76 -56
  21. package/dist/builtin/subagents/src/extension/index.ts +23 -32
  22. package/dist/builtin/subagents/src/extension/startup-maintenance.ts +25 -44
  23. package/dist/builtin/subagents/src/intercom/result-intercom.ts +7 -7
  24. package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +166 -434
  25. package/dist/builtin/subagents/src/runs/background/notify.ts +29 -8
  26. package/dist/builtin/subagents/src/runs/foreground/chain-execution-dynamic-step.ts +2 -2
  27. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-runner.ts +4 -4
  28. package/dist/builtin/subagents/src/runs/foreground/chain-execution-parallel-step.ts +2 -2
  29. package/dist/builtin/subagents/src/runs/foreground/chain-execution-sequential-step.ts +2 -2
  30. package/dist/builtin/subagents/src/runs/foreground/execution-run-sync.ts +1 -281
  31. package/dist/builtin/subagents/src/runs/foreground/execution-structured-retries.ts +11 -75
  32. package/dist/builtin/subagents/src/runs/foreground/inprocess-run-sync.ts +457 -0
  33. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +119 -246
  34. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-chain.ts +1 -1
  35. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-context.ts +18 -9
  36. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +1 -1
  37. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel.ts +4 -4
  38. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-resume.ts +1 -646
  39. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-runtime.ts +2 -7
  40. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +5 -5
  41. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-status.ts +7 -8
  42. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-types.ts +14 -5
  43. package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +158 -93
  44. package/dist/builtin/subagents/src/runs/inprocess/background-single.ts +179 -0
  45. package/dist/builtin/subagents/src/runs/inprocess/background.ts +89 -0
  46. package/dist/builtin/subagents/src/runs/inprocess/child-policy.ts +27 -0
  47. package/dist/builtin/subagents/src/runs/inprocess/control-registry.ts +55 -0
  48. package/dist/builtin/subagents/src/runs/inprocess/control-status.ts +106 -0
  49. package/dist/builtin/subagents/src/runs/inprocess/index.ts +50 -0
  50. package/dist/builtin/subagents/src/runs/inprocess/nested-routing.ts +218 -0
  51. package/dist/builtin/subagents/src/runs/{shared/subagent-prompt-runtime.ts → inprocess/prompt-behavior.ts} +37 -75
  52. package/dist/builtin/subagents/src/runs/inprocess/runner.ts +1138 -0
  53. package/dist/builtin/subagents/src/runs/{shared/nested-events.ts → inprocess/runtime-support/nested-api.ts} +13 -7
  54. package/dist/builtin/subagents/src/runs/{shared/nested-events-control.ts → inprocess/runtime-support/nested-control.ts} +18 -17
  55. package/dist/builtin/subagents/src/runs/{shared/nested-events-core.ts → inprocess/runtime-support/nested-core.ts} +14 -61
  56. package/dist/builtin/subagents/src/runs/{shared/nested-events-projection.ts → inprocess/runtime-support/nested-projection.ts} +4 -10
  57. package/dist/builtin/subagents/src/runs/{shared/nested-events-registry.ts → inprocess/runtime-support/nested-registry.ts} +19 -4
  58. package/dist/builtin/subagents/src/runs/{shared/nested-render.ts → inprocess/runtime-support/nested-rendering.ts} +3 -3
  59. package/dist/builtin/subagents/src/runs/{shared/nested-events-sanitize.ts → inprocess/runtime-support/nested-sanitize.ts} +3 -3
  60. package/dist/builtin/subagents/src/runs/inprocess.ts +1 -0
  61. package/dist/builtin/subagents/src/runs/shared/dynamic-fanout.ts +10 -4
  62. package/dist/builtin/subagents/src/runs/shared/model-candidate-filter.ts +0 -1
  63. package/dist/builtin/subagents/src/runs/shared/model-fallback.ts +15 -492
  64. package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +13 -11
  65. package/dist/builtin/subagents/src/runs/shared/run-history.ts +3 -5
  66. package/dist/builtin/subagents/src/runs/shared/single-output.ts +4 -4
  67. package/dist/builtin/subagents/src/runs/shared/workflow-graph.ts +5 -5
  68. package/dist/builtin/subagents/src/shared/types-async.ts +0 -1
  69. package/dist/builtin/subagents/src/shared/types-config.ts +18 -0
  70. package/dist/builtin/subagents/src/shared/types-results.ts +9 -2
  71. package/dist/builtin/subagents/src/slash/prompt-template-bridge.ts +2 -3
  72. package/dist/builtin/subagents/src/slash/slash-live-state.ts +2 -2
  73. package/dist/builtin/subagents/src/tui/render-chain-graph.ts +10 -4
  74. package/dist/builtin/subagents/src/tui/render-event-formatting.ts +12 -11
  75. package/dist/builtin/subagents/src/tui/render-result-compact.ts +49 -12
  76. package/dist/builtin/subagents/src/tui/render-result.ts +46 -17
  77. package/dist/builtin/subagents/src/tui/render-stable-output.ts +1 -1
  78. package/dist/builtin/subagents/src/tui/render-status-progress.ts +8 -5
  79. package/dist/builtin/subagents/src/tui/render-widget-graph.ts +0 -8
  80. package/dist/builtin/subagents/src/tui/render-widget.ts +0 -24
  81. package/dist/builtin/web-access/package.json +1 -1
  82. package/dist/builtin/workflows/CHANGELOG.md +25 -0
  83. package/dist/builtin/workflows/README.md +13 -3
  84. package/dist/builtin/workflows/package.json +1 -1
  85. package/dist/builtin/workflows/src/durable/backend.ts +7 -0
  86. package/dist/builtin/workflows/src/durable/dbos-metadata.ts +11 -1
  87. package/dist/builtin/workflows/src/durable/resume-runtime.ts +1 -0
  88. package/dist/builtin/workflows/src/durable/tool-primitive.ts +4 -28
  89. package/dist/builtin/workflows/src/durable/types.ts +5 -0
  90. package/dist/builtin/workflows/src/engine/run.ts +17 -1
  91. package/dist/builtin/workflows/src/extension/atomic-stage-session.ts +12 -39
  92. package/dist/builtin/workflows/src/extension/config-file-loader.ts +10 -1
  93. package/dist/builtin/workflows/src/extension/config-loader.ts +1 -1
  94. package/dist/builtin/workflows/src/extension/dispatcher.ts +4 -0
  95. package/dist/builtin/workflows/src/extension/index.bundle.mjs +1151 -737
  96. package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +303 -38
  97. package/dist/builtin/workflows/src/extension/render-result.ts +4 -0
  98. package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +6 -3
  99. package/dist/builtin/workflows/src/extension/runtime.ts +7 -1
  100. package/dist/builtin/workflows/src/extension/wiring.ts +53 -11
  101. package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +12 -3
  102. package/dist/builtin/workflows/src/extension/workflow-durable-resume-command.ts +5 -2
  103. package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +9 -7
  104. package/dist/builtin/workflows/src/extension/workflow-status-summary.ts +11 -0
  105. package/dist/builtin/workflows/src/extension/workflow-tool-content.ts +18 -1
  106. package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +10 -8
  107. package/dist/builtin/workflows/src/extension/workflow-tool.ts +9 -4
  108. package/dist/builtin/workflows/src/runs/background/quit.ts +28 -4
  109. package/dist/builtin/workflows/src/runs/background/resume-acknowledgements.ts +2 -1
  110. package/dist/builtin/workflows/src/runs/background/status.ts +55 -8
  111. package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +4 -0
  112. package/dist/builtin/workflows/src/runs/foreground/executor-prompt-nodes.ts +3 -1
  113. package/dist/builtin/workflows/src/runs/foreground/executor-stage-control.ts +1 -1
  114. package/dist/builtin/workflows/src/runs/foreground/stage-runner-context.ts +1 -1
  115. package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +688 -38
  116. package/dist/builtin/workflows/src/runs/foreground/stage-runner-types.ts +3 -1
  117. package/dist/builtin/workflows/src/runs/shared/model-fallback-failures.ts +19 -514
  118. package/dist/builtin/workflows/src/runs/shared/retry.ts +44 -0
  119. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +5 -0
  120. package/dist/builtin/workflows/src/shared/authoring-contract-stage.ts +6 -0
  121. package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +5 -1
  122. package/dist/builtin/workflows/src/shared/authoring-contract-ui.ts +5 -0
  123. package/dist/builtin/workflows/src/shared/persistence-restore-helpers.ts +5 -0
  124. package/dist/builtin/workflows/src/shared/persistence-restore.ts +3 -0
  125. package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +4 -0
  126. package/dist/builtin/workflows/src/shared/run-indicator-status.ts +75 -0
  127. package/dist/builtin/workflows/src/shared/store-public-types.ts +43 -7
  128. package/dist/builtin/workflows/src/shared/store-run-methods.ts +42 -8
  129. package/dist/builtin/workflows/src/shared/store-stage-methods.ts +31 -8
  130. package/dist/builtin/workflows/src/shared/store-types.ts +34 -0
  131. package/dist/builtin/workflows/src/shared/timing.ts +10 -0
  132. package/dist/builtin/workflows/src/tui/chat-surface-message.ts +22 -2
  133. package/dist/builtin/workflows/src/tui/session-list.ts +1 -1
  134. package/dist/builtin/workflows/src/tui/session-overlays.ts +14 -10
  135. package/dist/builtin/workflows/src/tui/session-picker.ts +20 -4
  136. package/dist/builtin/workflows/src/tui/status-list.ts +31 -47
  137. package/dist/builtin/workflows/src/tui/store-widget-installer.ts +9 -1
  138. package/dist/builtin/workflows/src/tui/widget.ts +16 -46
  139. package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
  140. package/dist/core/agent-session-auto-compaction.js +54 -11
  141. package/dist/core/agent-session-auto-compaction.js.map +1 -1
  142. package/dist/core/agent-session-events.d.ts.map +1 -1
  143. package/dist/core/agent-session-events.js +49 -14
  144. package/dist/core/agent-session-events.js.map +1 -1
  145. package/dist/core/agent-session-methods.d.ts +13 -0
  146. package/dist/core/agent-session-methods.d.ts.map +1 -1
  147. package/dist/core/agent-session-methods.js.map +1 -1
  148. package/dist/core/agent-session-models.d.ts.map +1 -1
  149. package/dist/core/agent-session-models.js +12 -1
  150. package/dist/core/agent-session-models.js.map +1 -1
  151. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  152. package/dist/core/agent-session-prompt.js +4 -0
  153. package/dist/core/agent-session-prompt.js.map +1 -1
  154. package/dist/core/agent-session-retry.d.ts +21 -4
  155. package/dist/core/agent-session-retry.d.ts.map +1 -1
  156. package/dist/core/agent-session-retry.js +232 -106
  157. package/dist/core/agent-session-retry.js.map +1 -1
  158. package/dist/core/agent-session-state.d.ts.map +1 -1
  159. package/dist/core/agent-session-state.js +2 -1
  160. package/dist/core/agent-session-state.js.map +1 -1
  161. package/dist/core/agent-session-tool-hooks.d.ts.map +1 -1
  162. package/dist/core/agent-session-tool-hooks.js +12 -0
  163. package/dist/core/agent-session-tool-hooks.js.map +1 -1
  164. package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
  165. package/dist/core/agent-session-tool-registry.js +1 -1
  166. package/dist/core/agent-session-tool-registry.js.map +1 -1
  167. package/dist/core/agent-session-types.d.ts +3 -1
  168. package/dist/core/agent-session-types.d.ts.map +1 -1
  169. package/dist/core/agent-session-types.js.map +1 -1
  170. package/dist/core/agent-session.d.ts +12 -1
  171. package/dist/core/agent-session.d.ts.map +1 -1
  172. package/dist/core/agent-session.js +7 -0
  173. package/dist/core/agent-session.js.map +1 -1
  174. package/dist/core/extensions/context-types.d.ts +25 -0
  175. package/dist/core/extensions/context-types.d.ts.map +1 -1
  176. package/dist/core/extensions/context-types.js.map +1 -1
  177. package/dist/core/extensions/index.d.ts +1 -1
  178. package/dist/core/extensions/index.d.ts.map +1 -1
  179. package/dist/core/extensions/index.js.map +1 -1
  180. package/dist/core/extensions/runner-context.d.ts +2 -1
  181. package/dist/core/extensions/runner-context.d.ts.map +1 -1
  182. package/dist/core/extensions/runner-context.js +4 -0
  183. package/dist/core/extensions/runner-context.js.map +1 -1
  184. package/dist/core/extensions/runner.d.ts +3 -2
  185. package/dist/core/extensions/runner.d.ts.map +1 -1
  186. package/dist/core/extensions/runner.js +3 -1
  187. package/dist/core/extensions/runner.js.map +1 -1
  188. package/dist/core/model-fallback-failures.d.ts +30 -0
  189. package/dist/core/model-fallback-failures.d.ts.map +1 -0
  190. package/dist/core/model-fallback-failures.js +610 -0
  191. package/dist/core/model-fallback-failures.js.map +1 -0
  192. package/dist/core/retry-policy.d.ts +30 -0
  193. package/dist/core/retry-policy.d.ts.map +1 -0
  194. package/dist/core/retry-policy.js +25 -0
  195. package/dist/core/retry-policy.js.map +1 -0
  196. package/dist/core/sdk-types.d.ts +8 -2
  197. package/dist/core/sdk-types.d.ts.map +1 -1
  198. package/dist/core/sdk-types.js.map +1 -1
  199. package/dist/core/sdk.d.ts.map +1 -1
  200. package/dist/core/sdk.js +6 -1
  201. package/dist/core/sdk.js.map +1 -1
  202. package/dist/core/session-manager-core.d.ts +2 -0
  203. package/dist/core/session-manager-core.d.ts.map +1 -1
  204. package/dist/core/session-manager-core.js +7 -0
  205. package/dist/core/session-manager-core.js.map +1 -1
  206. package/dist/index-extensions.d.ts +1 -1
  207. package/dist/index-extensions.d.ts.map +1 -1
  208. package/dist/index-extensions.js.map +1 -1
  209. package/dist/index.d.ts +3 -0
  210. package/dist/index.d.ts.map +1 -1
  211. package/dist/index.js +2 -0
  212. package/dist/index.js.map +1 -1
  213. package/docs/intercom.md +5 -10
  214. package/docs/settings.md +7 -1
  215. package/docs/subagents.md +19 -19
  216. package/docs/workflows.md +21 -5
  217. package/examples/extensions/gondolin/package-lock.json +3 -3
  218. package/npm-shrinkwrap.json +29 -29
  219. package/package.json +2 -2
  220. package/dist/builtin/subagents/src/runs/background/async-event-journal.ts +0 -112
  221. package/dist/builtin/subagents/src/runs/background/async-execution-chain.ts +0 -543
  222. package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +0 -140
  223. package/dist/builtin/subagents/src/runs/background/async-execution-single.ts +0 -279
  224. package/dist/builtin/subagents/src/runs/background/async-execution-types.ts +0 -99
  225. package/dist/builtin/subagents/src/runs/background/async-execution.ts +0 -17
  226. package/dist/builtin/subagents/src/runs/background/async-resume.ts +0 -402
  227. package/dist/builtin/subagents/src/runs/background/async-status.ts +0 -411
  228. package/dist/builtin/subagents/src/runs/background/completion-claims.ts +0 -196
  229. package/dist/builtin/subagents/src/runs/background/completion-dedupe.ts +0 -102
  230. package/dist/builtin/subagents/src/runs/background/parallel-groups.ts +0 -59
  231. package/dist/builtin/subagents/src/runs/background/result-delivery-processor.ts +0 -300
  232. package/dist/builtin/subagents/src/runs/background/result-file-claims.ts +0 -166
  233. package/dist/builtin/subagents/src/runs/background/result-quarantine.ts +0 -77
  234. package/dist/builtin/subagents/src/runs/background/result-retry-scheduler.ts +0 -48
  235. package/dist/builtin/subagents/src/runs/background/result-status.ts +0 -87
  236. package/dist/builtin/subagents/src/runs/background/result-watcher-data.ts +0 -72
  237. package/dist/builtin/subagents/src/runs/background/result-watcher.ts +0 -320
  238. package/dist/builtin/subagents/src/runs/background/run-id-resolver.ts +0 -105
  239. package/dist/builtin/subagents/src/runs/background/run-status.ts +0 -358
  240. package/dist/builtin/subagents/src/runs/background/stale-run-reconciler.ts +0 -457
  241. package/dist/builtin/subagents/src/runs/background/subagent-runner-dynamic.ts +0 -376
  242. package/dist/builtin/subagents/src/runs/background/subagent-runner-finalize.ts +0 -150
  243. package/dist/builtin/subagents/src/runs/background/subagent-runner-output.ts +0 -109
  244. package/dist/builtin/subagents/src/runs/background/subagent-runner-parallel-helpers.ts +0 -128
  245. package/dist/builtin/subagents/src/runs/background/subagent-runner-parallel.ts +0 -309
  246. package/dist/builtin/subagents/src/runs/background/subagent-runner-sequential.ts +0 -173
  247. package/dist/builtin/subagents/src/runs/background/subagent-runner-state.ts +0 -578
  248. package/dist/builtin/subagents/src/runs/background/subagent-runner-step.ts +0 -330
  249. package/dist/builtin/subagents/src/runs/background/subagent-runner-streaming.ts +0 -330
  250. package/dist/builtin/subagents/src/runs/background/subagent-runner-types.ts +0 -210
  251. package/dist/builtin/subagents/src/runs/background/subagent-runner-utils.ts +0 -69
  252. package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +0 -90
  253. package/dist/builtin/subagents/src/runs/background/top-level-async.ts +0 -12
  254. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-control.ts +0 -140
  255. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-finalize.ts +0 -108
  256. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-types.ts +0 -17
  257. package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +0 -558
  258. package/dist/builtin/subagents/src/runs/shared/attempt-watchdog.ts +0 -126
  259. package/dist/builtin/subagents/src/runs/shared/final-drain.ts +0 -39
  260. package/dist/builtin/subagents/src/runs/shared/pi-args.ts +0 -339
  261. package/dist/builtin/subagents/src/runs/shared/pi-spawn.ts +0 -165
  262. package/dist/builtin/subagents/src/runs/shared/spawn-env.ts +0 -21
  263. package/dist/builtin/subagents/src/shared/post-exit-stdio-guard.ts +0 -86
  264. /package/dist/builtin/subagents/src/runs/{shared/nested-path.ts → inprocess/runtime-support/nested-paths.ts} +0 -0
@@ -1,558 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import { existsSync, unlinkSync } from "node:fs";
3
- import type { Message } from "@earendil-works/pi-ai/compat";
4
- import type { AgentConfig } from "../../agents/agents.ts";
5
- import { requestSupervisorAuthorization } from "../../intercom/supervisor-authorization.ts";
6
- import { resolveSubagentModelFastMode } from "../../shared/fast-mode.ts";
7
- import { createJsonlWriter } from "../../shared/jsonl-writer.ts";
8
- import { attachPostExitStdioGuard, trySignalChild } from "../../shared/post-exit-stdio-guard.ts";
9
- import { type AgentProgress, getSubagentDepthEnv, type RunSyncOptions, type SingleResult } from "../../shared/types.ts";
10
- import { extractTextFromContent, extractToolArgsPreview, getFinalOutput } from "../../shared/utils.ts";
11
- import { createAttemptWatchdog } from "../shared/attempt-watchdog.ts";
12
- import {
13
- assistantStopReason,
14
- isAssistantFailureStopReason,
15
- shouldStartSubagentFinalDrain,
16
- } from "../shared/final-drain.ts";
17
- import {
18
- createMutatingFailureState,
19
- didMutatingToolFail,
20
- isMutatingTool,
21
- recordMutatingFailure,
22
- resetMutatingFailureState,
23
- resolveCurrentPath,
24
- shouldEscalateMutatingFailures,
25
- summarizeRecentMutatingFailures,
26
- } from "../shared/long-running-guard.ts";
27
- import { modelFailureMessage } from "../shared/model-fallback.ts";
28
- import { applyThinkingSuffix, buildPiArgs, cleanupTempDir } from "../shared/pi-args.ts";
29
- import { formatPiSpawnError, getPiSpawnCommand, validatePiSpawnCwd } from "../shared/pi-spawn.ts";
30
- import { buildSubagentSpawnEnv } from "../shared/spawn-env.ts";
31
- import { createAttemptControlRuntime } from "./execution-attempt-control.ts";
32
- import { finalizeSingleAttempt } from "./execution-attempt-finalize.ts";
33
- import type { RunSingleAttemptShared } from "./execution-attempt-types.ts";
34
- import { registerExecutionIntercomDetach } from "./execution-intercom-detach.ts";
35
- import {
36
- appendRecentOutput,
37
- emptyUsage,
38
- modelFailureSignalByResult,
39
- snapshotProgress,
40
- snapshotResult,
41
- } from "./execution-utils.ts";
42
- export async function runSingleAttempt(
43
- runtimeCwd: string,
44
- agent: AgentConfig,
45
- task: string,
46
- model: string | undefined,
47
- options: RunSyncOptions,
48
- shared: RunSingleAttemptShared,
49
- ): Promise<SingleResult> {
50
- const modelArg = applyThinkingSuffix(model, agent.thinking);
51
- const runCwd = options.cwd ?? runtimeCwd;
52
- const fastMode = resolveSubagentModelFastMode({
53
- model: modelArg,
54
- cwd: runCwd,
55
- settings: shared.fastModeSettings,
56
- scope: shared.fastModeScope,
57
- });
58
- const supervisorAuthorization =
59
- options.orchestratorIntercomTarget && options.intercomSessionName
60
- ? await requestSupervisorAuthorization(options.intercomEvents, options.intercomSessionName)
61
- : undefined;
62
- const {
63
- args,
64
- env: sharedEnv,
65
- tempDir,
66
- } = buildPiArgs({
67
- baseArgs: ["--mode", "json", "-p"],
68
- task,
69
- sessionEnabled: shared.sessionEnabled,
70
- sessionDir: options.sessionDir,
71
- sessionFile: options.sessionFile,
72
- model,
73
- thinking: agent.thinking,
74
- systemPromptMode: agent.systemPromptMode,
75
- inheritProjectContext: agent.inheritProjectContext,
76
- inheritSkills: agent.inheritSkills,
77
- tools: agent.tools,
78
- extensions: agent.extensions,
79
- systemPrompt: shared.systemPrompt,
80
- mcpDirectTools: agent.mcpDirectTools,
81
- cwd: runCwd,
82
- promptFileStem: agent.name,
83
- intercomSessionName: options.intercomSessionName,
84
- orchestratorIntercomTarget: supervisorAuthorization ? options.orchestratorIntercomTarget : undefined,
85
- intercomGroup: options.intercomGroup,
86
- supervisorAuthorization,
87
- runId: options.runId,
88
- childAgentName: agent.name,
89
- childIndex: options.index ?? 0,
90
- parentEventSink: options.nestedRoute?.eventSink,
91
- parentControlInbox: options.nestedRoute?.controlInbox,
92
- parentRootRunId: options.nestedRoute?.rootRunId,
93
- parentCapabilityToken: options.nestedRoute?.capabilityToken,
94
- codexFastModeSettings: shared.fastModeSettings,
95
- codexFastModeScope: shared.fastModeScope,
96
- workflowSessionMetadata: options.workflowSessionMetadata,
97
- structuredOutput: options.structuredOutput,
98
- });
99
- const result: SingleResult = {
100
- agent: agent.name,
101
- task: shared.originalTask ?? task,
102
- exitCode: 0,
103
- messages: [],
104
- usage: emptyUsage(),
105
- model: modelArg,
106
- ...(fastMode ? { fastMode } : {}),
107
- artifactPaths: shared.artifactPaths,
108
- skills: shared.resolvedSkillNames,
109
- skillsWarning: shared.skillsWarning,
110
- };
111
- const startTime = Date.now();
112
- if (options.structuredOutput) {
113
- try {
114
- if (existsSync(options.structuredOutput.outputPath)) unlinkSync(options.structuredOutput.outputPath);
115
- } catch {
116
- // Missing/stale structured-output files are handled after the child exits.
117
- }
118
- }
119
- let interruptedByControl = false;
120
- const progress: AgentProgress = {
121
- index: options.index ?? 0,
122
- agent: agent.name,
123
- status: "running",
124
- task,
125
- skills: shared.resolvedSkillNames,
126
- recentTools: [],
127
- recentOutput: [...shared.attemptNotes],
128
- toolCount: 0,
129
- tokens: 0,
130
- durationMs: 0,
131
- lastActivityAt: startTime,
132
- };
133
- result.progress = progress;
134
- const controlRuntime = createAttemptControlRuntime({ options, agent, result, progress, startTime });
135
- const spawnEnv = buildSubagentSpawnEnv(
136
- process.env,
137
- sharedEnv,
138
- getSubagentDepthEnv(options.maxSubagentDepth, {
139
- workflowStageSubagentGuard: options.workflowStageSubagentGuard,
140
- }),
141
- );
142
- const cwdValidation = validatePiSpawnCwd(runCwd);
143
- if (!cwdValidation.ok) {
144
- cleanupTempDir(tempDir);
145
- result.error = cwdValidation.error;
146
- return finalizeSingleAttempt({
147
- result,
148
- progress,
149
- exitCode: 1,
150
- interruptedByControl,
151
- allControlEvents: controlRuntime.allControlEvents,
152
- options,
153
- shared,
154
- startTime,
155
- });
156
- }
157
- const exitCode = await new Promise<number>((resolve) => {
158
- const spawnSpec = getPiSpawnCommand(args, options.piArgv1 ? { argv1: options.piArgv1 } : {});
159
- const proc = spawn(spawnSpec.command, spawnSpec.args, {
160
- cwd: runCwd,
161
- env: spawnEnv,
162
- stdio: ["ignore", "pipe", "pipe"],
163
- windowsHide: true,
164
- });
165
- const jsonlWriter = createJsonlWriter(shared.jsonlPath, proc.stdout);
166
- let buf = "";
167
- let processClosed = false;
168
- let settled = false;
169
- let detached = false;
170
- let assistantError: string | undefined;
171
- let assistantFailureSignal: unknown;
172
- let removeAbortListener: (() => void) | undefined;
173
- let removeInterruptListener: (() => void) | undefined;
174
- let activityTimer: NodeJS.Timeout | undefined;
175
- const detachForIntercom = () => {
176
- if (detached || processClosed) return;
177
- detached = true;
178
- result.detached = true;
179
- result.detachedReason = "intercom coordination";
180
- progress.status = "detached";
181
- progress.durationMs = Date.now() - startTime;
182
- result.progressSummary = {
183
- toolCount: progress.toolCount,
184
- tokens: progress.tokens,
185
- durationMs: progress.durationMs,
186
- };
187
- // Settle foreground supervision while retaining process lifecycle ownership.
188
- finish(-2, true);
189
- };
190
- const FINAL_STOP_GRACE_MS = 1000;
191
- const HARD_KILL_MS = 3000;
192
- let childExited = false;
193
- let forcedTerminationSignal = false;
194
- let cleanTerminalAssistantStopReceived = false;
195
- let finalDrainTimer: NodeJS.Timeout | undefined;
196
- let finalHardKillTimer: NodeJS.Timeout | undefined;
197
- const clearFinalDrainTimers = () => {
198
- if (finalDrainTimer) {
199
- clearTimeout(finalDrainTimer);
200
- finalDrainTimer = undefined;
201
- }
202
- if (finalHardKillTimer) {
203
- clearTimeout(finalHardKillTimer);
204
- finalHardKillTimer = undefined;
205
- }
206
- };
207
- const startFinalDrain = () => {
208
- if (childExited || finalDrainTimer || processClosed) return;
209
- finalDrainTimer = setTimeout(() => {
210
- if (processClosed) return;
211
- const termSent = trySignalChild(proc, "SIGTERM");
212
- if (!termSent) return;
213
- forcedTerminationSignal = true;
214
- if (!cleanTerminalAssistantStopReceived && !assistantError) {
215
- result.error =
216
- result.error ??
217
- `Subagent process did not exit within ${FINAL_STOP_GRACE_MS}ms after its final message. Forcing termination.`;
218
- }
219
- finalHardKillTimer = setTimeout(() => {
220
- if (processClosed) return;
221
- forcedTerminationSignal = trySignalChild(proc, "SIGKILL") || forcedTerminationSignal;
222
- }, HARD_KILL_MS);
223
- finalHardKillTimer.unref?.();
224
- }, FINAL_STOP_GRACE_MS);
225
- finalDrainTimer.unref?.();
226
- };
227
- const finish = (code: number, retainLifecycleOwner = false) => {
228
- if (settled) return;
229
- settled = true;
230
- if (!retainLifecycleOwner) {
231
- clearFinalDrainTimers();
232
- clearStdioGuard();
233
- attemptWatchdog.clear();
234
- removeAbortListener?.();
235
- cleanupIntercomDetach();
236
- }
237
- if (activityTimer) {
238
- clearInterval(activityTimer);
239
- activityTimer = undefined;
240
- }
241
- removeInterruptListener?.();
242
- resolve(code);
243
- };
244
- const cleanupIntercomDetach = registerExecutionIntercomDetach(options, {
245
- isUnavailable: () => processClosed || options.signal?.aborted === true,
246
- isDetached: () => detached,
247
- detach: detachForIntercom,
248
- });
249
- let pendingToolResult: { tool: string; path?: string; mutates: boolean; startedAt?: number } | undefined;
250
- const mutatingFailures = createMutatingFailureState();
251
- const mutatingFailureWindowMs = 5 * 60_000;
252
- const emitUpdateSnapshot = (text: string) => {
253
- if (!options.onUpdate || processClosed) return;
254
- const progressSnapshot = snapshotProgress(progress);
255
- const resultSnapshot = snapshotResult(result, progressSnapshot);
256
- options.onUpdate({
257
- content: [{ type: "text", text }],
258
- details: {
259
- mode: "single",
260
- results: [resultSnapshot],
261
- progress: [progressSnapshot],
262
- controlEvents: controlRuntime.drainPendingControlEvents(),
263
- },
264
- });
265
- };
266
- const fireUpdate = () => {
267
- if (!options.onUpdate || processClosed) return;
268
- progress.durationMs = Date.now() - startTime;
269
- emitUpdateSnapshot(getFinalOutput(result.messages ?? []) || "(running...)");
270
- };
271
- const processLine = (line: string) => {
272
- if (!line.trim()) return;
273
- jsonlWriter.writeLine(line);
274
- let evt: { type?: string; message?: Message; toolName?: string; args?: unknown };
275
- try {
276
- evt = JSON.parse(line) as { type?: string; message?: Message; toolName?: string; args?: unknown };
277
- } catch {
278
- return;
279
- }
280
-
281
- const now = Date.now();
282
- progress.durationMs = now - startTime;
283
- progress.lastActivityAt = now;
284
- controlRuntime.updateActivityState(now);
285
-
286
- if (evt.type === "tool_execution_start") {
287
- const toolArgs =
288
- evt.args && typeof evt.args === "object" && !Array.isArray(evt.args)
289
- ? (evt.args as Record<string, unknown>)
290
- : {};
291
- // Broker delivery is the authoritative detach trigger; tool-start observation
292
- // is intentionally not required because the broker event may arrive first.
293
- progress.toolCount++;
294
- progress.currentTool = evt.toolName;
295
- progress.currentToolArgs = extractToolArgsPreview(toolArgs);
296
- progress.currentToolStartedAt = now;
297
- progress.currentPath = resolveCurrentPath(evt.toolName, toolArgs);
298
- pendingToolResult = {
299
- tool: evt.toolName ?? "tool",
300
- path: progress.currentPath,
301
- mutates: isMutatingTool(evt.toolName, toolArgs),
302
- startedAt: now,
303
- };
304
- fireUpdate();
305
- }
306
-
307
- if (evt.type === "tool_execution_end") {
308
- if (progress.currentTool) {
309
- progress.recentTools.push({
310
- tool: progress.currentTool,
311
- args: progress.currentToolArgs || "",
312
- endMs: now,
313
- });
314
- }
315
- progress.currentTool = undefined;
316
- progress.currentToolArgs = undefined;
317
- progress.currentToolStartedAt = undefined;
318
- progress.currentPath = undefined;
319
- fireUpdate();
320
- }
321
-
322
- if (evt.type === "message_end" && evt.message) {
323
- result.messages?.push(evt.message);
324
- if (evt.message.role === "assistant") {
325
- result.usage.turns++;
326
- progress.turnCount = result.usage.turns;
327
- const u = evt.message.usage;
328
- if (u) {
329
- result.usage.input += u.input || 0;
330
- result.usage.output += u.output || 0;
331
- result.usage.cacheRead += u.cacheRead || 0;
332
- result.usage.cacheWrite += u.cacheWrite || 0;
333
- result.usage.cost += u.cost?.total || 0;
334
- progress.tokens = result.usage.input + result.usage.output;
335
- }
336
- if (!result.model && evt.message.model) result.model = evt.message.model;
337
- const assistantText = extractTextFromContent(evt.message.content);
338
- appendRecentOutput(progress, assistantText.split("\n").slice(-10));
339
- const stopReason = assistantStopReason(evt.message);
340
- if (evt.message.errorMessage) {
341
- assistantError = evt.message.errorMessage;
342
- assistantFailureSignal = evt.message;
343
- }
344
- if (isAssistantFailureStopReason(stopReason)) {
345
- assistantError = modelFailureMessage(evt.message);
346
- assistantFailureSignal = evt.message;
347
- }
348
- if (shouldStartSubagentFinalDrain(evt.message)) {
349
- if (assistantText.trim()) {
350
- assistantError = undefined;
351
- assistantFailureSignal = undefined;
352
- }
353
- cleanTerminalAssistantStopReceived = true;
354
- startFinalDrain();
355
- }
356
- }
357
- controlRuntime.updateActivityState(now);
358
- fireUpdate();
359
- }
360
-
361
- if (evt.type === "tool_result_end" && evt.message) {
362
- result.messages?.push(evt.message);
363
- const resultText = extractTextFromContent(evt.message.content);
364
- appendRecentOutput(progress, resultText.split("\n").slice(-10));
365
- const toolSnapshot = pendingToolResult;
366
- pendingToolResult = undefined;
367
- if (toolSnapshot?.mutates && didMutatingToolFail(resultText)) {
368
- recordMutatingFailure(
369
- mutatingFailures,
370
- {
371
- tool: toolSnapshot.tool,
372
- path: toolSnapshot.path,
373
- error:
374
- resultText
375
- .split("\n")
376
- .find((row) => row.trim())
377
- ?.trim()
378
- .slice(0, 180) ?? "mutating tool failed",
379
- ts: now,
380
- },
381
- mutatingFailureWindowMs,
382
- );
383
- if (
384
- shouldEscalateMutatingFailures(
385
- mutatingFailures,
386
- controlRuntime.config.failedToolAttemptsBeforeAttention,
387
- )
388
- ) {
389
- controlRuntime.emitNeedsAttention(now, {
390
- message: `${agent.name} needs attention after repeated mutating tool failures`,
391
- reason: "tool_failures",
392
- currentTool: toolSnapshot.tool,
393
- currentPath: toolSnapshot.path,
394
- currentToolDurationMs: toolSnapshot.startedAt
395
- ? Math.max(0, now - toolSnapshot.startedAt)
396
- : undefined,
397
- recentFailureSummary: summarizeRecentMutatingFailures(mutatingFailures),
398
- });
399
- }
400
- } else if (toolSnapshot?.mutates) {
401
- resetMutatingFailureState(mutatingFailures);
402
- }
403
- fireUpdate();
404
- }
405
- };
406
-
407
- if (controlRuntime.config.enabled) {
408
- activityTimer = setInterval(() => {
409
- if (processClosed || settled || detached) return;
410
- const now = Date.now();
411
- if (controlRuntime.updateActivityState(now)) {
412
- progress.durationMs = now - startTime;
413
- fireUpdate();
414
- }
415
- }, 1000);
416
- activityTimer.unref?.();
417
- }
418
-
419
- let stderrBuf = "";
420
- const clearStdioGuard = attachPostExitStdioGuard(proc, { idleMs: 2000, hardMs: 8000 });
421
- const attemptWatchdog = createAttemptWatchdog({
422
- child: proc,
423
- isSettled: () => processClosed,
424
- // A slow, quiet tool call (long build/test run) must not be mistaken for a
425
- // stalled attempt: an in-flight tool execution counts as watchdog activity.
426
- // Caveat: `progress.currentTool` is cleared on tool_execution_end, so if a
427
- // tool ends abnormally without emitting its end event the idle watchdog is
428
- // deferred indefinitely and the wall-clock cap becomes the sole backstop for
429
- // this attempt — do not lower the wall cap assuming idle always fires.
430
- isToolActive: () => progress.currentTool !== undefined,
431
- onTimeout(message) {
432
- forcedTerminationSignal = true;
433
- result.error ??= message;
434
- progress.error = message;
435
- },
436
- });
437
- proc.stdout.on("data", (d) => {
438
- attemptWatchdog.activity();
439
- buf += d.toString();
440
- const lines = buf.split("\n");
441
- buf = lines.pop() || "";
442
- lines.forEach(processLine);
443
- });
444
- proc.stderr.on("data", (d) => {
445
- attemptWatchdog.activity();
446
- stderrBuf += d.toString();
447
- });
448
- proc.on("exit", () => {
449
- childExited = true;
450
- clearFinalDrainTimers();
451
- });
452
- proc.on("close", (code, signal) => {
453
- clearFinalDrainTimers();
454
- clearStdioGuard();
455
- attemptWatchdog.clear();
456
- removeAbortListener?.();
457
- removeAbortListener = undefined;
458
- removeInterruptListener?.();
459
- removeInterruptListener = undefined;
460
- cleanupIntercomDetach();
461
- void jsonlWriter.close().catch(() => undefined);
462
- cleanupTempDir(tempDir);
463
- if (buf.trim()) processLine(buf);
464
- if (!result.error && assistantError) result.error = assistantError;
465
- if (assistantFailureSignal !== undefined && result.error === assistantError) {
466
- modelFailureSignalByResult.set(result, assistantFailureSignal);
467
- }
468
- const forcedDrainAfterFinalSuccess =
469
- forcedTerminationSignal && cleanTerminalAssistantStopReceived && !result.error;
470
- if (code !== 0 && stderrBuf.trim() && !result.error && !forcedDrainAfterFinalSuccess)
471
- result.error = stderrBuf.trim();
472
- const finalCode = forcedDrainAfterFinalSuccess
473
- ? 0
474
- : forcedTerminationSignal || signal
475
- ? (code ?? 1)
476
- : (code ?? 0);
477
- if (detached) {
478
- processClosed = true;
479
- const recovered: SingleResult = { ...result, detached: undefined, detachedReason: undefined };
480
- const recoveredProgress = recovered.progress ? { ...recovered.progress } : progress;
481
- options.onDetachedExit?.(
482
- finalizeSingleAttempt({
483
- result: recovered,
484
- progress: recoveredProgress,
485
- exitCode: finalCode,
486
- interruptedByControl,
487
- allControlEvents: controlRuntime.allControlEvents,
488
- options: { ...options, onUpdate: undefined },
489
- shared,
490
- startTime,
491
- }),
492
- );
493
- return;
494
- }
495
- processClosed = true;
496
- finish(finalCode);
497
- });
498
- proc.on("error", (error) => {
499
- clearFinalDrainTimers();
500
- clearStdioGuard();
501
- attemptWatchdog.clear();
502
- cleanupIntercomDetach();
503
- void jsonlWriter.close().catch(() => undefined);
504
- cleanupTempDir(tempDir);
505
- if (!result.error) result.error = formatPiSpawnError(error, spawnSpec, runCwd);
506
- finish(1);
507
- });
508
-
509
- if (options.signal) {
510
- const kill = () => {
511
- if (childExited) return;
512
- trySignalChild(proc, "SIGTERM");
513
- setTimeout(() => {
514
- if (!childExited) trySignalChild(proc, "SIGKILL");
515
- }, 3000).unref?.();
516
- };
517
- if (options.signal.aborted) kill();
518
- else {
519
- options.signal.addEventListener("abort", kill, { once: true });
520
- removeAbortListener = () => options.signal?.removeEventListener("abort", kill);
521
- }
522
- }
523
-
524
- if (options.interruptSignal) {
525
- const interrupt = () => {
526
- if (processClosed || detached || settled) return;
527
- interruptedByControl = true;
528
- progress.status = "running";
529
- progress.durationMs = Date.now() - startTime;
530
- result.interrupted = true;
531
- result.finalOutput = "Interrupted. Waiting for explicit next action.";
532
- progress.activityState = undefined;
533
- fireUpdate();
534
- trySignalChild(proc, "SIGINT");
535
- setTimeout(() => {
536
- if (settled || processClosed || detached) return;
537
- trySignalChild(proc, "SIGTERM");
538
- }, 1000).unref?.();
539
- };
540
- if (options.interruptSignal.aborted) interrupt();
541
- else {
542
- options.interruptSignal.addEventListener("abort", interrupt, { once: true });
543
- removeInterruptListener = () => options.interruptSignal?.removeEventListener("abort", interrupt);
544
- }
545
- }
546
- });
547
-
548
- return finalizeSingleAttempt({
549
- result,
550
- progress,
551
- exitCode,
552
- interruptedByControl,
553
- allControlEvents: controlRuntime.allControlEvents,
554
- options,
555
- shared,
556
- startTime,
557
- });
558
- }
@@ -1,126 +0,0 @@
1
- import type { ChildProcess } from "node:child_process";
2
- import { trySignalChild } from "../../shared/post-exit-stdio-guard.ts";
3
-
4
- const DEFAULT_IDLE_MS = 5 * 60_000;
5
- const DEFAULT_WALL_MS = 60 * 60_000;
6
- const DEFAULT_KILL_GRACE_MS = 3_000;
7
-
8
- export interface AttemptTimeoutConfig {
9
- idleMs: number;
10
- wallMs: number;
11
- killGraceMs: number;
12
- }
13
-
14
- export interface AttemptWatchdog {
15
- activity(): void;
16
- clear(): void;
17
- }
18
-
19
- /** Parse a millisecond override from the environment. Non-numeric values are
20
- * silently ignored (the default applies). Zero or negative values are clamped
21
- * to `0`, which callers treat as "timeout disabled". */
22
- function envMs(name: string): number | undefined {
23
- const raw = process.env[name];
24
- if (!raw) return undefined;
25
- const value = Number(raw);
26
- if (!Number.isFinite(value)) return undefined;
27
- return value > 0 ? Math.floor(value) : 0;
28
- }
29
-
30
- function positiveEnvMs(name: string): number | undefined {
31
- const value = envMs(name);
32
- return value !== undefined && value > 0 ? value : undefined;
33
- }
34
-
35
- export function resolveAttemptTimeoutConfig(): AttemptTimeoutConfig {
36
- return {
37
- // `0` (or a negative value) disables the corresponding timeout entirely.
38
- idleMs: envMs("ATOMIC_SUBAGENT_ATTEMPT_IDLE_TIMEOUT_MS") ?? DEFAULT_IDLE_MS,
39
- wallMs: envMs("ATOMIC_SUBAGENT_ATTEMPT_TIMEOUT_MS") ?? DEFAULT_WALL_MS,
40
- // The SIGTERM→SIGKILL grace period intentionally cannot be disabled: once a
41
- // watchdog trips, escalation must always be bounded. `0`, negative, or
42
- // non-numeric values fall back to the default.
43
- killGraceMs: positiveEnvMs("ATOMIC_SUBAGENT_ATTEMPT_KILL_GRACE_MS") ?? DEFAULT_KILL_GRACE_MS,
44
- };
45
- }
46
-
47
- export function idleTimeoutMessage(idleMs: number): string {
48
- return `Subagent model attempt timed out after ${idleMs}ms without child activity.`;
49
- }
50
-
51
- export function wallTimeoutMessage(wallMs: number): string {
52
- return `Subagent model attempt timed out after ${wallMs}ms.`;
53
- }
54
-
55
- export function createAttemptWatchdog(params: {
56
- child: ChildProcess;
57
- config?: Partial<AttemptTimeoutConfig>;
58
- onTimeout: (message: string) => void;
59
- isSettled: () => boolean;
60
- /** Reports whether a tool call is currently executing in the child. A slow tool
61
- * (long build, large test suite) can legitimately stay silent past the idle
62
- * window, so an in-flight tool execution counts as activity and defers the idle
63
- * trip. The wall-clock cap still bounds the whole attempt. */
64
- isToolActive?: () => boolean;
65
- }): AttemptWatchdog {
66
- const config = { ...resolveAttemptTimeoutConfig(), ...(params.config ?? {}) };
67
- let idleTimer: NodeJS.Timeout | undefined;
68
- let wallTimer: NodeJS.Timeout | undefined;
69
- let killTimer: NodeJS.Timeout | undefined;
70
- let tripped = false;
71
-
72
- const clearIdle = () => {
73
- if (!idleTimer) return;
74
- clearTimeout(idleTimer);
75
- idleTimer = undefined;
76
- };
77
- const clearAll = () => {
78
- clearIdle();
79
- if (wallTimer) {
80
- clearTimeout(wallTimer);
81
- wallTimer = undefined;
82
- }
83
- if (killTimer) {
84
- clearTimeout(killTimer);
85
- killTimer = undefined;
86
- }
87
- };
88
- const trip = (message: string) => {
89
- if (tripped || params.isSettled()) return;
90
- tripped = true;
91
- clearIdle();
92
- params.onTimeout(message);
93
- trySignalChild(params.child, "SIGTERM");
94
- killTimer = setTimeout(() => {
95
- if (!params.isSettled()) trySignalChild(params.child, "SIGKILL");
96
- }, config.killGraceMs);
97
- killTimer.unref?.();
98
- };
99
- const scheduleIdle = () => {
100
- clearIdle();
101
- if (config.idleMs <= 0) return; // idle watchdog disabled
102
- idleTimer = setTimeout(() => {
103
- if (params.isToolActive?.()) {
104
- // Do not kill a healthy attempt that is busy inside a slow tool call;
105
- // re-arm the idle window and let the wall-clock cap bound the attempt.
106
- scheduleIdle();
107
- return;
108
- }
109
- trip(idleTimeoutMessage(config.idleMs));
110
- }, config.idleMs);
111
- idleTimer.unref?.();
112
- };
113
-
114
- scheduleIdle();
115
- if (config.wallMs > 0) {
116
- wallTimer = setTimeout(() => trip(wallTimeoutMessage(config.wallMs)), config.wallMs);
117
- wallTimer.unref?.();
118
- }
119
-
120
- return {
121
- activity() {
122
- if (!tripped && !params.isSettled()) scheduleIdle();
123
- },
124
- clear: clearAll,
125
- };
126
- }