@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
@@ -3,22 +3,78 @@
3
3
  * parent-checkpoint interrupt reader.
4
4
  *
5
5
  * These two helpers are what every "drive a real deepagents/LangGraph graph
6
- * through the approval gate" test needs, and they were previously copy-pasted
7
- * inline. They are shared by:
8
- * - `__tests__/subagent-approval-propagation.test.ts` (sub-agent interrupt
9
- * propagation against the real runtime), and
10
- * - `__test-utils__/gateway-substrate.ts` (the deep-agent adapter for the
11
- * gateway Contract Test Kit).
6
+ * through the approval gate" test needs. They are shared by the graph-level
7
+ * tests (`__tests__/subagent-approval-propagation.test.ts`,
8
+ * `shell-execute-gate.test.ts`, …), the gateway Contract Test Kit adapter
9
+ * (`gateway-substrate.ts`), and the hermetic activity driver
10
+ * (`hermetic-deep-agent.ts`), which runs the REAL `ExecuteDeepAgent` activity
11
+ * with this model as the only LLM. Keeping one copy means a change to how the
12
+ * runner reads pending interrupts (or how a scripted run is driven) updates
13
+ * every consumer at once.
12
14
  *
13
- * Keeping one copy means a change to how the runner reads pending interrupts (or
14
- * how a scripted run is driven) updates every consumer at once.
15
+ * The one rule the model keeps: it is a PURE FUNCTION of (bound tools,
16
+ * transcript). A script is a sequence of turns per role, and the turn to play
17
+ * is chosen by how many tool rounds the transcript already holds (AI messages
18
+ * carrying `tool_calls`), never by a call counter. That is what lets one
19
+ * script serve both checkpointers the runner ships: under `memory` a HITL
20
+ * reinvocation REPLAYS the graph from the first message (the saver is
21
+ * recreated empty per invocation), so the same transcript indices produce the
22
+ * same proposals; under `sqlite` the graph RESUMES after the interrupt and the
23
+ * next call sees one more completed round. A call-counted script would emit
24
+ * the wrong turn on replay.
25
+ *
26
+ * A script may also be a {@link TurnPlayer}: a function of the whole
27
+ * transcript that returns the one turn to play now. The same rule, with the
28
+ * indexing left to the caller — for a consumer whose plan is not "turn k on
29
+ * round k" but "the first step the conversation does not yet show" (the
30
+ * harness contract kit's native subject, whose one execution spans many
31
+ * kit turns on one sqlite thread, S3 M3).
32
+ *
33
+ * A turn may END the model call instead of finishing the message
34
+ * ({@link TurnEnding}): `fail` throws after its chunks (a provider error
35
+ * mid-stream); `hang` parks on the call's abort signal after its chunks and
36
+ * throws the abort when it fires (a provider stream that stalls and is then
37
+ * cancelled). A hang never parks on a timer: `@langchain/core` hands the
38
+ * graph run's signal to `_streamResponseChunks` as `options.signal`
39
+ * (`_separateRunnableConfigFromCallOptionsCompat`), and LangGraph threads
40
+ * its composite abort signal into every task's config, so the runtime's one
41
+ * stop is what unparks it. The `onPark` hook is how a test learns the engine
42
+ * is silent before it stops the turn from the outside.
43
+ *
44
+ * The model STREAMS. With LangGraph's v3 messages handler attached, LangChain
45
+ * Core streams a model internally when it implements `_streamResponseChunks`
46
+ * and otherwise falls back to a synthesized final-message event sequence
47
+ * (`@langchain/langgraph` `pregel/messages-v2.js` `emitFinalMessage`). The
48
+ * fallback spreads a `tool_call` block's `args` OBJECT into the
49
+ * `tool_call_chunk` fields the runner's normalizer reads as a JSON STRING
50
+ * (`v3-protocol-normalizer.ts` `argsChunk`), which no real provider does.
51
+ * Streaming keeps the double on the production event path: `@langchain/core`
52
+ * `language_models/compat.js` `convertChunksToEvents` turns the chunks below
53
+ * into `message-start`, per-block `content-block-start` / `-delta` /
54
+ * `-finish`, and `message-finish` with usage — the same events `ChatAnthropic`
55
+ * produces. The chunk shapes are chosen from that converter: a string chunk
56
+ * opens block 0 and emits a text delta in one step; an array-content part
57
+ * opens its block with NO delta on first sight, so a reasoning block is sent
58
+ * as an empty opener followed by the text; a `tool_call_chunk` always emits a
59
+ * delta carrying the accumulated JSON args; `usage_metadata` rides the LAST
60
+ * chunk so it lands on `message-finish` (the one place the runner reads it),
61
+ * not on `message-start`.
15
62
  */
16
63
 
17
64
  import { BaseChatModel } from "@langchain/core/language_models/chat_models";
18
- import { AIMessage, ToolMessage, type BaseMessage } from "@langchain/core/messages";
19
- import type { ChatResult } from "@langchain/core/outputs";
65
+ import type { BaseChatModelCallOptions } from "@langchain/core/language_models/chat_models";
66
+ import type { CallbackManagerForLLMRun } from "@langchain/core/callbacks/manager";
67
+ import {
68
+ AIMessageChunk,
69
+ isAIMessage,
70
+ isSystemMessage,
71
+ type BaseMessage,
72
+ type ContentBlock,
73
+ type UsageMetadata,
74
+ } from "@langchain/core/messages";
75
+ import { ChatGenerationChunk, type ChatResult } from "@langchain/core/outputs";
20
76
 
21
- /** A single tool call the scripted model proposes on a non-terminal turn. */
77
+ /** A single tool call the scripted model proposes on a turn. */
22
78
  export interface ScriptedToolCall {
23
79
  name: string;
24
80
  args: Record<string, unknown>;
@@ -26,8 +82,62 @@ export interface ScriptedToolCall {
26
82
  }
27
83
 
28
84
  /**
29
- * What the scripted model does for a given role: propose `toolCalls` while no
30
- * tool result is pending, then emit the `done` text once a tool result returns.
85
+ * Token usage a turn reports; fixed round numbers keep `streamingUsage`
86
+ * legible in a golden. The cache buckets ride `input_token_details` the way
87
+ * the Anthropic adapter reports them (`cache_read`, `cache_creation`);
88
+ * `inputTokens` is the total the provider states, cache included.
89
+ */
90
+ export interface ScriptedUsage {
91
+ readonly inputTokens: number;
92
+ readonly outputTokens: number;
93
+ readonly cacheReadTokens?: number;
94
+ readonly cacheWriteTokens?: number;
95
+ }
96
+
97
+ /**
98
+ * How a turn ends the model call instead of finishing its message.
99
+ * - `fail`: throw `error` after the turn's chunks — a provider error
100
+ * mid-stream; the graph propagates it and the adapter classifies it.
101
+ * - `hang`: after the turn's chunks, park on the call's abort signal and
102
+ * throw the abort when it fires — a stalled provider stream, cancelled by
103
+ * the run's one stop. Refused (thrown, diagnosing) when the call carries
104
+ * no signal: a hang outside an abortable run would park forever.
105
+ */
106
+ export type TurnEnding = { readonly kind: "fail"; readonly error: Error } | { readonly kind: "hang" };
107
+
108
+ /**
109
+ * One assistant turn, rendered in the standard content-block shape a
110
+ * streaming provider produces: an optional leading reasoning block, an
111
+ * optional text block, and one `tool_call` per entry of `toolCalls` (which is
112
+ * also what the graph executes). A turn with neither text nor tool calls is
113
+ * an empty assistant message — legal, and what a script that has said all it
114
+ * has to say looks like. A turn with `ends` never finishes its message: its
115
+ * chunks are streamed, then the ending takes the call.
116
+ */
117
+ export interface ScriptedTurn {
118
+ readonly reasoning?: string;
119
+ readonly text?: string;
120
+ readonly toolCalls?: readonly ScriptedToolCall[];
121
+ readonly usage?: ScriptedUsage;
122
+ readonly ends?: TurnEnding;
123
+ }
124
+
125
+ /**
126
+ * A role's script: `turns[k]` is played when the transcript already holds `k`
127
+ * completed tool rounds. Running past the end throws (a script that runs out
128
+ * is a test bug) unless `repeatLast` is set, in which case the final turn
129
+ * plays again — the shape of a model that keeps calling a tool until the
130
+ * graph's recursion limit stops it.
131
+ */
132
+ export interface RoleScript {
133
+ readonly turns: readonly ScriptedTurn[];
134
+ readonly repeatLast?: boolean;
135
+ }
136
+
137
+ /**
138
+ * The two-turn sugar most graph-level tests use: propose `toolCalls` on the
139
+ * first round, then say `done` on every round after. Exactly
140
+ * `{ turns: [{ toolCalls }, { text: done }], repeatLast: true }`.
31
141
  */
32
142
  export interface ScriptStep {
33
143
  toolCalls: ScriptedToolCall[];
@@ -35,18 +145,65 @@ export interface ScriptStep {
35
145
  }
36
146
 
37
147
  /**
38
- * Picks the {@link ScriptStep} for the currently-bound tool set. A single-agent
39
- * test ignores the argument; a parent/sub-agent test keys the role on a tool
40
- * unique to one role (e.g. the sub-agent's gated tool), because `createDeepAgent`
41
- * injects the `task` tool into both the parent and its sub-agents.
148
+ * What a selector can tell one role from another by. `createDeepAgent` gives
149
+ * a declared sub-agent the SAME tool set as its parent (`task` included), so
150
+ * tool names alone cannot separate them; the system prompt can it carries
151
+ * the role's own instructions.
42
152
  */
43
- export type ScriptSelector = (boundToolNames: string[]) => ScriptStep;
153
+ export interface ScriptRoleContext {
154
+ /** The transcript's leading system message, or "" when there is none. */
155
+ readonly systemPrompt: string;
156
+ }
44
157
 
45
158
  /**
46
- * A deterministic two-turn chat model: on the first turn it proposes the
47
- * selected role's tool calls; once a tool result comes back it returns the
48
- * role's terminating text. No LLM, no network — the role is keyed on the bound
49
- * tool names so the same model instance drives a parent and its sub-agents.
159
+ * A script as a function of the whole transcript: called on every model turn
160
+ * with the messages the model was asked with, returns the turn to play. The
161
+ * round-indexed `RoleScript` is the common case; this is for a plan whose
162
+ * progress is read off the conversation itself (see the header).
163
+ */
164
+ export type TurnPlayer = (transcript: readonly BaseMessage[]) => ScriptedTurn;
165
+
166
+ /** The three shapes a selector may answer with. */
167
+ export type Script = ScriptStep | RoleScript | TurnPlayer;
168
+
169
+ /**
170
+ * Picks the script for the role being asked. A single-agent test ignores both
171
+ * arguments; a parent/sub-agent test keys the role on a tool unique to one
172
+ * role when there is one (a custom counting tool), or on the role's
173
+ * instructions in `context.systemPrompt` when both roles bind the same tools
174
+ * (the hermetic delegation arm). Called at `_generate` time, never at bind
175
+ * time, so a role that is compiled but never invoked (the default
176
+ * general-purpose sub-agent) needs no script.
177
+ */
178
+ export type ScriptSelector = (boundToolNames: string[], context: ScriptRoleContext) => Script;
179
+
180
+ /** What the driver learns before a turn is rendered: which role, which round. */
181
+ export interface ScriptedTurnInfo {
182
+ readonly boundToolNames: readonly string[];
183
+ readonly round: number;
184
+ }
185
+
186
+ export interface ScriptedModelOptions {
187
+ /**
188
+ * Called once per model turn, before it is rendered. The hermetic driver
189
+ * ticks its clock here and runs a scenario's scheduled effect (a user pause,
190
+ * a worker shutdown) — from a model turn, never from a timer, so the
191
+ * interruption lands at the same instant every run.
192
+ */
193
+ readonly onTurn?: (info: ScriptedTurnInfo) => void | Promise<void>;
194
+ /**
195
+ * Called the moment a `hang` turn parks on its abort signal — the engine
196
+ * is silent from here until the signal fires. A test that must stop the
197
+ * turn from the outside (the contract kit's `whenHanging`) listens here,
198
+ * so the stop lands in the hang and never in the adapter's setup.
199
+ */
200
+ readonly onPark?: () => void;
201
+ }
202
+
203
+ /**
204
+ * A deterministic chat model driven by a per-role script. No LLM, no network.
205
+ * The role is keyed on the bound tool names so the same instance drives a
206
+ * parent and its sub-agents.
50
207
  */
51
208
  export class ScriptedModel extends BaseChatModel {
52
209
  toolNames: string[] = [];
@@ -59,11 +216,13 @@ export class ScriptedModel extends BaseChatModel {
59
216
  */
60
217
  readonly boundTools: unknown[];
61
218
  private readonly select: ScriptSelector;
219
+ private readonly options: ScriptedModelOptions;
62
220
 
63
- constructor(select: ScriptSelector, boundTools: unknown[] = []) {
221
+ constructor(select: ScriptSelector, boundTools: unknown[] = [], options: ScriptedModelOptions = {}) {
64
222
  super({});
65
223
  this.select = select;
66
224
  this.boundTools = boundTools;
225
+ this.options = options;
67
226
  }
68
227
 
69
228
  _llmType(): string {
@@ -71,29 +230,217 @@ export class ScriptedModel extends BaseChatModel {
71
230
  }
72
231
 
73
232
  bindTools(tools: unknown[]): this {
74
- const next = new ScriptedModel(this.select, this.boundTools);
75
- next.toolNames = (tools as Array<{ name?: string }>).map((t) => t?.name ?? "");
233
+ const next = new ScriptedModel(this.select, this.boundTools, this.options);
234
+ next.toolNames = tools.map(boundToolName);
76
235
  this.boundTools.length = 0;
77
236
  this.boundTools.push(...tools);
78
237
  return next as unknown as this;
79
238
  }
80
239
 
81
- async _generate(messages: BaseMessage[]): Promise<ChatResult> {
82
- const step = this.select(this.toolNames);
83
- const lastIsToolResult = messages[messages.length - 1] instanceof ToolMessage;
240
+ /** The turn for this transcript, after the driver hook has run. */
241
+ private async turnFor(messages: BaseMessage[]): Promise<ScriptedTurn> {
242
+ const round = completedToolRounds(messages);
243
+ await this.options.onTurn?.({ boundToolNames: this.toolNames, round });
244
+ const context: ScriptRoleContext = { systemPrompt: systemPromptOf(messages) };
245
+ return resolveTurn(this.select(this.toolNames, context), { round, transcript: messages, toolNames: this.toolNames });
246
+ }
247
+
248
+ /**
249
+ * The non-streaming path (`invoke` outside a graph — the runtime's tier-2
250
+ * structured-output extractor is the one caller): the SAME chunks the
251
+ * streaming path yields, merged, which is the `AIMessageChunk` a streaming
252
+ * provider's `invoke` returns. `@langchain/core`'s base `withStructuredOutput`
253
+ * pipeline reads exactly that shape (`AIMessageChunk.isInstance`, then
254
+ * `tool_calls`); a plain `AIMessage` here would fail it with "Input is not
255
+ * an AIMessageChunk" where the real provider succeeds. An ending turn ends
256
+ * this call the same way it ends the stream.
257
+ */
258
+ async _generate(messages: BaseMessage[], options: this["ParsedCallOptions"]): Promise<ChatResult> {
259
+ const turn = await this.turnFor(messages);
260
+ if (turn.ends) await this.takeEnding(turn.ends, options.signal);
261
+ const message = renderTurnChunks(turn).reduce((merged, chunk) => merged.concat(chunk));
262
+ return { generations: [{ message, text: turn.text ?? "" }] };
263
+ }
264
+
265
+ async *_streamResponseChunks(
266
+ messages: BaseMessage[],
267
+ options: this["ParsedCallOptions"] & BaseChatModelCallOptions,
268
+ _runManager?: CallbackManagerForLLMRun,
269
+ ): AsyncGenerator<ChatGenerationChunk> {
270
+ const turn = await this.turnFor(messages);
271
+ for (const chunk of renderTurnChunks(turn)) {
272
+ yield new ChatGenerationChunk({ message: chunk, text: typeof chunk.content === "string" ? chunk.content : "" });
273
+ }
274
+ if (turn.ends) await this.takeEnding(turn.ends, options.signal);
275
+ }
276
+
277
+ /** Never returns: throws the ending's error, or parks on the signal and throws its abort. */
278
+ private async takeEnding(ending: TurnEnding, signal: AbortSignal | undefined): Promise<never> {
279
+ switch (ending.kind) {
280
+ case "fail":
281
+ throw ending.error;
282
+ case "hang": {
283
+ if (!signal) {
284
+ throw new Error(
285
+ "ScriptedModel: a `hang` turn parks on the call's abort signal and this call carried none; " +
286
+ "a hang is only meaningful inside a run that can be aborted",
287
+ );
288
+ }
289
+ this.options.onPark?.();
290
+ if (!signal.aborted) {
291
+ await new Promise<void>((resolve) => signal.addEventListener("abort", () => resolve(), { once: true }));
292
+ }
293
+ throw abortErrorOf(signal);
294
+ }
295
+ default: {
296
+ const exhaustive: never = ending;
297
+ throw new Error(`ScriptedModel: unknown turn ending ${String(exhaustive)}`);
298
+ }
299
+ }
300
+ }
301
+ }
84
302
 
85
- const message = lastIsToolResult
86
- ? new AIMessage({ content: step.done })
87
- : new AIMessage({
88
- content: "",
89
- tool_calls: step.toolCalls.map((tc) => ({ ...tc, type: "tool_call" as const })),
90
- });
303
+ /** What a provider SDK throws when its in-flight request is aborted: the signal's own reason, or an `AbortError` naming it. */
304
+ function abortErrorOf(signal: AbortSignal): Error {
305
+ if (signal.reason instanceof Error) return signal.reason;
306
+ const err = new Error(`ScriptedModel: the hang was aborted (${String(signal.reason)})`);
307
+ err.name = "AbortError";
308
+ return err;
309
+ }
310
+
311
+ // ---------------------------------------------------------------------------
312
+ // Script resolution
313
+ // ---------------------------------------------------------------------------
314
+
315
+ /**
316
+ * The name a bound tool answers to: a LangChain tool's `name`, or an
317
+ * OpenAI-style function definition's `function.name` (how langchain binds the
318
+ * structured-output schema tool of `toolStrategy`). A real provider client
319
+ * accepts both shapes; so does this double.
320
+ */
321
+ function boundToolName(tool: unknown): string {
322
+ const t = tool as { name?: unknown; function?: { name?: unknown } } | null | undefined;
323
+ if (typeof t?.name === "string") return t.name;
324
+ if (typeof t?.function?.name === "string") return t.function.name;
325
+ return "";
326
+ }
91
327
 
92
- const text = typeof message.content === "string" ? message.content : "";
93
- return { generations: [{ message, text }] };
328
+ function systemPromptOf(messages: readonly BaseMessage[]): string {
329
+ const system = messages.find((m) => isSystemMessage(m));
330
+ if (!system) return "";
331
+ return typeof system.content === "string" ? system.content : system.text;
332
+ }
333
+
334
+ function normalizeScript(script: ScriptStep | RoleScript): RoleScript {
335
+ if ("done" in script) {
336
+ return { turns: [{ toolCalls: script.toolCalls }, { text: script.done }], repeatLast: true };
337
+ }
338
+ return script;
339
+ }
340
+
341
+ /** Tool rounds the transcript already holds: AI messages that proposed at least one tool call. */
342
+ export function completedToolRounds(messages: readonly BaseMessage[]): number {
343
+ let rounds = 0;
344
+ for (const m of messages) {
345
+ if (isAIMessage(m) && (m.tool_calls?.length ?? 0) > 0) rounds += 1;
94
346
  }
347
+ return rounds;
95
348
  }
96
349
 
350
+ /** What one model call knows when it picks its turn. */
351
+ interface TurnRequest {
352
+ readonly round: number;
353
+ readonly transcript: readonly BaseMessage[];
354
+ readonly toolNames: readonly string[];
355
+ }
356
+
357
+ function resolveTurn(script: Script, request: TurnRequest): ScriptedTurn {
358
+ if (typeof script === "function") return script(request.transcript);
359
+ const role = normalizeScript(script);
360
+ const { round, toolNames } = request;
361
+ if (round < role.turns.length) return role.turns[round];
362
+ if (role.repeatLast && role.turns.length > 0) return role.turns[role.turns.length - 1];
363
+ throw new Error(
364
+ `ScriptedModel: the script for role [${toolNames.join(", ")}] has ${role.turns.length} turn(s) ` +
365
+ `but the transcript already holds ${round} completed tool round(s); ` +
366
+ "add a turn or set repeatLast.",
367
+ );
368
+ }
369
+
370
+ // ---------------------------------------------------------------------------
371
+ // Rendering: the chunk sequence (stream), merged into one message for invoke
372
+ // ---------------------------------------------------------------------------
373
+
374
+ function usageMetadataOf(usage: ScriptedUsage | undefined): UsageMetadata | undefined {
375
+ if (!usage) return undefined;
376
+ const hasCacheBuckets = usage.cacheReadTokens !== undefined || usage.cacheWriteTokens !== undefined;
377
+ return {
378
+ input_tokens: usage.inputTokens,
379
+ output_tokens: usage.outputTokens,
380
+ total_tokens: usage.inputTokens + usage.outputTokens,
381
+ ...(hasCacheBuckets
382
+ ? { input_token_details: { cache_read: usage.cacheReadTokens ?? 0, cache_creation: usage.cacheWriteTokens ?? 0 } }
383
+ : {}),
384
+ };
385
+ }
386
+
387
+ function reasoningBlock(reasoning: string, index?: number): ContentBlock.Reasoning {
388
+ return { type: "reasoning", reasoning, ...(index !== undefined ? { index } : {}) };
389
+ }
390
+
391
+ function textBlock(text: string, index?: number): ContentBlock.Text {
392
+ return { type: "text", text, ...(index !== undefined ? { index } : {}) };
393
+ }
394
+
395
+ /**
396
+ * The chunk sequence `convertChunksToEvents` turns into the production event
397
+ * stream (see the header). An ending turn gets NO closing chunk: its message
398
+ * never finishes — the ending takes the call after these chunks.
399
+ */
400
+ function renderTurnChunks(turn: ScriptedTurn): AIMessageChunk[] {
401
+ const chunks: AIMessageChunk[] = [];
402
+ let nextIndex = 0;
403
+
404
+ if (turn.reasoning) {
405
+ const index = nextIndex++;
406
+ chunks.push(new AIMessageChunk({ content: [reasoningBlock("", index)] }));
407
+ chunks.push(new AIMessageChunk({ content: [reasoningBlock(turn.reasoning, index)] }));
408
+ }
409
+
410
+ if (turn.text) {
411
+ if (turn.reasoning) {
412
+ const index = nextIndex++;
413
+ chunks.push(new AIMessageChunk({ content: [textBlock("", index)] }));
414
+ chunks.push(new AIMessageChunk({ content: [textBlock(turn.text, index)] }));
415
+ } else {
416
+ nextIndex++;
417
+ chunks.push(new AIMessageChunk({ content: turn.text }));
418
+ }
419
+ }
420
+
421
+ for (const tc of turn.toolCalls ?? []) {
422
+ const index = nextIndex++;
423
+ chunks.push(
424
+ new AIMessageChunk({
425
+ content: "",
426
+ tool_call_chunks: [{ type: "tool_call_chunk", id: tc.id, name: tc.name, args: JSON.stringify(tc.args), index }],
427
+ }),
428
+ );
429
+ }
430
+
431
+ if (turn.ends) return chunks;
432
+
433
+ const usage = usageMetadataOf(turn.usage);
434
+ // The closing chunk: carries usage onto message-finish, and guarantees at
435
+ // least one chunk so an empty turn is still a message.
436
+ chunks.push(new AIMessageChunk({ content: "", ...(usage ? { usage_metadata: usage } : {}) }));
437
+ return chunks;
438
+ }
439
+
440
+ // ---------------------------------------------------------------------------
441
+ // Pending interrupts
442
+ // ---------------------------------------------------------------------------
443
+
97
444
  /** A pending approval interrupt surfaced at the parent checkpoint. */
98
445
  export interface PendingInterrupt {
99
446
  taskId: string;
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Pins that the native adapter's lifecycle module loads no engine: nothing
3
+ * on `adapter.ts`'s STATIC graph — the module and every relative module it
4
+ * loads at import time, transitively — names `deepagents`, `@langchain/*`
5
+ * or `@temporalio/*`.
6
+ *
7
+ * Why it matters: the composition roots import the harness table
8
+ * (`src/harness-adapters.ts`) BEFORE they boot it, and that table must stay
9
+ * connect- and SDK-free (the Cursor adapter's boot patches `node:http2`
10
+ * before anything dials the control plane; `harness-adapters.ts` states the
11
+ * rule). An adapter that imported its SDK at the top of its module would
12
+ * defeat it: this adapter's row is the table's second (S3 M2b, 2026-09-13).
13
+ * This fence is THE proof that the engine is not on the static graph — it
14
+ * walks every relative module transitively and records every package the
15
+ * graph names; the boot ORDER (native's `boot` runs after the Cursor patch)
16
+ * is proven in a real process by `src/__tests__/harness-boot-order.test.ts`,
17
+ * which boots both rows.
18
+ *
19
+ * Read off the syntax tree (`__test-utils__/module-specifiers.ts`): a
20
+ * `import type` is erased and a dynamic `import()` runs only inside `boot`,
21
+ * so neither is on the static graph; a package name in a header comment
22
+ * cannot trip it.
23
+ */
24
+
25
+ import { describe, it, expect } from "vitest";
26
+ import { existsSync } from "node:fs";
27
+ import { dirname, join, relative, resolve } from "node:path";
28
+ import { fileURLToPath } from "node:url";
29
+
30
+ import { readSource, staticRuntimeSpecifiers } from "../../../__test-utils__/module-specifiers.js";
31
+
32
+ const SRC_ROOT = fileURLToPath(new URL("../../../", import.meta.url));
33
+ const ADAPTER = join(SRC_ROOT, "activities", "execute-deep-agent", "adapter.ts");
34
+ const FORBIDDEN = ["deepagents", "@langchain/", "@temporalio/"] as const;
35
+
36
+ /** Every file on the static graph rooted at `entry`, and every package the graph names. */
37
+ function walkStaticGraph(entry: string): { files: string[]; packages: string[] } {
38
+ const files: string[] = [];
39
+ const packages: string[] = [];
40
+ const seen = new Set<string>();
41
+ const visit = (file: string): void => {
42
+ if (seen.has(file)) return;
43
+ seen.add(file);
44
+ files.push(file);
45
+ for (const specifier of staticRuntimeSpecifiers(file, readSource(file))) {
46
+ if (!specifier.startsWith(".")) {
47
+ packages.push(specifier);
48
+ continue;
49
+ }
50
+ // `.js` specifiers name `.ts` sources (NodeNext); a directory specifier is not used here.
51
+ const target = resolve(dirname(file), specifier.replace(/\.js$/, ".ts"));
52
+ if (existsSync(target)) visit(target);
53
+ }
54
+ };
55
+ visit(entry);
56
+ return { files, packages };
57
+ }
58
+
59
+ describe("the native adapter's static graph is SDK-free", () => {
60
+ const graph = walkStaticGraph(ADAPTER);
61
+
62
+ it("walked the lifecycle module and stayed out of the engine slice", () => {
63
+ const walked = graph.files.map((f) => relative(SRC_ROOT, f));
64
+ expect(walked).toContain("activities/execute-deep-agent/adapter.ts");
65
+ expect(walked).toContain("activities/execute-deep-agent/deep-agent-capabilities.ts");
66
+ // The engine slice is reached only through the dynamic import inside `boot`.
67
+ expect(walked).not.toContain("activities/execute-deep-agent/turn.ts");
68
+ expect(walked).not.toContain("activities/execute-deep-agent/turn-setup.ts");
69
+ expect(walked).not.toContain("activities/execute-deep-agent/deepagents-profiles.ts");
70
+ });
71
+
72
+ it("names no engine or Temporal package anywhere on the graph", () => {
73
+ const offences = graph.packages.filter((p) => FORBIDDEN.some((root) => p === root.replace(/\/$/, "") || p.startsWith(root)));
74
+ expect(offences, `adapter.ts's static graph must stay SDK-free; found: ${offences.join(", ")}`).toEqual([]);
75
+ });
76
+ });
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Pins that the native adapter is an engine slice and nothing more: no
3
+ * production module under `activities/execute-deep-agent/` imports
4
+ * `@temporalio/*`.
5
+ *
6
+ * Why it matters: every Temporal fact a turn needs — the heartbeat, the
7
+ * cancellation, the throw the workflow sees — is the turn runtime's
8
+ * (`harness/run-turn.ts`) and reaches the adapter through the sink. The
9
+ * contract kit runs an adapter OUTSIDE any activity context
10
+ * (`__test-utils__/harness-contract/`), so a `Context.current()` anywhere
11
+ * in the adapter would throw there; and an adapter that threw a
12
+ * `CancelledFailure` would be deciding pause-vs-shutdown, which is the
13
+ * runtime's table. The Cursor adapter's fence
14
+ * (`execute-cursor/__tests__/adapter-is-temporal-free.test.ts`) is the
15
+ * precedent; this is its native twin.
16
+ *
17
+ * Until S3 M2b (2026-09-13) one module was tolerated here: `index.ts`, the
18
+ * orchestrator the adapter replaced, which imported `@temporalio/activity`
19
+ * while it still served production. It is deleted; the list is empty and
20
+ * stays empty.
21
+ */
22
+
23
+ import { describe, it, expect } from "vitest";
24
+ import { join, relative } from "node:path";
25
+ import { fileURLToPath } from "node:url";
26
+
27
+ import { packageImports, readSource, typeScriptFilesUnder } from "../../../__test-utils__/module-specifiers.js";
28
+
29
+ const SRC_ROOT = fileURLToPath(new URL("../../../", import.meta.url));
30
+ const ADAPTER_ROOT = join(SRC_ROOT, "activities", "execute-deep-agent");
31
+
32
+ describe("the native adapter never imports @temporalio", () => {
33
+ const files = typeScriptFilesUnder(ADAPTER_ROOT, new Set(["__tests__", "__test-utils__"]));
34
+ const offences = files.flatMap((file) =>
35
+ packageImports(file, readSource(file), "@temporalio").map((specifier) => ` ${relative(SRC_ROOT, file)} imports "${specifier}"`),
36
+ );
37
+
38
+ it("inspected the adapter's own files (the walk is rooted where it claims)", () => {
39
+ expect(files.map((f) => relative(ADAPTER_ROOT, f))).toEqual(
40
+ expect.arrayContaining(["adapter.ts", "turn.ts", "turn-setup.ts", "turn-stream.ts", "turn-settle.ts", "deep-agent-capabilities.ts"]),
41
+ );
42
+ });
43
+
44
+ it("finds no @temporalio import in any production module", () => {
45
+ expect(offences, `the native adapter must not import @temporalio/*:\n${offences.join("\n")}`).toEqual([]);
46
+ });
47
+ });