@bastani/atomic 0.9.12-alpha.1 → 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 (265) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/builtin/intercom/CHANGELOG.md +12 -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 +12 -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 +36 -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/CHANGELOG.md +6 -0
  82. package/dist/builtin/web-access/package.json +1 -1
  83. package/dist/builtin/workflows/CHANGELOG.md +38 -0
  84. package/dist/builtin/workflows/README.md +13 -3
  85. package/dist/builtin/workflows/package.json +1 -1
  86. package/dist/builtin/workflows/src/durable/backend.ts +7 -0
  87. package/dist/builtin/workflows/src/durable/dbos-metadata.ts +11 -1
  88. package/dist/builtin/workflows/src/durable/resume-runtime.ts +1 -0
  89. package/dist/builtin/workflows/src/durable/tool-primitive.ts +4 -28
  90. package/dist/builtin/workflows/src/durable/types.ts +5 -0
  91. package/dist/builtin/workflows/src/engine/run.ts +17 -1
  92. package/dist/builtin/workflows/src/extension/atomic-stage-session.ts +12 -39
  93. package/dist/builtin/workflows/src/extension/config-file-loader.ts +10 -1
  94. package/dist/builtin/workflows/src/extension/config-loader.ts +1 -1
  95. package/dist/builtin/workflows/src/extension/dispatcher.ts +4 -0
  96. package/dist/builtin/workflows/src/extension/index.bundle.mjs +1151 -737
  97. package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +303 -38
  98. package/dist/builtin/workflows/src/extension/render-result.ts +4 -0
  99. package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +6 -3
  100. package/dist/builtin/workflows/src/extension/runtime.ts +7 -1
  101. package/dist/builtin/workflows/src/extension/wiring.ts +53 -11
  102. package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +12 -3
  103. package/dist/builtin/workflows/src/extension/workflow-durable-resume-command.ts +5 -2
  104. package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +9 -7
  105. package/dist/builtin/workflows/src/extension/workflow-status-summary.ts +11 -0
  106. package/dist/builtin/workflows/src/extension/workflow-tool-content.ts +18 -1
  107. package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +10 -8
  108. package/dist/builtin/workflows/src/extension/workflow-tool.ts +9 -4
  109. package/dist/builtin/workflows/src/runs/background/quit.ts +28 -4
  110. package/dist/builtin/workflows/src/runs/background/resume-acknowledgements.ts +2 -1
  111. package/dist/builtin/workflows/src/runs/background/status.ts +55 -8
  112. package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +4 -0
  113. package/dist/builtin/workflows/src/runs/foreground/executor-prompt-nodes.ts +3 -1
  114. package/dist/builtin/workflows/src/runs/foreground/executor-stage-control.ts +1 -1
  115. package/dist/builtin/workflows/src/runs/foreground/stage-runner-context.ts +1 -1
  116. package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +688 -38
  117. package/dist/builtin/workflows/src/runs/foreground/stage-runner-types.ts +3 -1
  118. package/dist/builtin/workflows/src/runs/shared/model-fallback-failures.ts +19 -514
  119. package/dist/builtin/workflows/src/runs/shared/retry.ts +44 -0
  120. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +5 -0
  121. package/dist/builtin/workflows/src/shared/authoring-contract-stage.ts +6 -0
  122. package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +5 -1
  123. package/dist/builtin/workflows/src/shared/authoring-contract-ui.ts +5 -0
  124. package/dist/builtin/workflows/src/shared/persistence-restore-helpers.ts +5 -0
  125. package/dist/builtin/workflows/src/shared/persistence-restore.ts +3 -0
  126. package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +4 -0
  127. package/dist/builtin/workflows/src/shared/run-indicator-status.ts +75 -0
  128. package/dist/builtin/workflows/src/shared/store-public-types.ts +43 -7
  129. package/dist/builtin/workflows/src/shared/store-run-methods.ts +42 -8
  130. package/dist/builtin/workflows/src/shared/store-stage-methods.ts +31 -8
  131. package/dist/builtin/workflows/src/shared/store-types.ts +34 -0
  132. package/dist/builtin/workflows/src/shared/timing.ts +10 -0
  133. package/dist/builtin/workflows/src/tui/chat-surface-message.ts +22 -2
  134. package/dist/builtin/workflows/src/tui/session-list.ts +1 -1
  135. package/dist/builtin/workflows/src/tui/session-overlays.ts +14 -10
  136. package/dist/builtin/workflows/src/tui/session-picker.ts +20 -4
  137. package/dist/builtin/workflows/src/tui/status-list.ts +31 -47
  138. package/dist/builtin/workflows/src/tui/store-widget-installer.ts +9 -1
  139. package/dist/builtin/workflows/src/tui/widget.ts +16 -46
  140. package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
  141. package/dist/core/agent-session-auto-compaction.js +54 -11
  142. package/dist/core/agent-session-auto-compaction.js.map +1 -1
  143. package/dist/core/agent-session-events.d.ts.map +1 -1
  144. package/dist/core/agent-session-events.js +49 -14
  145. package/dist/core/agent-session-events.js.map +1 -1
  146. package/dist/core/agent-session-methods.d.ts +13 -0
  147. package/dist/core/agent-session-methods.d.ts.map +1 -1
  148. package/dist/core/agent-session-methods.js.map +1 -1
  149. package/dist/core/agent-session-models.d.ts.map +1 -1
  150. package/dist/core/agent-session-models.js +12 -1
  151. package/dist/core/agent-session-models.js.map +1 -1
  152. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  153. package/dist/core/agent-session-prompt.js +4 -0
  154. package/dist/core/agent-session-prompt.js.map +1 -1
  155. package/dist/core/agent-session-retry.d.ts +21 -4
  156. package/dist/core/agent-session-retry.d.ts.map +1 -1
  157. package/dist/core/agent-session-retry.js +232 -106
  158. package/dist/core/agent-session-retry.js.map +1 -1
  159. package/dist/core/agent-session-state.d.ts.map +1 -1
  160. package/dist/core/agent-session-state.js +2 -1
  161. package/dist/core/agent-session-state.js.map +1 -1
  162. package/dist/core/agent-session-tool-hooks.d.ts.map +1 -1
  163. package/dist/core/agent-session-tool-hooks.js +12 -0
  164. package/dist/core/agent-session-tool-hooks.js.map +1 -1
  165. package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
  166. package/dist/core/agent-session-tool-registry.js +1 -1
  167. package/dist/core/agent-session-tool-registry.js.map +1 -1
  168. package/dist/core/agent-session-types.d.ts +3 -1
  169. package/dist/core/agent-session-types.d.ts.map +1 -1
  170. package/dist/core/agent-session-types.js.map +1 -1
  171. package/dist/core/agent-session.d.ts +12 -1
  172. package/dist/core/agent-session.d.ts.map +1 -1
  173. package/dist/core/agent-session.js +7 -0
  174. package/dist/core/agent-session.js.map +1 -1
  175. package/dist/core/extensions/context-types.d.ts +25 -0
  176. package/dist/core/extensions/context-types.d.ts.map +1 -1
  177. package/dist/core/extensions/context-types.js.map +1 -1
  178. package/dist/core/extensions/index.d.ts +1 -1
  179. package/dist/core/extensions/index.d.ts.map +1 -1
  180. package/dist/core/extensions/index.js.map +1 -1
  181. package/dist/core/extensions/runner-context.d.ts +2 -1
  182. package/dist/core/extensions/runner-context.d.ts.map +1 -1
  183. package/dist/core/extensions/runner-context.js +4 -0
  184. package/dist/core/extensions/runner-context.js.map +1 -1
  185. package/dist/core/extensions/runner.d.ts +3 -2
  186. package/dist/core/extensions/runner.d.ts.map +1 -1
  187. package/dist/core/extensions/runner.js +3 -1
  188. package/dist/core/extensions/runner.js.map +1 -1
  189. package/dist/core/model-fallback-failures.d.ts +30 -0
  190. package/dist/core/model-fallback-failures.d.ts.map +1 -0
  191. package/dist/core/model-fallback-failures.js +610 -0
  192. package/dist/core/model-fallback-failures.js.map +1 -0
  193. package/dist/core/retry-policy.d.ts +30 -0
  194. package/dist/core/retry-policy.d.ts.map +1 -0
  195. package/dist/core/retry-policy.js +25 -0
  196. package/dist/core/retry-policy.js.map +1 -0
  197. package/dist/core/sdk-types.d.ts +8 -2
  198. package/dist/core/sdk-types.d.ts.map +1 -1
  199. package/dist/core/sdk-types.js.map +1 -1
  200. package/dist/core/sdk.d.ts.map +1 -1
  201. package/dist/core/sdk.js +6 -1
  202. package/dist/core/sdk.js.map +1 -1
  203. package/dist/core/session-manager-core.d.ts +2 -0
  204. package/dist/core/session-manager-core.d.ts.map +1 -1
  205. package/dist/core/session-manager-core.js +7 -0
  206. package/dist/core/session-manager-core.js.map +1 -1
  207. package/dist/index-extensions.d.ts +1 -1
  208. package/dist/index-extensions.d.ts.map +1 -1
  209. package/dist/index-extensions.js.map +1 -1
  210. package/dist/index.d.ts +3 -0
  211. package/dist/index.d.ts.map +1 -1
  212. package/dist/index.js +2 -0
  213. package/dist/index.js.map +1 -1
  214. package/docs/intercom.md +5 -10
  215. package/docs/settings.md +7 -1
  216. package/docs/subagents.md +19 -19
  217. package/docs/workflows.md +21 -5
  218. package/examples/extensions/gondolin/package-lock.json +3 -3
  219. package/npm-shrinkwrap.json +29 -29
  220. package/package.json +2 -2
  221. package/dist/builtin/subagents/src/runs/background/async-event-journal.ts +0 -112
  222. package/dist/builtin/subagents/src/runs/background/async-execution-chain.ts +0 -543
  223. package/dist/builtin/subagents/src/runs/background/async-execution-common.ts +0 -140
  224. package/dist/builtin/subagents/src/runs/background/async-execution-single.ts +0 -279
  225. package/dist/builtin/subagents/src/runs/background/async-execution-types.ts +0 -99
  226. package/dist/builtin/subagents/src/runs/background/async-execution.ts +0 -17
  227. package/dist/builtin/subagents/src/runs/background/async-resume.ts +0 -402
  228. package/dist/builtin/subagents/src/runs/background/async-status.ts +0 -411
  229. package/dist/builtin/subagents/src/runs/background/completion-claims.ts +0 -196
  230. package/dist/builtin/subagents/src/runs/background/completion-dedupe.ts +0 -102
  231. package/dist/builtin/subagents/src/runs/background/parallel-groups.ts +0 -59
  232. package/dist/builtin/subagents/src/runs/background/result-delivery-processor.ts +0 -300
  233. package/dist/builtin/subagents/src/runs/background/result-file-claims.ts +0 -166
  234. package/dist/builtin/subagents/src/runs/background/result-quarantine.ts +0 -77
  235. package/dist/builtin/subagents/src/runs/background/result-retry-scheduler.ts +0 -48
  236. package/dist/builtin/subagents/src/runs/background/result-status.ts +0 -87
  237. package/dist/builtin/subagents/src/runs/background/result-watcher-data.ts +0 -72
  238. package/dist/builtin/subagents/src/runs/background/result-watcher.ts +0 -320
  239. package/dist/builtin/subagents/src/runs/background/run-id-resolver.ts +0 -105
  240. package/dist/builtin/subagents/src/runs/background/run-status.ts +0 -358
  241. package/dist/builtin/subagents/src/runs/background/stale-run-reconciler.ts +0 -457
  242. package/dist/builtin/subagents/src/runs/background/subagent-runner-dynamic.ts +0 -376
  243. package/dist/builtin/subagents/src/runs/background/subagent-runner-finalize.ts +0 -150
  244. package/dist/builtin/subagents/src/runs/background/subagent-runner-output.ts +0 -109
  245. package/dist/builtin/subagents/src/runs/background/subagent-runner-parallel-helpers.ts +0 -128
  246. package/dist/builtin/subagents/src/runs/background/subagent-runner-parallel.ts +0 -309
  247. package/dist/builtin/subagents/src/runs/background/subagent-runner-sequential.ts +0 -173
  248. package/dist/builtin/subagents/src/runs/background/subagent-runner-state.ts +0 -578
  249. package/dist/builtin/subagents/src/runs/background/subagent-runner-step.ts +0 -330
  250. package/dist/builtin/subagents/src/runs/background/subagent-runner-streaming.ts +0 -330
  251. package/dist/builtin/subagents/src/runs/background/subagent-runner-types.ts +0 -210
  252. package/dist/builtin/subagents/src/runs/background/subagent-runner-utils.ts +0 -69
  253. package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +0 -90
  254. package/dist/builtin/subagents/src/runs/background/top-level-async.ts +0 -12
  255. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-control.ts +0 -140
  256. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-finalize.ts +0 -108
  257. package/dist/builtin/subagents/src/runs/foreground/execution-attempt-types.ts +0 -17
  258. package/dist/builtin/subagents/src/runs/foreground/execution-attempt.ts +0 -558
  259. package/dist/builtin/subagents/src/runs/shared/attempt-watchdog.ts +0 -126
  260. package/dist/builtin/subagents/src/runs/shared/final-drain.ts +0 -39
  261. package/dist/builtin/subagents/src/runs/shared/pi-args.ts +0 -339
  262. package/dist/builtin/subagents/src/runs/shared/pi-spawn.ts +0 -165
  263. package/dist/builtin/subagents/src/runs/shared/spawn-env.ts +0 -21
  264. package/dist/builtin/subagents/src/shared/post-exit-stdio-guard.ts +0 -86
  265. /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
- }