@stigmer/runner 3.15.0 → 3.15.2-dev.20260913223433

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 (518) hide show
  1. package/README.md +2 -4
  2. package/dist/.build-fingerprint +1 -1
  3. package/dist/__test-utils__/execution-record-fixture.d.ts +14 -0
  4. package/dist/__test-utils__/execution-record-fixture.js +4 -0
  5. package/dist/__test-utils__/execution-record-fixture.js.map +1 -1
  6. package/dist/__test-utils__/file-review-projection.d.ts +40 -0
  7. package/dist/__test-utils__/file-review-projection.js +136 -0
  8. package/dist/__test-utils__/file-review-projection.js.map +1 -0
  9. package/dist/__test-utils__/harness-contract/types.d.ts +23 -1
  10. package/dist/__test-utils__/harness-contract/types.js +15 -0
  11. package/dist/__test-utils__/harness-contract/types.js.map +1 -1
  12. package/dist/__test-utils__/hermetic-activity.d.ts +44 -12
  13. package/dist/__test-utils__/hermetic-activity.js +52 -14
  14. package/dist/__test-utils__/hermetic-activity.js.map +1 -1
  15. package/dist/__test-utils__/model-registry-fixture.d.ts +32 -7
  16. package/dist/__test-utils__/model-registry-fixture.js +31 -7
  17. package/dist/__test-utils__/model-registry-fixture.js.map +1 -1
  18. package/dist/__test-utils__/turn-input-fixture.d.ts +1 -1
  19. package/dist/__test-utils__/turn-input-fixture.js +1 -1
  20. package/dist/__test-utils__/turn-input-fixture.js.map +1 -1
  21. package/dist/activities/call-agent.js +2 -2
  22. package/dist/activities/call-agent.js.map +1 -1
  23. package/dist/activities/execute-cursor/__test-utils__/contract-subject.js +45 -3
  24. package/dist/activities/execute-cursor/__test-utils__/contract-subject.js.map +1 -1
  25. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.d.ts +0 -9
  26. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js +2 -41
  27. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js.map +1 -1
  28. package/dist/activities/execute-cursor/adapter.d.ts +7 -5
  29. package/dist/activities/execute-cursor/adapter.js +7 -5
  30. package/dist/activities/execute-cursor/adapter.js.map +1 -1
  31. package/dist/activities/execute-cursor/approval-policy.d.ts +5 -2
  32. package/dist/activities/execute-cursor/approval-policy.js +5 -2
  33. package/dist/activities/execute-cursor/approval-policy.js.map +1 -1
  34. package/dist/activities/execute-cursor/approval-state.d.ts +16 -8
  35. package/dist/activities/execute-cursor/approval-state.js +6 -3
  36. package/dist/activities/execute-cursor/approval-state.js.map +1 -1
  37. package/dist/activities/execute-cursor/cas-observations.d.ts +14 -2
  38. package/dist/activities/execute-cursor/cas-observations.js +19 -2
  39. package/dist/activities/execute-cursor/cas-observations.js.map +1 -1
  40. package/dist/activities/execute-cursor/cursor-capabilities.d.ts +8 -4
  41. package/dist/activities/execute-cursor/cursor-capabilities.js +21 -4
  42. package/dist/activities/execute-cursor/cursor-capabilities.js.map +1 -1
  43. package/dist/activities/execute-cursor/message-translator.d.ts +12 -20
  44. package/dist/activities/execute-cursor/message-translator.js +19 -32
  45. package/dist/activities/execute-cursor/message-translator.js.map +1 -1
  46. package/dist/activities/execute-cursor/prompt-builder.d.ts +48 -58
  47. package/dist/activities/execute-cursor/prompt-builder.js +76 -95
  48. package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
  49. package/dist/activities/execute-cursor/turn-boundary.d.ts +27 -55
  50. package/dist/activities/execute-cursor/turn-boundary.js +30 -90
  51. package/dist/activities/execute-cursor/turn-boundary.js.map +1 -1
  52. package/dist/activities/execute-cursor/turn-settle.d.ts +11 -7
  53. package/dist/activities/execute-cursor/turn-settle.js +37 -49
  54. package/dist/activities/execute-cursor/turn-settle.js.map +1 -1
  55. package/dist/activities/execute-cursor/turn-setup.d.ts +16 -24
  56. package/dist/activities/execute-cursor/turn-setup.js +29 -59
  57. package/dist/activities/execute-cursor/turn-setup.js.map +1 -1
  58. package/dist/activities/execute-cursor/turn-stream.d.ts +3 -8
  59. package/dist/activities/execute-cursor/turn-stream.js +9 -22
  60. package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
  61. package/dist/activities/execute-cursor/turn.js +5 -1
  62. package/dist/activities/execute-cursor/turn.js.map +1 -1
  63. package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.d.ts +93 -0
  64. package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.js +348 -0
  65. package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.js.map +1 -0
  66. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.d.ts +170 -0
  67. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js +225 -0
  68. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js.map +1 -0
  69. package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.d.ts +24 -0
  70. package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js +41 -0
  71. package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js.map +1 -0
  72. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.d.ts +54 -0
  73. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js +72 -0
  74. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js.map +1 -0
  75. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.d.ts +187 -23
  76. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js +238 -27
  77. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js.map +1 -1
  78. package/dist/activities/execute-deep-agent/adapter.d.ts +41 -0
  79. package/dist/activities/execute-deep-agent/adapter.js +78 -0
  80. package/dist/activities/execute-deep-agent/adapter.js.map +1 -0
  81. package/dist/activities/execute-deep-agent/cas-capture-observer.d.ts +8 -0
  82. package/dist/activities/execute-deep-agent/cas-capture-observer.js +9 -0
  83. package/dist/activities/execute-deep-agent/cas-capture-observer.js.map +1 -1
  84. package/dist/activities/execute-deep-agent/deep-agent-capabilities.d.ts +31 -0
  85. package/dist/activities/execute-deep-agent/deep-agent-capabilities.js +40 -0
  86. package/dist/activities/execute-deep-agent/deep-agent-capabilities.js.map +1 -0
  87. package/dist/activities/execute-deep-agent/execution-state.d.ts +4 -11
  88. package/dist/activities/execute-deep-agent/execution-state.js +4 -12
  89. package/dist/activities/execute-deep-agent/execution-state.js.map +1 -1
  90. package/dist/activities/execute-deep-agent/hitl.d.ts +49 -47
  91. package/dist/activities/execute-deep-agent/hitl.js +77 -103
  92. package/dist/activities/execute-deep-agent/hitl.js.map +1 -1
  93. package/dist/activities/execute-deep-agent/prompt-builder.d.ts +51 -23
  94. package/dist/activities/execute-deep-agent/prompt-builder.js +115 -76
  95. package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
  96. package/dist/activities/execute-deep-agent/status-builder-shared.d.ts +18 -32
  97. package/dist/activities/execute-deep-agent/status-builder-shared.js +10 -65
  98. package/dist/activities/execute-deep-agent/status-builder-shared.js.map +1 -1
  99. package/dist/activities/execute-deep-agent/streaming-side-effects.d.ts +10 -8
  100. package/dist/activities/execute-deep-agent/streaming-side-effects.js +12 -14
  101. package/dist/activities/execute-deep-agent/streaming-side-effects.js.map +1 -1
  102. package/dist/activities/execute-deep-agent/subagent-tracker.d.ts +36 -13
  103. package/dist/activities/execute-deep-agent/subagent-tracker.js +76 -39
  104. package/dist/activities/execute-deep-agent/subagent-tracker.js.map +1 -1
  105. package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +25 -28
  106. package/dist/activities/execute-deep-agent/subagent-transformer.js +29 -82
  107. package/dist/activities/execute-deep-agent/subagent-transformer.js.map +1 -1
  108. package/dist/activities/execute-deep-agent/subagent-wiring.d.ts +3 -2
  109. package/dist/activities/execute-deep-agent/subagent-wiring.js +2 -2
  110. package/dist/activities/execute-deep-agent/subagent-wiring.js.map +1 -1
  111. package/dist/activities/execute-deep-agent/turn-settle.d.ts +42 -0
  112. package/dist/activities/execute-deep-agent/turn-settle.js +146 -0
  113. package/dist/activities/execute-deep-agent/turn-settle.js.map +1 -0
  114. package/dist/activities/execute-deep-agent/turn-setup.d.ts +212 -0
  115. package/dist/activities/execute-deep-agent/turn-setup.js +430 -0
  116. package/dist/activities/execute-deep-agent/turn-setup.js.map +1 -0
  117. package/dist/activities/execute-deep-agent/turn-stream.d.ts +97 -0
  118. package/dist/activities/execute-deep-agent/turn-stream.js +242 -0
  119. package/dist/activities/execute-deep-agent/turn-stream.js.map +1 -0
  120. package/dist/activities/execute-deep-agent/turn.d.ts +42 -0
  121. package/dist/activities/execute-deep-agent/turn.js +116 -0
  122. package/dist/activities/execute-deep-agent/turn.js.map +1 -0
  123. package/dist/activities/execute-deep-agent/v3-event-recorder.d.ts +6 -5
  124. package/dist/activities/execute-deep-agent/v3-event-recorder.js +6 -5
  125. package/dist/activities/execute-deep-agent/v3-event-recorder.js.map +1 -1
  126. package/dist/activities/execute-deep-agent/v3-events.d.ts +1 -1
  127. package/dist/activities/execute-deep-agent/v3-events.js +1 -1
  128. package/dist/activities/execute-deep-agent/v3-status-builder.d.ts +60 -17
  129. package/dist/activities/execute-deep-agent/v3-status-builder.js +72 -57
  130. package/dist/activities/execute-deep-agent/v3-status-builder.js.map +1 -1
  131. package/dist/harness/approval-decisions.d.ts +61 -0
  132. package/dist/harness/approval-decisions.js +102 -0
  133. package/dist/harness/approval-decisions.js.map +1 -0
  134. package/dist/harness/capabilities.d.ts +16 -5
  135. package/dist/harness/capabilities.js +9 -0
  136. package/dist/harness/capabilities.js.map +1 -1
  137. package/dist/harness/capture.d.ts +144 -0
  138. package/dist/harness/capture.js +219 -0
  139. package/dist/harness/capture.js.map +1 -0
  140. package/dist/harness/persist-chokepoint.d.ts +19 -4
  141. package/dist/harness/persist-chokepoint.js +17 -4
  142. package/dist/harness/persist-chokepoint.js.map +1 -1
  143. package/dist/harness/run-turn.js +115 -29
  144. package/dist/harness/run-turn.js.map +1 -1
  145. package/dist/harness/terminal-table.d.ts +40 -11
  146. package/dist/harness/terminal-table.js +58 -19
  147. package/dist/harness/terminal-table.js.map +1 -1
  148. package/dist/harness/turn-context.d.ts +141 -76
  149. package/dist/harness/turn-context.js +194 -99
  150. package/dist/harness/turn-context.js.map +1 -1
  151. package/dist/harness/types.d.ts +65 -12
  152. package/dist/harness/types.js +8 -2
  153. package/dist/harness/types.js.map +1 -1
  154. package/dist/harness-adapters.d.ts +12 -8
  155. package/dist/harness-adapters.js +17 -9
  156. package/dist/harness-adapters.js.map +1 -1
  157. package/dist/middleware/approval-gate.d.ts +1 -1
  158. package/dist/middleware/approval-gate.js +1 -1
  159. package/dist/middleware/approval-gate.js.map +1 -1
  160. package/dist/middleware/cost-advisory.d.ts +39 -0
  161. package/dist/middleware/{cost-cap.js → cost-advisory.js} +37 -55
  162. package/dist/middleware/cost-advisory.js.map +1 -0
  163. package/dist/middleware/index.d.ts +23 -12
  164. package/dist/middleware/index.js +26 -18
  165. package/dist/middleware/index.js.map +1 -1
  166. package/dist/middleware/types.d.ts +3 -2
  167. package/dist/runner-manager.js +1 -5
  168. package/dist/runner-manager.js.map +1 -1
  169. package/dist/runner.js +1 -5
  170. package/dist/runner.js.map +1 -1
  171. package/dist/shared/attachment-resolver.d.ts +41 -18
  172. package/dist/shared/attachment-resolver.js +178 -46
  173. package/dist/shared/attachment-resolver.js.map +1 -1
  174. package/dist/shared/attachment-zip.d.ts +85 -0
  175. package/dist/shared/attachment-zip.js +185 -0
  176. package/dist/shared/attachment-zip.js.map +1 -0
  177. package/dist/shared/connect-backfill.js +5 -4
  178. package/dist/shared/connect-backfill.js.map +1 -1
  179. package/dist/shared/cost-guard.d.ts +3 -3
  180. package/dist/shared/cost-guard.js +3 -3
  181. package/dist/shared/execution-status-writer.d.ts +5 -5
  182. package/dist/shared/execution-status-writer.js +5 -5
  183. package/dist/shared/extract-structured-output.d.ts +8 -7
  184. package/dist/shared/extract-structured-output.js +8 -7
  185. package/dist/shared/extract-structured-output.js.map +1 -1
  186. package/dist/shared/filereview/cas-progress.d.ts +1 -18
  187. package/dist/shared/filereview/cas-progress.js +4 -0
  188. package/dist/shared/filereview/cas-progress.js.map +1 -1
  189. package/dist/shared/filereview/cas-touched.d.ts +56 -0
  190. package/dist/shared/filereview/cas-touched.js +63 -0
  191. package/dist/shared/filereview/cas-touched.js.map +1 -0
  192. package/dist/shared/filereview/index.d.ts +2 -1
  193. package/dist/shared/filereview/index.js +2 -1
  194. package/dist/shared/filereview/index.js.map +1 -1
  195. package/dist/shared/mcp-resolver.d.ts +4 -5
  196. package/dist/shared/mcp-resolver.js +4 -5
  197. package/dist/shared/mcp-resolver.js.map +1 -1
  198. package/dist/shared/persist-decision.d.ts +3 -4
  199. package/dist/shared/persist-decision.js +3 -4
  200. package/dist/shared/persist-decision.js.map +1 -1
  201. package/dist/shared/plan-mode-permissions.d.ts +2 -2
  202. package/dist/shared/plan-mode-permissions.js +2 -2
  203. package/dist/shared/plan-mode-prompt.d.ts +1 -1
  204. package/dist/shared/plan-mode-prompt.js +1 -1
  205. package/dist/shared/prompt-sections.d.ts +163 -0
  206. package/dist/shared/prompt-sections.js +164 -0
  207. package/dist/shared/prompt-sections.js.map +1 -0
  208. package/dist/shared/skill-resolver.d.ts +4 -2
  209. package/dist/shared/skill-resolver.js +4 -2
  210. package/dist/shared/skill-resolver.js.map +1 -1
  211. package/dist/shared/tool-rounds.d.ts +32 -0
  212. package/dist/shared/tool-rounds.js +43 -0
  213. package/dist/shared/tool-rounds.js.map +1 -1
  214. package/dist/shared/tool-row.d.ts +34 -0
  215. package/dist/shared/tool-row.js +52 -0
  216. package/dist/shared/tool-row.js.map +1 -1
  217. package/dist/shared/workspace/session-provision.d.ts +3 -3
  218. package/dist/shared/workspace/session-provision.js +3 -3
  219. package/dist/shared/workspace/stigmer-link.d.ts +3 -3
  220. package/dist/shared/workspace/stigmer-link.js +3 -3
  221. package/dist/shared/workspace/writeback-coordinator.d.ts +15 -22
  222. package/dist/shared/workspace/writeback-coordinator.js +16 -53
  223. package/dist/shared/workspace/writeback-coordinator.js.map +1 -1
  224. package/dist/tools/index.d.ts +1 -1
  225. package/dist/tools/index.js +1 -1
  226. package/package.json +4 -4
  227. package/src/__test-utils__/__tests__/harness-contract-self-check.test.ts +1 -0
  228. package/src/__test-utils__/execution-record-fixture.ts +18 -2
  229. package/src/__test-utils__/file-review-projection.ts +156 -0
  230. package/src/__test-utils__/git-workspace-fixture.ts +58 -0
  231. package/src/__test-utils__/harness-boot-order-child.ts +7 -2
  232. package/src/__test-utils__/harness-contract/contract.ts +33 -20
  233. package/src/__test-utils__/harness-contract/recording-sink.ts +11 -1
  234. package/src/__test-utils__/harness-contract/runtime-contract.ts +328 -10
  235. package/src/__test-utils__/harness-contract/scripted-adapter.ts +38 -6
  236. package/src/__test-utils__/harness-contract/types.ts +27 -3
  237. package/src/__test-utils__/hermetic-activity.ts +52 -14
  238. package/src/__test-utils__/model-registry-fixture.ts +32 -7
  239. package/src/__test-utils__/module-specifiers.ts +24 -0
  240. package/src/__test-utils__/turn-input-fixture.ts +2 -2
  241. package/src/__tests__/harness-boot-order.test.ts +9 -2
  242. package/src/activities/call-agent.ts +2 -2
  243. package/src/activities/execute-cursor/__test-utils__/contract-subject.ts +47 -3
  244. package/src/activities/execute-cursor/__test-utils__/hermetic-cursor.ts +2 -48
  245. package/src/activities/execute-cursor/__tests__/approval-decisions-agree.test.ts +1 -1
  246. package/src/activities/execute-cursor/__tests__/approval-gate.test.ts +6 -1
  247. package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +52 -27
  248. package/src/activities/execute-cursor/__tests__/cas-observations.test.ts +25 -0
  249. package/src/activities/execute-cursor/__tests__/goldens/prompt.enhanced.everything.prompt.md +166 -0
  250. package/src/activities/execute-cursor/__tests__/goldens/prompt.enhanced.plan-mode.prompt.md +186 -0
  251. package/src/activities/execute-cursor/__tests__/goldens/prompt.hitl.recovery.prompt.md +191 -0
  252. package/src/activities/execute-cursor/__tests__/goldens/prompt.hitl.reinvocation.prompt.md +13 -0
  253. package/src/activities/execute-cursor/__tests__/goldens/prompt.resumed.prefixed.prompt.md +32 -0
  254. package/src/activities/execute-cursor/__tests__/goldens/prompt.resumed.raw.prompt.md +1 -0
  255. package/src/activities/execute-cursor/__tests__/hermetic/file-review-capture.test.ts +1 -2
  256. package/src/activities/execute-cursor/__tests__/hermetic/goldens/sdk-error-at-create.status.json +4 -0
  257. package/src/activities/execute-cursor/__tests__/hermetic/harness-contract.test.ts +24 -4
  258. package/src/activities/execute-cursor/__tests__/hermetic/stream-self-stop-arms.test.ts +6 -5
  259. package/src/activities/execute-cursor/__tests__/hermetic/thrown-error-arms.test.ts +9 -0
  260. package/src/activities/execute-cursor/__tests__/hitl-resume-history.test.ts +11 -8
  261. package/src/activities/execute-cursor/__tests__/prompt-goldens.test.ts +229 -0
  262. package/src/activities/execute-cursor/__tests__/same-identity-reproposal.test.ts +3 -3
  263. package/src/activities/execute-cursor/__tests__/sequential-gate-resume.test.ts +2 -2
  264. package/src/activities/execute-cursor/__tests__/turn-boundary.test.ts +78 -234
  265. package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +1 -26
  266. package/src/activities/execute-cursor/adapter.ts +7 -5
  267. package/src/activities/execute-cursor/approval-policy.ts +5 -2
  268. package/src/activities/execute-cursor/approval-state.ts +16 -8
  269. package/src/activities/execute-cursor/cas-observations.ts +20 -2
  270. package/src/activities/execute-cursor/cursor-capabilities.ts +24 -5
  271. package/src/activities/execute-cursor/message-translator.ts +29 -41
  272. package/src/activities/execute-cursor/prompt-builder.ts +99 -157
  273. package/src/activities/execute-cursor/turn-boundary.ts +34 -140
  274. package/src/activities/execute-cursor/turn-settle.ts +37 -51
  275. package/src/activities/execute-cursor/turn-setup.ts +30 -70
  276. package/src/activities/execute-cursor/turn-stream.ts +8 -31
  277. package/src/activities/execute-cursor/turn.ts +5 -1
  278. package/src/activities/execute-deep-agent/__test-utils__/contract-subject.ts +391 -0
  279. package/src/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.ts +313 -0
  280. package/src/activities/execute-deep-agent/__test-utils__/hitl-script.ts +48 -0
  281. package/src/activities/execute-deep-agent/__test-utils__/scripted-model-module.ts +85 -0
  282. package/src/activities/execute-deep-agent/__test-utils__/scripted-model.ts +383 -36
  283. package/src/activities/execute-deep-agent/__tests__/adapter-graph-is-sdk-free.test.ts +76 -0
  284. package/src/activities/execute-deep-agent/__tests__/adapter-is-temporal-free.test.ts +47 -0
  285. package/src/activities/execute-deep-agent/__tests__/adapter.test.ts +80 -0
  286. package/src/activities/execute-deep-agent/__tests__/cas-capture-backend.test.ts +1 -1
  287. package/src/activities/execute-deep-agent/__tests__/execution-state-extended.test.ts +0 -2
  288. package/src/activities/execute-deep-agent/__tests__/execution-state.test.ts +0 -3
  289. package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.build-from-plan.prompt.md +172 -0
  290. package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.everything.prompt.md +167 -0
  291. package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.minimal.prompt.md +36 -0
  292. package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.plan-mode.prompt.md +178 -0
  293. package/src/activities/execute-deep-agent/__tests__/goldens/system-prompt.skills-below-threshold.prompt.md +158 -0
  294. package/src/activities/execute-deep-agent/__tests__/hermetic/file-review-capture.test.ts +210 -0
  295. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn1.status.json +74 -0
  296. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn2.status.json +104 -0
  297. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve.turn2.status.json +78 -0
  298. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/file-review-capture.status.json +138 -0
  299. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/gate.turn1.status.json +68 -0
  300. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn1.status.json +154 -0
  301. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn2.status.json +116 -0
  302. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.after-tool.status.json +69 -0
  303. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.mid-tool.status.json +67 -0
  304. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/plain-turn.status.json +47 -0
  305. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/platform-stop.status.json +68 -0
  306. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/recursion-limit.persisted.status.json +280 -0
  307. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/reject.turn2.status.json +77 -0
  308. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/resolution-error.status.json +18 -0
  309. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn2.status.json +99 -0
  310. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn3.status.json +109 -0
  311. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/skip.turn2.status.json +76 -0
  312. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/structured-output.text-fallback.status.json +51 -0
  313. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/structured-output.tier2.status.json +51 -0
  314. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/structured-output.tool-strategy.status.json +56 -0
  315. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sub-agent-delegation.status.json +90 -0
  316. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/tool-call.status.json +70 -0
  317. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/worker-shutdown.status.json +71 -0
  318. package/src/activities/execute-deep-agent/__tests__/hermetic/harness-contract.test.ts +144 -0
  319. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-approve-all-lease.test.ts +184 -0
  320. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-round-trips.test.ts +203 -0
  321. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-sequential-gates.test.ts +170 -0
  322. package/src/activities/execute-deep-agent/__tests__/hermetic/inline-artifact-across-gate.test.ts +175 -0
  323. package/src/activities/execute-deep-agent/__tests__/hermetic/pause-vs-shutdown.test.ts +206 -0
  324. package/src/activities/execute-deep-agent/__tests__/hermetic/plain-turn.test.ts +142 -0
  325. package/src/activities/execute-deep-agent/__tests__/hermetic/platform-stop.test.ts +126 -0
  326. package/src/activities/execute-deep-agent/__tests__/hermetic/recursion-limit.test.ts +139 -0
  327. package/src/activities/execute-deep-agent/__tests__/hermetic/resolution-error.test.ts +122 -0
  328. package/src/activities/execute-deep-agent/__tests__/hermetic/structured-output.test.ts +236 -0
  329. package/src/activities/execute-deep-agent/__tests__/hermetic/sub-agent-delegation.test.ts +161 -0
  330. package/src/activities/execute-deep-agent/__tests__/hermetic/tool-call.test.ts +157 -0
  331. package/src/activities/execute-deep-agent/__tests__/hermetic/workspace-lock-timeout.test.ts +152 -0
  332. package/src/activities/execute-deep-agent/__tests__/hitl.test.ts +50 -122
  333. package/src/activities/execute-deep-agent/__tests__/inline-publisher.test.ts +8 -6
  334. package/src/activities/execute-deep-agent/__tests__/plan-mode-path-normalization.test.ts +2 -2
  335. package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +35 -35
  336. package/src/activities/execute-deep-agent/__tests__/prompt-goldens.test.ts +247 -0
  337. package/src/activities/execute-deep-agent/__tests__/scripted-model.test.ts +329 -0
  338. package/src/activities/execute-deep-agent/__tests__/status-builder-shared.test.ts +1 -20
  339. package/src/activities/execute-deep-agent/__tests__/streaming-side-effects.test.ts +78 -0
  340. package/src/activities/execute-deep-agent/__tests__/subagent-gitignored-capture.test.ts +1 -1
  341. package/src/activities/execute-deep-agent/__tests__/subagent-plan-mode-permissions.test.ts +2 -2
  342. package/src/activities/execute-deep-agent/__tests__/subagent-tracker.test.ts +57 -31
  343. package/src/activities/execute-deep-agent/__tests__/subagent-transformer.test.ts +19 -79
  344. package/src/activities/execute-deep-agent/__tests__/subagent-wiring.test.ts +15 -15
  345. package/src/activities/execute-deep-agent/__tests__/summarization-verification.test.ts +1 -1
  346. package/src/activities/execute-deep-agent/__tests__/turn-stream.test.ts +391 -0
  347. package/src/activities/execute-deep-agent/__tests__/v3-status-builder.test.ts +343 -38
  348. package/src/activities/execute-deep-agent/__tests__/vision-input.test.ts +5 -5
  349. package/src/activities/execute-deep-agent/adapter.ts +94 -0
  350. package/src/activities/execute-deep-agent/cas-capture-observer.ts +11 -0
  351. package/src/activities/execute-deep-agent/deep-agent-capabilities.ts +43 -0
  352. package/src/activities/execute-deep-agent/execution-state.ts +4 -13
  353. package/src/activities/execute-deep-agent/hitl.ts +100 -123
  354. package/src/activities/execute-deep-agent/prompt-builder.ts +141 -115
  355. package/src/activities/execute-deep-agent/status-builder-shared.ts +21 -84
  356. package/src/activities/execute-deep-agent/streaming-side-effects.ts +13 -19
  357. package/src/activities/execute-deep-agent/subagent-tracker.ts +77 -42
  358. package/src/activities/execute-deep-agent/subagent-transformer.ts +46 -105
  359. package/src/activities/execute-deep-agent/subagent-wiring.ts +5 -4
  360. package/src/activities/execute-deep-agent/turn-settle.ts +164 -0
  361. package/src/activities/execute-deep-agent/turn-setup.ts +541 -0
  362. package/src/activities/execute-deep-agent/turn-stream.ts +313 -0
  363. package/src/activities/execute-deep-agent/turn.ts +131 -0
  364. package/src/activities/execute-deep-agent/v3-event-recorder.ts +6 -5
  365. package/src/activities/execute-deep-agent/v3-events.ts +1 -1
  366. package/src/activities/execute-deep-agent/v3-status-builder.ts +84 -63
  367. package/src/harness/__tests__/approval-decisions.test.ts +116 -0
  368. package/src/harness/__tests__/capture.test.ts +268 -0
  369. package/src/harness/__tests__/mount-skills.test.ts +169 -0
  370. package/src/harness/__tests__/persist-chokepoint.test.ts +38 -2
  371. package/src/harness/__tests__/run-turn-deterministic.test.ts +94 -0
  372. package/src/harness/__tests__/run-turn.test.ts +39 -23
  373. package/src/harness/__tests__/turn-attachments-vision.test.ts +80 -0
  374. package/src/harness/__tests__/turn-context.test.ts +73 -26
  375. package/src/harness/approval-decisions.ts +104 -0
  376. package/src/harness/capabilities.ts +16 -5
  377. package/src/harness/capture.ts +301 -0
  378. package/src/harness/persist-chokepoint.ts +24 -4
  379. package/src/harness/run-turn.ts +120 -29
  380. package/src/harness/terminal-table.ts +61 -20
  381. package/src/harness/turn-context.ts +208 -111
  382. package/src/harness/types.ts +66 -12
  383. package/src/harness-adapters.ts +17 -9
  384. package/src/middleware/__tests__/approval-gate.test.ts +1 -1
  385. package/src/middleware/__tests__/cost-advisory.test.ts +113 -0
  386. package/src/middleware/approval-gate.ts +2 -2
  387. package/src/middleware/{cost-cap.ts → cost-advisory.ts} +40 -70
  388. package/src/middleware/index.ts +29 -29
  389. package/src/middleware/types.ts +3 -2
  390. package/src/runner-manager.ts +0 -8
  391. package/src/runner.ts +0 -8
  392. package/src/shared/__tests__/attachment-naming.test.ts +6 -19
  393. package/src/shared/__tests__/attachment-resolver.test.ts +158 -8
  394. package/src/shared/__tests__/attachment-zip.test.ts +236 -0
  395. package/src/shared/__tests__/bedrock-adapter.test.ts +1 -1
  396. package/src/shared/__tests__/blueprint-resolver.test.ts +43 -0
  397. package/src/shared/__tests__/cost-guard.test.ts +3 -3
  398. package/src/shared/__tests__/prompt-sections.test.ts +167 -0
  399. package/src/shared/__tests__/secret-leak-scan.test.ts +2 -2
  400. package/src/{activities/execute-deep-agent → shared}/__tests__/stamp-flowed-rows.test.ts +33 -10
  401. package/src/shared/__tests__/vertex-adapter.test.ts +1 -1
  402. package/src/shared/attachment-resolver.ts +218 -55
  403. package/src/shared/attachment-zip.ts +281 -0
  404. package/src/shared/connect-backfill.ts +9 -11
  405. package/src/shared/cost-guard.ts +3 -3
  406. package/src/shared/execution-status-writer.ts +5 -5
  407. package/src/shared/extract-structured-output.ts +8 -7
  408. package/src/shared/filereview/__tests__/capture.test.ts +86 -4
  409. package/src/shared/filereview/__tests__/cas-progress.test.ts +2 -1
  410. package/src/shared/filereview/cas-progress.ts +5 -19
  411. package/src/shared/filereview/cas-touched.ts +89 -0
  412. package/src/shared/filereview/index.ts +4 -2
  413. package/src/shared/mcp-resolver.ts +4 -5
  414. package/src/shared/persist-decision.ts +3 -4
  415. package/src/shared/plan-mode-permissions.ts +2 -2
  416. package/src/shared/plan-mode-prompt.ts +1 -1
  417. package/src/shared/prompt-sections.ts +256 -0
  418. package/src/shared/skill-resolver.ts +4 -2
  419. package/src/shared/tool-rounds.ts +48 -0
  420. package/src/shared/tool-row.ts +61 -0
  421. package/src/shared/workspace/__tests__/stigmer-link.test.ts +7 -22
  422. package/src/shared/workspace/__tests__/writeback-coordinator.test.ts +20 -61
  423. package/src/shared/workspace/session-provision.ts +3 -3
  424. package/src/shared/workspace/stigmer-link.ts +3 -3
  425. package/src/shared/workspace/writeback-coordinator.ts +16 -64
  426. package/src/tools/index.ts +1 -1
  427. package/dist/activities/execute-cursor/capture-flow.d.ts +0 -142
  428. package/dist/activities/execute-cursor/capture-flow.js +0 -285
  429. package/dist/activities/execute-cursor/capture-flow.js.map +0 -1
  430. package/dist/activities/execute-cursor/command-provenance.d.ts +0 -48
  431. package/dist/activities/execute-cursor/command-provenance.js +0 -38
  432. package/dist/activities/execute-cursor/command-provenance.js.map +0 -1
  433. package/dist/activities/execute-deep-agent/attachment-injector.d.ts +0 -134
  434. package/dist/activities/execute-deep-agent/attachment-injector.js +0 -386
  435. package/dist/activities/execute-deep-agent/attachment-injector.js.map +0 -1
  436. package/dist/activities/execute-deep-agent/command-provenance.d.ts +0 -61
  437. package/dist/activities/execute-deep-agent/command-provenance.js +0 -72
  438. package/dist/activities/execute-deep-agent/command-provenance.js.map +0 -1
  439. package/dist/activities/execute-deep-agent/environment.d.ts +0 -24
  440. package/dist/activities/execute-deep-agent/environment.js +0 -58
  441. package/dist/activities/execute-deep-agent/environment.js.map +0 -1
  442. package/dist/activities/execute-deep-agent/event-recorder.d.ts +0 -21
  443. package/dist/activities/execute-deep-agent/event-recorder.js +0 -67
  444. package/dist/activities/execute-deep-agent/event-recorder.js.map +0 -1
  445. package/dist/activities/execute-deep-agent/index.d.ts +0 -15
  446. package/dist/activities/execute-deep-agent/index.js +0 -918
  447. package/dist/activities/execute-deep-agent/index.js.map +0 -1
  448. package/dist/activities/execute-deep-agent/mcp-gate.d.ts +0 -28
  449. package/dist/activities/execute-deep-agent/mcp-gate.js +0 -22
  450. package/dist/activities/execute-deep-agent/mcp-gate.js.map +0 -1
  451. package/dist/activities/execute-deep-agent/post-stream.d.ts +0 -23
  452. package/dist/activities/execute-deep-agent/post-stream.js +0 -71
  453. package/dist/activities/execute-deep-agent/post-stream.js.map +0 -1
  454. package/dist/activities/execute-deep-agent/setup.d.ts +0 -136
  455. package/dist/activities/execute-deep-agent/setup.js +0 -767
  456. package/dist/activities/execute-deep-agent/setup.js.map +0 -1
  457. package/dist/activities/execute-deep-agent/stamp-flowed-rows.d.ts +0 -36
  458. package/dist/activities/execute-deep-agent/stamp-flowed-rows.js +0 -56
  459. package/dist/activities/execute-deep-agent/stamp-flowed-rows.js.map +0 -1
  460. package/dist/activities/execute-deep-agent/status-builder.d.ts +0 -93
  461. package/dist/activities/execute-deep-agent/status-builder.js +0 -365
  462. package/dist/activities/execute-deep-agent/status-builder.js.map +0 -1
  463. package/dist/activities/execute-deep-agent/streaming-terminal.d.ts +0 -21
  464. package/dist/activities/execute-deep-agent/streaming-terminal.js +0 -80
  465. package/dist/activities/execute-deep-agent/streaming-terminal.js.map +0 -1
  466. package/dist/activities/execute-deep-agent/streaming-v3.d.ts +0 -13
  467. package/dist/activities/execute-deep-agent/streaming-v3.js +0 -174
  468. package/dist/activities/execute-deep-agent/streaming-v3.js.map +0 -1
  469. package/dist/activities/execute-deep-agent/streaming.d.ts +0 -81
  470. package/dist/activities/execute-deep-agent/streaming.js +0 -160
  471. package/dist/activities/execute-deep-agent/streaming.js.map +0 -1
  472. package/dist/middleware/cost-cap.d.ts +0 -22
  473. package/dist/middleware/cost-cap.js.map +0 -1
  474. package/dist/middleware/graceful-stop.d.ts +0 -17
  475. package/dist/middleware/graceful-stop.js +0 -63
  476. package/dist/middleware/graceful-stop.js.map +0 -1
  477. package/dist/shared/skill-writer.d.ts +0 -75
  478. package/dist/shared/skill-writer.js +0 -207
  479. package/dist/shared/skill-writer.js.map +0 -1
  480. package/src/activities/execute-cursor/__tests__/capture-flow.test.ts +0 -1032
  481. package/src/activities/execute-cursor/__tests__/command-provenance.test.ts +0 -240
  482. package/src/activities/execute-cursor/__tests__/progress-substrate.test.ts +0 -169
  483. package/src/activities/execute-cursor/capture-flow.ts +0 -379
  484. package/src/activities/execute-cursor/command-provenance.ts +0 -73
  485. package/src/activities/execute-deep-agent/__tests__/attachment-injector.test.ts +0 -1161
  486. package/src/activities/execute-deep-agent/__tests__/command-provenance.test.ts +0 -252
  487. package/src/activities/execute-deep-agent/__tests__/environment.test.ts +0 -108
  488. package/src/activities/execute-deep-agent/__tests__/event-recorder.test.ts +0 -150
  489. package/src/activities/execute-deep-agent/__tests__/hitl-integration.test.ts +0 -226
  490. package/src/activities/execute-deep-agent/__tests__/hitl-reject.test.ts +0 -318
  491. package/src/activities/execute-deep-agent/__tests__/hitl-resume-approve-all.test.ts +0 -351
  492. package/src/activities/execute-deep-agent/__tests__/hitl-resume-history.test.ts +0 -293
  493. package/src/activities/execute-deep-agent/__tests__/index.test.ts +0 -99
  494. package/src/activities/execute-deep-agent/__tests__/mcp-gate.test.ts +0 -44
  495. package/src/activities/execute-deep-agent/__tests__/post-stream.test.ts +0 -112
  496. package/src/activities/execute-deep-agent/__tests__/sequential-gate-resume.test.ts +0 -358
  497. package/src/activities/execute-deep-agent/__tests__/status-builder.test.ts +0 -1933
  498. package/src/activities/execute-deep-agent/__tests__/streaming-terminal.test.ts +0 -40
  499. package/src/activities/execute-deep-agent/__tests__/streaming-v3.test.ts +0 -597
  500. package/src/activities/execute-deep-agent/__tests__/streaming.test.ts +0 -508
  501. package/src/activities/execute-deep-agent/attachment-injector.ts +0 -627
  502. package/src/activities/execute-deep-agent/command-provenance.ts +0 -102
  503. package/src/activities/execute-deep-agent/environment.ts +0 -76
  504. package/src/activities/execute-deep-agent/event-recorder.ts +0 -95
  505. package/src/activities/execute-deep-agent/index.ts +0 -1072
  506. package/src/activities/execute-deep-agent/mcp-gate.ts +0 -37
  507. package/src/activities/execute-deep-agent/post-stream.ts +0 -109
  508. package/src/activities/execute-deep-agent/setup.ts +0 -1081
  509. package/src/activities/execute-deep-agent/stamp-flowed-rows.ts +0 -64
  510. package/src/activities/execute-deep-agent/status-builder.ts +0 -481
  511. package/src/activities/execute-deep-agent/streaming-terminal.ts +0 -106
  512. package/src/activities/execute-deep-agent/streaming-v3.ts +0 -277
  513. package/src/activities/execute-deep-agent/streaming.ts +0 -313
  514. package/src/middleware/__tests__/cost-cap.test.ts +0 -192
  515. package/src/middleware/__tests__/graceful-stop.test.ts +0 -105
  516. package/src/middleware/graceful-stop.ts +0 -86
  517. package/src/shared/__tests__/skill-writer.test.ts +0 -372
  518. package/src/shared/skill-writer.ts +0 -266
@@ -1,918 +0,0 @@
1
- /**
2
- * ExecuteDeepAgent activity — runs a Stigmer deep agent via LangGraph.
3
- *
4
- * Signature matches ExecuteGraphton (Python): (executionId, threadId) → status.
5
- * The slim-payload pattern is preserved: input is just IDs, output is a slim
6
- * AgentExecutionStatus proto.
7
- *
8
- * Phase 3b-iii: full middleware stack + artifact storage, inline publishing,
9
- * incremental git writeback, and post-stream safety net.
10
- */
11
- import { readFile } from "node:fs/promises";
12
- import { join } from "node:path";
13
- import { Context, CancelledFailure } from "@temporalio/activity";
14
- import { create, clone } from "@bufbuild/protobuf";
15
- import { AgentExecutionStatusSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
16
- import { AgentMessageSchema, ToolCallSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/message_pb";
17
- import { ExecutionPhase, FileCaptureClass, FileChangeSetStatus, InteractionMode, MessageType, ToolCallStatus } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
18
- import { activityStarted, activityFinished } from "../../idle-watchdog.js";
19
- import { normalizeActivityInput } from "../../shared/activity-input.js";
20
- import { persistStatus, reportSetupProgress, slimStatus, utcTimestamp } from "../../shared/status.js";
21
- import { acquireWorkspaceLock, WorkspaceLockCancelledError, WorkspaceLockTimeoutError, } from "../../shared/workspace/workspace-lock.js";
22
- import { ensureStigmerSymlink, removeStigmerSymlink, } from "../../shared/workspace/stigmer-link.js";
23
- import { publishPlanArtifact } from "../../shared/plan-artifact.js";
24
- import { classifyTool } from "../../shared/tool-kind.js";
25
- import { POLICY_ENGINE_VERSION, toProtoPolicySource, } from "../../shared/approval-policy.js";
26
- import { StigmerClient } from "../../client/stigmer-client.js";
27
- import { performSetup } from "./setup.js";
28
- import { streamExecution } from "./streaming.js";
29
- import { loadStreamingConfig } from "../../shared/streaming-scheduler.js";
30
- import { StatusBuilder } from "./status-builder.js";
31
- import { InlinePublisher } from "./inline-publisher.js";
32
- import { WriteBackCoordinator } from "../../shared/workspace/writeback-coordinator.js";
33
- import { processPostStream } from "./post-stream.js";
34
- import { resolveResumeInput, reconcileNonExecutingDecisions, reconcileUnattendedSkips } from "./hitl.js";
35
- import { captureApprovalArtifacts } from "./approval-file-change.js";
36
- import { applyCaptureDecisions, captureBaselineToLedger, captureCandidateToLedger, } from "../../shared/filereview/capture.js";
37
- import { captureFileChangeProgress, createGitProgressSubstrate, createHybridProgressSubstrate, newProgressCaptureState, } from "../../shared/filereview/progress.js";
38
- import { createCasProgressSubstrate, } from "../../shared/filereview/cas-progress.js";
39
- import { hasCandidateCaptured } from "../../shared/filereview/events.js";
40
- import { casBlobReader } from "../../shared/filereview/cas-substrate.js";
41
- import { partitionIgnoredPathsBySecret } from "../../shared/filereview/secret-paths.js";
42
- import { collectSettledToolCallIds, collectSubAgentToolCallIds, withholdSecretContentFromMessages, } from "../../shared/tool-row.js";
43
- import { stampFlowedFileEditRows, stampFlowedSubAgentFileEditRows } from "./stamp-flowed-rows.js";
44
- import { deriveTurnCommandProvenance } from "./command-provenance.js";
45
- import { describeExecutionError } from "../../shared/model-error.js";
46
- import { inferProvider } from "../../shared/llm-proxy.js";
47
- import { getShutdownSignalForQueue } from "../../shared/worker-shutdown.js";
48
- /** The harness id stamped on the deep-agent's file-review ledger events. */
49
- const DEEP_AGENT_HARNESS_ID = "deep-agent";
50
- /**
51
- * The worker-shutdown terminal status (#776). A shutdown is not a pause: the
52
- * execution will not resume on this worker, so persisting PAUSED would strand
53
- * the user with a lie. The copy is byte-identical to the Cursor harness's
54
- * worker-shutdown branch so every downstream status.error consumer (the Go and
55
- * Java workflow fallbacks, the cloud channel decision table) keys on ONE shape.
56
- */
57
- function buildWorkerShutdownStatus() {
58
- return create(AgentExecutionStatusSchema, {
59
- phase: ExecutionPhase.EXECUTION_FAILED,
60
- error: "Execution interrupted: runner worker was shut down. Retry or resume.",
61
- completedAt: utcTimestamp(),
62
- messages: [
63
- create(AgentMessageSchema, {
64
- type: MessageType.MESSAGE_SYSTEM,
65
- content: "Execution interrupted: the runner worker was shut down while the agent was still running. You can retry or resume.",
66
- timestamp: utcTimestamp(),
67
- }),
68
- ],
69
- });
70
- }
71
- /**
72
- * Best-effort provider inference for error-message wording. inferProvider
73
- * throws on unrecognized names; an error path must never throw over a label.
74
- */
75
- function tryInferProvider(modelName) {
76
- try {
77
- return inferProvider(modelName);
78
- }
79
- catch {
80
- return undefined;
81
- }
82
- }
83
- export function createDeepAgentActivities(config) {
84
- const client = new StigmerClient({
85
- endpoint: config.stigmerBackendEndpoint,
86
- token: config.stigmerToken,
87
- tokenRef: config.stigmerTokenRef,
88
- runnerTokenRef: config.stigmerRunnerTokenRef,
89
- });
90
- const streamingConfig = loadStreamingConfig();
91
- return {
92
- // Accepts the new typed object OR the legacy positional args (transitional
93
- // dual-shape so the runner can deploy before the control planes — see
94
- // shared/activity-input.ts). Drop the positional arm once both control
95
- // planes send the object.
96
- ExecuteDeepAgent: async (arg0, arg1) => {
97
- const { executionId, threadId, turnSeq } = normalizeActivityInput(arg0, arg1);
98
- activityStarted();
99
- // Worker-shutdown classification channel (#776): the pause paths below
100
- // consult this signal to distinguish "my worker is draining" (SIGTERM,
101
- // desktop quit) from "the orchestrator cancelled me" (a real user
102
- // pause). See shared/worker-shutdown.ts for the ownership contract.
103
- const shutdownSignal = getShutdownSignalForQueue(Context.current().info.taskQueue);
104
- let setup = null;
105
- // Exclusive turn lock on the workspace working tree — held across the
106
- // entire tree-mutating window (decision reconcile, agent writes,
107
- // candidate capture, write-back) and released in the finally. Mirrors
108
- // the Cursor harness; see shared/workspace/workspace-lock.ts.
109
- let releaseWorkspaceLock;
110
- try {
111
- console.log(`[ExecuteDeepAgent] Started for execution ${executionId}`);
112
- setup = await performSetup({ config, client, executionId, threadId });
113
- // Single offload context for every persist in this execution: spill
114
- // oversized tool outputs (e.g. computer-use screenshots) to artifact
115
- // storage so the UI can render them, and keep the status under the
116
- // gRPC cap. Threaded into the streaming loop and reused for the
117
- // terminal persists below so the guard is never skipped. Undefined when
118
- // there is no artifact store (proxy misconfig): offload is then disabled,
119
- // but persistStatus still enforces the aggregate size cap, so persistence
120
- // can never silently blow past the gRPC limit.
121
- const statusOffload = setup.artifactStorage
122
- ? { artifactStorage: setup.artifactStorage, executionId }
123
- : undefined;
124
- // Read the graph checkpoint once, to resolve how a pending approval
125
- // interrupt continues (Command(resume) vs a fresh replay). Reading once
126
- // avoids a redundant round-trip on the durable (http) saver.
127
- const graphState = await setup.agentGraph.getState(setup.langgraphConfig);
128
- // Seed from the persisted transcript whenever the execution already has
129
- // committed history, so streamed deltas append onto it instead of
130
- // replacing it. This holds for every re-invocation — durable resume and
131
- // memory-checkpointer replay alike — and is a no-op on a first run.
132
- const initialStatus = shouldSeedFromPersistedTranscript(setup.execution)
133
- ? seedStatusFromExecution(setup.execution)
134
- : create(AgentExecutionStatusSchema, {});
135
- // The semantic retriever's injection outcome (DD-008 D5), computed at
136
- // prompt build in setup Step 8. Stamped here — before the first
137
- // persist — because setup predates this status object; the server's
138
- // presence-guarded merge preserves it across report-less writes. On a
139
- // re-invocation the seeded status already carries the (replayed)
140
- // report, so this stamp is idempotent by construction.
141
- if (setup.recalledMemoriesReport !== undefined) {
142
- initialStatus.recalledMemoriesReport = setup.recalledMemoriesReport;
143
- }
144
- const statusBuilder = new StatusBuilder(executionId, initialStatus);
145
- statusBuilder.setApprovalProvider({
146
- policies: setup.approvalPolicies,
147
- toolServerMap: setup.toolServerMap,
148
- leasedCategories: setup.leasedCategories,
149
- globalBypass: setup.globalBypass,
150
- unattended: setup.unattended,
151
- });
152
- const resume = resolveResumeInput(setup.execution, graphState);
153
- // Not an approval resume -> setup.langgraphInput, the single
154
- // construction site of the turn's user message (string or multimodal
155
- // content blocks when the turn carries inline images).
156
- const effectiveInput = resume.isResumeFromApproval
157
- ? resume.graphInput
158
- : setup.langgraphInput;
159
- const inlinePublisher = new InlinePublisher({
160
- workspaceBackend: setup.workspaceBackend,
161
- artifactStorage: setup.artifactStorage,
162
- statusWriter: statusBuilder,
163
- executionId,
164
- });
165
- const workspaceEntries = setup.session.spec?.workspaceEntries ?? [];
166
- const writebackCoordinator = setup.provisionResults.length > 0
167
- ? new WriteBackCoordinator({
168
- statusWriter: statusBuilder,
169
- executionId,
170
- // Branch/PR are session-scoped: every turn of this session
171
- // appends commits to the same stigmer/<session-id> branch.
172
- sessionId: setup.session.metadata?.id ?? "",
173
- // The PR API token, plumbed from the resolved execution env —
174
- // gitMetadata.repoUrl is token-stripped by construction, so the
175
- // coordinator can never recover it from provisioning state.
176
- githubToken: setup.mergedEnvVars.GITHUB_TOKEN ?? "",
177
- provisionResults: setup.provisionResults,
178
- workspaceEntries: workspaceEntries,
179
- workspaceBackend: setup.workspaceBackend,
180
- })
181
- : null;
182
- // Apply-then-review capture identity + substrate root for this turn.
183
- const gitRoot = setup.workspaceBackend.rootDir;
184
- const changeSetId = `${executionId}:${turnSeq}`;
185
- // Serialize this turn against every other execution sharing this
186
- // working tree — an unserialized concurrent write lands inside this
187
- // turn's baseline→candidate window and gets misattributed to this
188
- // turn's review. Acquired before ANY tree mutation below (decision
189
- // reconcile, agent writes, candidate capture, write-back); waiting
190
- // surfaces a visible state and heartbeats, and a cancel aborts the
191
- // wait immediately. Mirrors the Cursor harness wiring exactly.
192
- try {
193
- releaseWorkspaceLock = await acquireWorkspaceLock(gitRoot, {
194
- onWaiting: () => reportSetupProgress(client, executionId, "Waiting for workspace — in use by another session"),
195
- heartbeat: () => Context.current().heartbeat(),
196
- signal: Context.current().cancellationSignal,
197
- timeoutMs: config.workspaceLockTimeoutMs,
198
- });
199
- }
200
- catch (lockErr) {
201
- if (lockErr instanceof WorkspaceLockCancelledError) {
202
- throw new CancelledFailure("Activity cancelled while waiting for the workspace lock");
203
- }
204
- if (lockErr instanceof WorkspaceLockTimeoutError) {
205
- const failedStatus = create(AgentExecutionStatusSchema, {
206
- phase: ExecutionPhase.EXECUTION_FAILED,
207
- error: lockErr.message,
208
- completedAt: utcTimestamp(),
209
- messages: [
210
- create(AgentMessageSchema, {
211
- type: MessageType.MESSAGE_SYSTEM,
212
- content: `Execution failed: ${lockErr.message}`,
213
- timestamp: utcTimestamp(),
214
- }),
215
- ],
216
- });
217
- await persistStatus(client, executionId, failedStatus, { offload: statusOffload });
218
- return slimStatus(failedStatus);
219
- }
220
- throw lockErr;
221
- }
222
- // Bridge the workspace to the session's platform dir so the agent's
223
- // file tools can read platform-mounted content (`.stigmer/inputs/…`
224
- // attachments incl. the approved plan, `.stigmer/skills/…`) — the
225
- // deepagents FilesystemBackend resolves paths against the workspace
226
- // root and knows nothing of the LocalWorkspaceBackend's `.stigmer`
227
- // routing. Two ordering invariants (see shared/workspace/stigmer-link.ts):
228
- // - AFTER the lock: the link is a tree mutation; sessions sharing one
229
- // attached directory must not re-point it under a running turn.
230
- // - BEFORE the baseline capture below: present in both the baseline
231
- // and candidate trees, the link cancels out of the file-review diff
232
- // even when the workspace's git excludes do not list `.stigmer`.
233
- // Removed in cleanup() (the finally below), before the lock releases.
234
- if (setup.workspaceBackend.platformDir) {
235
- await ensureStigmerSymlink(gitRoot, setup.workspaceBackend.platformDir);
236
- }
237
- // (1) Capture-mode resume — reconcile any DECIDED change set FIRST (this
238
- // drops the per-execution refs), before the next baseline re-pins them
239
- // (refs are executionId-keyed). Then (2) short-circuit a pure file-review
240
- // resume — the agent already finished in a prior segment, so finalize with
241
- // NO model re-invocation. A mixed turn (a tool gate is also pending) falls
242
- // through to resume the graph for the gated tool.
243
- if (setup.captureMode) {
244
- const decidedSets = (setup.execution.status?.fileChangeSets ?? []).filter((cs) => cs.status === FileChangeSetStatus.DECIDED);
245
- let reconciledAny = false;
246
- let reconcileFailed = false;
247
- let reconcileFailureDetail = "";
248
- // The CAS blob reader reconciles ignored-file decisions from the durable
249
- // manifest (git-only turns have no manifest, so the CAS branch no-ops).
250
- // Undefined with no store: this block still runs for a git workspace
251
- // whose captureMode is true without storage, but such a turn captures no
252
- // CAS files (captureIgnored is off), so its change set carries no CAS ref
253
- // and applyCaptureDecisions never needs the reader.
254
- const casReadBlob = setup.artifactStorage
255
- ? casBlobReader(setup.artifactStorage)
256
- : undefined;
257
- for (const changeSet of decidedSets) {
258
- const capResult = await applyCaptureDecisions({
259
- status: initialStatus,
260
- gitRoot,
261
- executionId,
262
- changeSet,
263
- harnessId: DEEP_AGENT_HARNESS_ID,
264
- storage: setup.artifactStorage,
265
- readBlob: casReadBlob,
266
- gitWorkspace: setup.gitWorkspace,
267
- });
268
- if (!capResult.isCaptureTurn)
269
- continue;
270
- reconciledAny = true;
271
- if (capResult.failed) {
272
- reconcileFailed = true;
273
- reconcileFailureDetail =
274
- capResult.failureDetail ?? "file review reconcile failed";
275
- }
276
- }
277
- if (reconciledAny) {
278
- if (reconcileFailed) {
279
- // What-you-approve-is-what-applies failed: nothing was applied.
280
- initialStatus.phase = ExecutionPhase.EXECUTION_FAILED;
281
- initialStatus.error = `File review reconcile failed: ${reconcileFailureDetail}`;
282
- initialStatus.completedAt = utcTimestamp();
283
- await persistStatus(client, executionId, initialStatus, { offload: statusOffload });
284
- return slimStatus(initialStatus);
285
- }
286
- if (!hasPendingToolApprovals(setup.execution)) {
287
- // Pure file review: the agent's final answer + outputs already rode
288
- // the prior segment's persisted status (seeded into initialStatus).
289
- // Complete now and push only the approved tree — NO model re-run.
290
- //
291
- // The discriminator is the PERSISTED transcript, not the live graph
292
- // checkpoint: it must behave identically across checkpointer
293
- // backends, but the live checkpoint does not — the memory backend
294
- // (opt-in, tests) recreates it empty each invocation while the
295
- // durable backends (sqlite local / http cloud) preserve it, so a
296
- // graphState-based check would diverge and could wrongly fire for a
297
- // mixed turn. A mixed turn leaves WAITING_APPROVAL tool rows in the
298
- // transcript; a pure file-review turn leaves none.
299
- initialStatus.phase = ExecutionPhase.EXECUTION_COMPLETED;
300
- initialStatus.completedAt = utcTimestamp();
301
- if (writebackCoordinator) {
302
- await processCaptureWriteback(writebackCoordinator, executionId);
303
- }
304
- await persistStatus(client, executionId, initialStatus, { offload: statusOffload });
305
- // Surface the agent's final outputs (computed in the prior segment,
306
- // carried on the seeded status) the same way a normal completion does.
307
- const slim = slimStatus(initialStatus);
308
- const lastAi = [...initialStatus.messages]
309
- .reverse()
310
- .find((m) => m.type === MessageType.MESSAGE_AI);
311
- if (lastAi?.content)
312
- slim.final_text = lastAi.content;
313
- if (initialStatus.structuredOutput !== undefined) {
314
- slim.structured = initialStatus.structuredOutput;
315
- }
316
- return slim;
317
- }
318
- // else: mixed turn — fall through; the graph resumes for the gated
319
- // tool and a new baseline is taken below for the continuation segment.
320
- }
321
- }
322
- // Turn start (capture mode): pin the pre-turn tree + author BASELINE. Taken
323
- // AFTER any reconcile above and AFTER performSetup's workspace writes and
324
- // the `.stigmer` symlink above, so the baseline absorbs the reconciled
325
- // state and the runner-owned files (the symlink then cancels out of the
326
- // baseline→candidate diff).
327
- let captureBaselineTree = "";
328
- // Snapshot the sub-agent tool-call ids that exist BEFORE this turn's
329
- // stream, so the turn-boundary stamp scopes itself to sub-agent rows
330
- // created this turn (empty here by construction — this harness never
331
- // seeds prior sub-agents — but computed, not assumed, so it stays correct
332
- // if that ever changes; see collectSubAgentToolCallIds).
333
- const priorSubAgentToolCallIds = collectSubAgentToolCallIds(initialStatus.subAgentExecutions);
334
- // Snapshot the top-level tool-call ids already SETTLED before this turn's
335
- // stream, so the approved-command provenance (DD-28) scopes itself to THIS
336
- // turn's executed commands by identity. The deep-agent's approved shell
337
- // executes in place at its seeded position, so the Cursor positional scope
338
- // would miss it — see execute-deep-agent/command-provenance.ts.
339
- const priorSettledToolCallIds = collectSettledToolCallIds(initialStatus.messages);
340
- if (setup.captureMode) {
341
- captureBaselineTree = await captureBaselineToLedger({
342
- status: initialStatus,
343
- gitRoot,
344
- executionId,
345
- changeSetId,
346
- harnessId: DEEP_AGENT_HARNESS_ID,
347
- gitWorkspace: setup.gitWorkspace,
348
- });
349
- }
350
- // Per-turn state + substrate for mid-run live capture (DD-32 / DD-33). The
351
- // floor lives in progressState; the substrate is chosen for this turn's
352
- // workspace shape and owns its own short-circuit cache. An atomic snapshot
353
- // of the shared observer feeds the CAS/HYBRID substrates — copied
354
- // synchronously so a concurrent sub-agent write cannot mutate it mid-read.
355
- const progressState = newProgressCaptureState();
356
- const casObserver = setup.casObserver;
357
- const readObserverTouched = () => ({
358
- before: new Map(casObserver.before),
359
- blockedSecretPaths: new Set(casObserver.blockedSecretPaths),
360
- });
361
- // Git tree -> hybrid (numstat for tracked + observer for gitignored);
362
- // non-git -> cas over the observer (no baseline tree needed). Undefined
363
- // outside capture mode (writes are deny-gated, nothing is captured).
364
- const progressSubstrate = !setup.captureMode
365
- ? undefined
366
- : setup.gitWorkspace
367
- ? captureBaselineTree
368
- ? createHybridProgressSubstrate(createGitProgressSubstrate({
369
- workspaceRoot: gitRoot,
370
- executionId,
371
- baselineTree: captureBaselineTree,
372
- }), createCasProgressSubstrate({ workspaceRoot: gitRoot, read: readObserverTouched }))
373
- : undefined
374
- : createCasProgressSubstrate({ workspaceRoot: gitRoot, read: readObserverTouched });
375
- const cancellationSignal = Context.current().cancellationSignal;
376
- const result = await streamExecution({
377
- agentGraph: setup.agentGraph,
378
- langgraphInput: effectiveInput,
379
- langgraphConfig: setup.langgraphConfig,
380
- executionId,
381
- client,
382
- initialStatus,
383
- streamingConfig,
384
- offload: statusOffload,
385
- gracefulStop: setup.gracefulStop,
386
- inlinePublisher,
387
- // Capture mode: never push speculative edits during the turn. Writeback
388
- // is deferred until the approved tree is reconciled (post-decision).
389
- writebackCoordinator: setup.captureMode ? undefined : (writebackCoordinator ?? undefined),
390
- heartbeatFn: (details) => Context.current().heartbeat(details),
391
- isCancelledFn: () => cancellationSignal.aborted,
392
- approvalProvider: {
393
- policies: setup.approvalPolicies,
394
- toolServerMap: setup.toolServerMap,
395
- leasedCategories: setup.leasedCategories,
396
- globalBypass: setup.globalBypass,
397
- unattended: setup.unattended,
398
- },
399
- streamVersion: setup.streamVersion,
400
- // Mid-run live capture (DD-32 / DD-33): attach file_change_progress
401
- // before each scheduled persist, throttled by the floor inside
402
- // captureFileChangeProgress. The substrate (git / non-git CAS / hybrid)
403
- // was chosen for this turn above; the deep-agent's only runner-owned
404
- // tree entry is the `.stigmer` symlink, created before the baseline
405
- // so it appears identically in every capture and cancels out of the
406
- // diff — the git slice therefore needs no excludePaths, matching its
407
- // turn-boundary candidate capture.
408
- beforePersist: async (status) => {
409
- if (!progressSubstrate)
410
- return;
411
- await captureFileChangeProgress({
412
- status,
413
- changeSetId,
414
- substrate: progressSubstrate,
415
- state: progressState,
416
- });
417
- },
418
- });
419
- await processPostStream({
420
- status: initialStatus,
421
- inlinePublisher,
422
- // Capture mode: suppress the post-stream writeback finalize — the edits
423
- // on disk are still speculative until reviewed. Writeback runs only on
424
- // the approved tree (processCaptureWriteback, after reconcile).
425
- writebackCoordinator: setup.captureMode ? null : writebackCoordinator,
426
- pendingPublishPromises: result.pendingPublishPromises,
427
- pendingWritebackPromises: result.pendingWritebackPromises,
428
- executionId,
429
- });
430
- // Never-persist-secret backstop (DD-26 #2): withhold content from any
431
- // built-in write row targeting a secret-like path, across the top-level
432
- // and sub-agent transcripts, before ANY persist below. On the deny-gate a
433
- // secret write is hard-blocked (a COMPLETED row) or — under
434
- // auto_approve_all, where no gate is installed — flowed; either way the
435
- // streamed row still carries `args` from handleToolStarted, and the
436
- // capture-mode stamping pass (which performs the same scrub) does not run
437
- // here. Idempotent / a no-op in capture mode. This single post-stream
438
- // sweep is the one choke point that precedes every downstream persist.
439
- withholdSecretContentFromMessages(initialStatus.messages, initialStatus.subAgentExecutions);
440
- // Terminalize any tool call the user SKIPPED or REJECTED at the gate.
441
- // These decisions never run the tool, so the resumed stream leaves the
442
- // seeded WAITING_APPROVAL row untouched (the gate returns a ToolMessage
443
- // with no on_tool_start on http; the memory replay never re-drives the
444
- // gate). Folding the recorded decision into a terminal status here makes
445
- // reject/skip resolve identically on both checkpointers — see
446
- // reconcileNonExecutingDecisions. Runs before the WAITING-detection and
447
- // completion persists below so the terminal status is what is persisted.
448
- reconcileNonExecutingDecisions(initialStatus);
449
- // Terminalize every tool call the gate auto-skipped under UNATTENDED
450
- // approval mode (DD-014): the skip has no human decision behind it, so
451
- // reconcileNonExecutingDecisions cannot see it — this sibling folds the
452
- // gate's registry into terminal SKIPPED rows with UNATTENDED_SKIP
453
- // provenance, whatever transient status the stream left behind. No-op
454
- // for interactive executions (empty registry).
455
- reconcileUnattendedSkips(initialStatus, setup.unattendedSkips);
456
- // Turn boundary (capture mode): capture the candidate change set from the
457
- // git diff and author CANDIDATE_CAPTURED, then stamp the flowed file-edit
458
- // rows with the change set id — they stay visible in place as
459
- // observational records while file_change_sets remains the single
460
- // decision surface. Skipped on an abnormal terminal (pause / stop /
461
- // recursion limit) — there is no review to open. `fileReviewPending`
462
- // then composes with any tool gate below.
463
- let fileReviewPending = false;
464
- const abnormalTerminal = !!result.terminalStatus &&
465
- initialStatus.phase !== ExecutionPhase.EXECUTION_WAITING_FOR_APPROVAL;
466
- if (setup.captureMode && !abnormalTerminal) {
467
- // Compose the CAS-captured paths (before-bytes from the observer,
468
- // after-bytes re-read from disk) and the secret-blocked paths into the
469
- // change set. The substrate class labels their provenance:
470
- // GIT_IGNORED_CAPTURED for a git tree's ignored paths, NON_GIT_CAS for a
471
- // non-git workspace (where these ARE the whole change set). In a git turn
472
- // they compose with the git-tracked diff into one hybrid set; in a non-git
473
- // turn they are the entire (CAS-only) set.
474
- const casCaptureClass = setup.gitWorkspace
475
- ? FileCaptureClass.GIT_IGNORED_CAPTURED
476
- : FileCaptureClass.NON_GIT_CAS;
477
- const { casCaptures, unreviewablePaths } = await buildCasTurnCaptures(setup.casObserver, gitRoot, casCaptureClass);
478
- // Approved-command turn facts (DD-28): when every mutation-capable call
479
- // this turn was a consented shell command, attach the provenance so the
480
- // backend can verify the cited consent rows and auto-keep the set
481
- // instead of arming a second review gate. Fail-closed: any non-qualifying
482
- // turn attaches nothing and reviews manually exactly as before. Attached
483
- // only when captureCandidateToLedger actually authors a CANDIDATE.
484
- const commandProvenance = deriveTurnCommandProvenance({
485
- status: initialStatus,
486
- priorSettledToolCallIds,
487
- priorSubAgentToolCallIds,
488
- globalBypass: setup.globalBypass,
489
- });
490
- if (commandProvenance) {
491
- console.log(`[ExecuteDeepAgent] capture: turn qualifies for approved-command auto-keep ` +
492
- `(consent rows: ${commandProvenance.consentToolCallIds.join(",") || "(auto_approve_all)"}); ` +
493
- `attaching provenance to candidate (execution=${executionId})`);
494
- }
495
- await captureCandidateToLedger({
496
- status: initialStatus,
497
- gitRoot,
498
- executionId,
499
- changeSetId,
500
- baselineTree: captureBaselineTree,
501
- harnessId: DEEP_AGENT_HARNESS_ID,
502
- casCaptures,
503
- storage: setup.artifactStorage,
504
- unreviewablePaths,
505
- unreviewableCaptureClass: casCaptureClass,
506
- gitWorkspace: setup.gitWorkspace,
507
- commandProvenance,
508
- });
509
- // Review is pending iff a CANDIDATE was actually authored (the seam
510
- // drops no-op captures), so a turn that only touched-then-unchanged an
511
- // ignored file does not open an empty review. Stamping is gated on the
512
- // same signal: a row must never reference a change set that does not
513
- // exist.
514
- fileReviewPending = hasCandidateCaptured(initialStatus, changeSetId);
515
- if (fileReviewPending) {
516
- stampFlowedFileEditRows(initialStatus.messages, changeSetId);
517
- stampFlowedSubAgentFileEditRows(initialStatus.subAgentExecutions, changeSetId, priorSubAgentToolCallIds);
518
- }
519
- }
520
- if (result.terminalStatus) {
521
- if (initialStatus.phase === ExecutionPhase.EXECUTION_PAUSED) {
522
- // The stream loop marks PAUSED for ANY platform cancellation; a
523
- // worker shutdown is not a pause and must not persist as one (#776).
524
- if (shutdownSignal?.aborted) {
525
- console.log(`[ExecuteDeepAgent] Cancelled (worker shutdown) for execution ${executionId}: events=${result.eventsProcessed}`);
526
- await persistStatus(client, executionId, buildWorkerShutdownStatus(), { offload: statusOffload }).catch(() => { });
527
- throw new CancelledFailure("Activity cancelled (worker shutdown, not user pause)");
528
- }
529
- await persistStatus(client, executionId, initialStatus, { offload: statusOffload });
530
- console.log(`[ExecuteDeepAgent] Paused for execution ${executionId}: events=${result.eventsProcessed}`);
531
- throw new CancelledFailure("Activity paused by orchestrator");
532
- }
533
- // Capture mode: a tool gate set WAITING during the stream while file
534
- // edits also flowed this turn. The CANDIDATE event + stamped file-edit
535
- // rows post-date the stream's slim, so persist + return the current
536
- // status (both review surfaces — the file change set and the tool gate —
537
- // are now pending). `!abnormalTerminal` means the capture block ran.
538
- if (setup.captureMode && !abnormalTerminal) {
539
- await persistStatus(client, executionId, initialStatus, { offload: statusOffload });
540
- return slimStatus(initialStatus);
541
- }
542
- return result.terminalStatus;
543
- }
544
- if (!setup.globalBypass) {
545
- const postStreamGraphState = await setup.agentGraph.getState(setup.langgraphConfig);
546
- const graphMessages = postStreamGraphState.values.messages;
547
- const aiMessages = Array.isArray(graphMessages) ? graphMessages : [];
548
- const pendingInterrupts = detectPendingInterrupts(postStreamGraphState);
549
- if (pendingInterrupts.length > 0) {
550
- console.log(`[ExecuteDeepAgent] Detected ${pendingInterrupts.length} pending interrupt(s) ` +
551
- `for execution ${executionId} — setting WAITING_FOR_APPROVAL`);
552
- initialStatus.phase = ExecutionPhase.EXECUTION_WAITING_FOR_APPROVAL;
553
- const aiMsg = create(AgentMessageSchema, {
554
- type: MessageType.MESSAGE_AI,
555
- content: "",
556
- timestamp: utcTimestamp(),
557
- isStreaming: false,
558
- });
559
- for (const intr of pendingInterrupts) {
560
- const toolCall = create(ToolCallSchema, {
561
- id: intr.toolCallId,
562
- name: intr.toolName,
563
- status: ToolCallStatus.TOOL_CALL_WAITING_APPROVAL,
564
- requiresApproval: true,
565
- approvalMessage: intr.message,
566
- approvalRequestedAt: utcTimestamp(),
567
- mcpServerSlug: intr.mcpServerSlug,
568
- startedAt: utcTimestamp(),
569
- toolKind: classifyTool(intr.toolName, intr.mcpServerSlug),
570
- approvalPolicySource: toProtoPolicySource(intr.policySource),
571
- policyEngineVersion: intr.policySource ? POLICY_ENGINE_VERSION : "",
572
- });
573
- // Capture a sanitized args preview AND the redacted args object
574
- // while the graph is paused, so the approval UI renders the
575
- // proposed change before the tool runs — and the row header can
576
- // extract its filename-first path from `args` like every other
577
- // row (issue #754: a placeholder without args rendered a
578
- // pathless "Write" header). Args are correlated from the
579
- // AI-message tool call in graph state (the single source of
580
- // truth).
581
- const { argsPreview, args } = captureApprovalArtifacts({
582
- toolCallId: intr.toolCallId,
583
- messages: aiMessages,
584
- });
585
- if (argsPreview)
586
- toolCall.argsPreview = argsPreview;
587
- if (args)
588
- toolCall.args = args;
589
- aiMsg.toolCalls.push(toolCall);
590
- }
591
- initialStatus.messages.push(aiMsg);
592
- await persistStatus(client, executionId, initialStatus, { offload: statusOffload });
593
- return slimStatus(initialStatus);
594
- }
595
- }
596
- // Capture mode: file edits flowed but no tool gate fired — open file
597
- // review instead of completing. The agent's final answer + outputs are
598
- // still computed and persisted below, so the pure-file-review resume can
599
- // complete from the seeded status with no model re-invocation.
600
- const completeNow = !fileReviewPending;
601
- initialStatus.phase = completeNow
602
- ? ExecutionPhase.EXECUTION_COMPLETED
603
- : ExecutionPhase.EXECUTION_WAITING_FOR_APPROVAL;
604
- if (completeNow) {
605
- initialStatus.completedAt = utcTimestamp();
606
- }
607
- let structuredOutput;
608
- let finalText;
609
- const lastAiMsg = [...initialStatus.messages]
610
- .reverse()
611
- .find(m => m.type === MessageType.MESSAGE_AI);
612
- if (lastAiMsg) {
613
- finalText = lastAiMsg.content;
614
- }
615
- if (setup.hasStructuredOutput) {
616
- // Primary source: deepagents' structuredResponse surfaced via the v3
617
- // run.output. This is the reliable path when the graph populates it.
618
- const sr = result.runOutput?.structuredResponse;
619
- if (sr != null && typeof sr === "object" && !Array.isArray(sr)) {
620
- structuredOutput = sr;
621
- }
622
- else if (sr !== undefined) {
623
- console.warn(`[ExecuteDeepAgent] structuredResponse is not a plain object ` +
624
- `for execution ${executionId}: type=${typeof sr}`);
625
- }
626
- // Fallback: extract JSON from the agent's final text message. The v3
627
- // streaming path does not surface deepagents' structuredResponse
628
- // (hasStructuredResponse=false), so we recover structured output by
629
- // parsing the agent's final response (JSON / code-fence / last-brace).
630
- if (structuredOutput === undefined && finalText) {
631
- const { extractJsonFromText } = await import("../../shared/extract-json.js");
632
- const extracted = extractJsonFromText(finalText);
633
- if (extracted != null && typeof extracted === "object" && !Array.isArray(extracted)) {
634
- structuredOutput = extracted;
635
- console.log(`[ExecuteDeepAgent] structured output extracted from final text ` +
636
- `for execution ${executionId}: finalTextLength=${finalText.length}`);
637
- }
638
- }
639
- if (structuredOutput !== undefined) {
640
- initialStatus.structuredOutput = structuredOutput;
641
- }
642
- }
643
- // Plan mode: the agent's final message is the plan. Publish it as a
644
- // first-class plan artifact (named from the plan's title) so the UI can
645
- // render a reviewable Plan card and a follow-up Implement run can
646
- // reference it. Read-only mode produces no file to auto-publish, so
647
- // this is the only artifact path.
648
- // Requires artifact storage; with none (proxy misconfig) the plan text
649
- // still lives in the final message — only the reviewable artifact is
650
- // skipped (mirrors Cursor's storage-guarded plan publish).
651
- if (setup.execution.spec?.executionConfig?.interactionMode === InteractionMode.PLAN &&
652
- finalText &&
653
- setup.artifactStorage) {
654
- await publishPlanArtifact({
655
- status: initialStatus,
656
- executionId,
657
- planText: finalText,
658
- artifactStorage: setup.artifactStorage,
659
- });
660
- }
661
- // Capture mode: push the approved tree exactly once, on terminal
662
- // completion — never the speculative mid-turn edits.
663
- if (setup.captureMode && completeNow && writebackCoordinator) {
664
- await processCaptureWriteback(writebackCoordinator, executionId);
665
- }
666
- await persistStatus(client, executionId, initialStatus, { offload: statusOffload });
667
- console.log(`[ExecuteDeepAgent] ${completeNow ? "Completed" : "Awaiting file review for"} ` +
668
- `execution ${executionId}: ` +
669
- `events=${result.eventsProcessed}, ` +
670
- `messages=${initialStatus.messages.length}, ` +
671
- `artifacts=${initialStatus.artifacts.length}, ` +
672
- `writebacks=${initialStatus.workspaceWriteBacks.length}, ` +
673
- `hasStructuredOutput=${structuredOutput !== undefined}`);
674
- // A WAITING (file-review) return carries no final outputs yet — those are
675
- // surfaced when the pure-file-review resume completes from this persisted
676
- // status. The COMPLETED return enriches the slim with final text/outputs.
677
- if (!completeNow) {
678
- return slimStatus(initialStatus);
679
- }
680
- const slim = slimStatus(initialStatus);
681
- if (finalText !== undefined) {
682
- slim.final_text = finalText;
683
- }
684
- if (structuredOutput !== undefined) {
685
- slim.structured = structuredOutput;
686
- }
687
- return slim;
688
- }
689
- catch (err) {
690
- if (err instanceof CancelledFailure) {
691
- // Worker shutdown is infrastructure failure, not pause — the caught
692
- // CancelledFailure is itself the interruption evidence (#776).
693
- if (shutdownSignal?.aborted) {
694
- console.log(`[ExecuteDeepAgent] Cancelled (worker shutdown) for execution ${executionId}`);
695
- await persistStatus(client, executionId, buildWorkerShutdownStatus()).catch(() => { });
696
- throw err;
697
- }
698
- console.log(`[ExecuteDeepAgent] Cancelled (pause) for execution ${executionId}`);
699
- const pausedStatus = create(AgentExecutionStatusSchema, {
700
- phase: ExecutionPhase.EXECUTION_PAUSED,
701
- });
702
- await persistStatus(client, executionId, pausedStatus).catch(() => { });
703
- throw err;
704
- }
705
- if (Context.current().cancellationSignal.aborted) {
706
- if (shutdownSignal?.aborted) {
707
- console.log(`[ExecuteDeepAgent] Error during worker-shutdown cancellation for ${executionId}: ${err}`);
708
- await persistStatus(client, executionId, buildWorkerShutdownStatus()).catch(() => { });
709
- throw new CancelledFailure("Activity cancelled (worker shutdown, not user pause)");
710
- }
711
- console.log(`[ExecuteDeepAgent] Error during cancellation for ${executionId}, treating as pause: ${err}`);
712
- const pausedStatus = create(AgentExecutionStatusSchema, {
713
- phase: ExecutionPhase.EXECUTION_PAUSED,
714
- });
715
- await persistStatus(client, executionId, pausedStatus).catch(() => { });
716
- throw new CancelledFailure("Activity paused by orchestrator (error during cancellation)");
717
- }
718
- // Classify before formatting: model-call failures get stable codes
719
- // and platform-vs-user attribution (LangChain's MiddlewareError
720
- // wrapper is unwrapped to the root SDK error); non-model failures
721
- // keep the root error's own identity. See shared/model-error.ts.
722
- const { errorType, errorMessage } = describeExecutionError(err, {
723
- proxyMode: !!config.proxyEndpoint,
724
- modelId: setup?.modelName,
725
- provider: setup ? tryInferProvider(setup.modelName) : undefined,
726
- });
727
- console.error(`[ExecuteDeepAgent] Failed for execution ${executionId}: ` +
728
- `[${errorType}] ${errorMessage}`);
729
- const failedStatus = create(AgentExecutionStatusSchema, {
730
- phase: ExecutionPhase.EXECUTION_FAILED,
731
- error: `Execution failed: [${errorType}] ${errorMessage}`,
732
- completedAt: utcTimestamp(),
733
- messages: [
734
- create(AgentMessageSchema, {
735
- type: MessageType.MESSAGE_SYSTEM,
736
- content: `Error: [${errorType}] ${errorMessage}`,
737
- timestamp: utcTimestamp(),
738
- }),
739
- ],
740
- });
741
- await persistStatus(client, executionId, failedStatus);
742
- return slimStatus(failedStatus);
743
- }
744
- finally {
745
- await cleanup(setup);
746
- // Release the workspace turn lock LAST — the next queued turn must
747
- // not baseline until every mutation of this one has landed.
748
- // Idempotent and non-throwing (see workspace-lock.ts).
749
- await releaseWorkspaceLock?.();
750
- activityFinished();
751
- }
752
- },
753
- };
754
- }
755
- /**
756
- * Normalize the graph checkpoint's un-resumed interrupts into pending approvals.
757
- * Used both before streaming (to detect whether a resume is a pure file review)
758
- * and after (to seed the WAITING_FOR_APPROVAL tool rows).
759
- */
760
- function detectPendingInterrupts(graphState) {
761
- const tasks = graphState.tasks;
762
- return (tasks?.flatMap((task) => (task.interrupts ?? [])
763
- .filter((intr) => intr.resumeValue === undefined)
764
- .map((intr) => {
765
- const val = intr.value;
766
- return {
767
- toolCallId: val?.tool_call_id ?? "",
768
- toolName: val?.tool_name ?? "",
769
- mcpServerSlug: val?.mcp_server_slug ?? "",
770
- message: val?.message ?? "",
771
- policySource: val?.policy_source || undefined,
772
- };
773
- })) ?? []);
774
- }
775
- /**
776
- * Whether the persisted transcript holds any tool call awaiting approval — the
777
- * checkpointer-independent signal that a resume must drive a tool gate (resume
778
- * the graph), not just a file review. Scans root + sub-agent messages. A tool
779
- * keeps `WAITING_APPROVAL` after the user decides (the decision rides
780
- * `approval_action`) until the runner reconciles it, so this is true for a mixed
781
- * turn's resume and false for a pure file-review turn.
782
- */
783
- function hasPendingToolApprovals(execution) {
784
- const status = execution.status;
785
- if (!status)
786
- return false;
787
- const anyWaiting = (msgs) => msgs.some((m) => m.toolCalls.some((tc) => tc.status === ToolCallStatus.TOOL_CALL_WAITING_APPROVAL));
788
- if (anyWaiting(status.messages))
789
- return true;
790
- return status.subAgentExecutions.some((sa) => anyWaiting(sa.messages));
791
- }
792
- /**
793
- * Assemble the turn's CAS captures and secret-blocked paths from the shared
794
- * observer (the pre-turn bytes recorded by the parent AND every sub-agent CAS
795
- * backend, plus the gate's secret-blocked set).
796
- *
797
- * For each observed CAS-owned path the after-bytes are re-read from disk (the
798
- * authoritative net result of the turn; `null` when the file is gone). A path
799
- * that is secret-like is diverted to `unreviewablePaths` and its before-bytes are
800
- * dropped — the fail-closed backstop that holds even under the global bypass,
801
- * where the gate did not run to block it up front. The result composes into the
802
- * change set in {@link captureCandidateToLedger}.
803
- *
804
- * `captureClass` is the turn's CAS substrate class — GIT_IGNORED_CAPTURED for a
805
- * git work tree's ignored paths, NON_GIT_CAS for a non-git workspace (where these
806
- * ARE the whole change set) — so each captured path carries its true provenance.
807
- */
808
- async function buildCasTurnCaptures(observer, workspaceRoot, captureClass) {
809
- // The secret partition (pure, corpus-lockable) decides what may be captured;
810
- // this shell only performs the IO for the capturable set. The backstop that
811
- // withholds a secret observed under the global bypass lives in the partition.
812
- const { capturablePaths, unreviewablePaths } = partitionIgnoredPathsBySecret(observer.before.keys(), observer.blockedSecretPaths);
813
- const casCaptures = [];
814
- for (const relPath of capturablePaths) {
815
- const after = await readFileOrNull(join(workspaceRoot, relPath));
816
- casCaptures.push({
817
- path: relPath,
818
- before: observer.before.get(relPath) ?? null,
819
- after,
820
- captureClass,
821
- });
822
- }
823
- return { casCaptures, unreviewablePaths: [...unreviewablePaths] };
824
- }
825
- /** Raw bytes of a file, or `null` when it does not exist (a DELETE). */
826
- async function readFileOrNull(absolutePath) {
827
- try {
828
- return await readFile(absolutePath);
829
- }
830
- catch {
831
- return null;
832
- }
833
- }
834
- /**
835
- * Push the reconciled (approved) tree exactly once, on terminal completion in
836
- * capture mode. The coordinator's {@link WriteBackCoordinator.finalize} commits +
837
- * pushes whatever uncommitted changes remain — which, post-reconcile, is exactly
838
- * the approved content (rejected files were already snapped back to baseline).
839
- * Speculative mid-turn edits never reach here (writeback is suppressed during the
840
- * turn). Fire-and-forget by the coordinator's own contract (errors logged).
841
- */
842
- async function processCaptureWriteback(writebackCoordinator, executionId) {
843
- await writebackCoordinator.finalize();
844
- console.log(`[ExecuteDeepAgent] capture writeback finalized for execution ${executionId}`);
845
- }
846
- /**
847
- * Whether to seed the initial status from the persisted execution transcript.
848
- *
849
- * The Temporal workflow re-invokes ExecuteDeepAgent with the same thread_id on
850
- * every continuation — HITL approval, pause/resume, and transient recovery. The
851
- * runner owns the transcript and the server enforces it as append-only at
852
- * identity, so any continuation must build ON the committed history rather than
853
- * rebuilding from an empty proto and replacing it.
854
- *
855
- * The decision is therefore driven solely by whether the server already holds
856
- * committed history for this execution — NOT by the live graph checkpoint, which
857
- * the checkpointer backends leave in different states for the same continuation:
858
- * - durable (sqlite, the OSS local / desktop default; and http in cloud): the
859
- * checkpoint survives, the graph resumes via Command(resume), and
860
- * streamEvents re-emits only post-checkpoint events;
861
- * - memory (ephemeral, opt-in — used by tests): the checkpoint is recreated
862
- * empty every invocation, so the graph REPLAYS from scratch and the blind
863
- * FIFO turns advance one gate at a time.
864
- * Keying on the live checkpoint skipped seeding on that memory-replay path, so a
865
- * second sequential gate emitted a transcript holding only the new gate, dropped
866
- * the first gate's committed tool-call id, and tripped the server's append-only
867
- * guard — the silent sequential-gate skip. Seeding whenever persisted history
868
- * exists covers both paths; a re-emitted prior turn reconciles in place by
869
- * tool-call id (StatusBuilder.rebuildToolCallIndex), so seeding never
870
- * duplicates. False on a first run (no persisted messages), preserving the
871
- * original start-from-empty behavior.
872
- */
873
- function shouldSeedFromPersistedTranscript(execution) {
874
- return (execution.status?.messages.length ?? 0) > 0;
875
- }
876
- /**
877
- * Seed a fresh status from the persisted execution transcript so streamed
878
- * deltas append onto existing history rather than replacing it. The clone keeps
879
- * the persisted proto immutable. Terminal fields are cleared because the resumed
880
- * run is in progress again; the StatusBuilder constructor re-sets the phase.
881
- */
882
- function seedStatusFromExecution(execution) {
883
- const seeded = clone(AgentExecutionStatusSchema, execution.status);
884
- seeded.completedAt = "";
885
- seeded.error = "";
886
- return seeded;
887
- }
888
- async function cleanup(setup) {
889
- if (!setup)
890
- return;
891
- if (setup.mcpConnection) {
892
- try {
893
- await setup.mcpConnection.client.close();
894
- }
895
- catch (err) {
896
- console.warn("[ExecuteDeepAgent] MCP connection cleanup failed:", err);
897
- }
898
- }
899
- // Close the checkpointer's backing resources. Only the durable sqlite saver
900
- // holds an OS handle (an open DB file); memory/http savers have no close(),
901
- // so this is duck-typed and best-effort.
902
- const closable = setup.checkpointer;
903
- if (closable && typeof closable.close === "function") {
904
- try {
905
- closable.close();
906
- }
907
- catch (err) {
908
- console.warn("[ExecuteDeepAgent] Checkpointer cleanup failed:", err);
909
- }
910
- }
911
- // Drop the workspace→platform `.stigmer` symlink so an attached repo is
912
- // left untouched between turns (issue #173 semantics; a multi-turn session
913
- // recreates it next turn). Runs in the activity finally, BEFORE the
914
- // workspace lock releases, so the next queued turn baselines a clean tree.
915
- // Best-effort and symlink-only: a real `.stigmer` directory is never removed.
916
- await removeStigmerSymlink(setup.workspaceBackend.rootDir);
917
- }
918
- //# sourceMappingURL=index.js.map