@stigmer/runner 3.15.3-dev.20260914100347 → 3.15.3-dev.20260916211208

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 (549) hide show
  1. package/README.md +1 -0
  2. package/dist/.build-fingerprint +1 -1
  3. package/dist/__test-utils__/approval-contract/types.d.ts +1 -1
  4. package/dist/__test-utils__/hermetic-activity.d.ts +61 -7
  5. package/dist/__test-utils__/hermetic-activity.js +100 -9
  6. package/dist/__test-utils__/hermetic-activity.js.map +1 -1
  7. package/dist/__test-utils__/model-registry-fixture.d.ts +22 -3
  8. package/dist/__test-utils__/model-registry-fixture.js +22 -7
  9. package/dist/__test-utils__/model-registry-fixture.js.map +1 -1
  10. package/dist/activities/execute-cursor/__test-utils__/contract-subject.d.ts +2 -2
  11. package/dist/activities/execute-cursor/__test-utils__/contract-subject.js +14 -11
  12. package/dist/activities/execute-cursor/__test-utils__/contract-subject.js.map +1 -1
  13. package/dist/activities/execute-cursor/__test-utils__/fold.d.ts +61 -0
  14. package/dist/activities/execute-cursor/__test-utils__/fold.js +94 -0
  15. package/dist/activities/execute-cursor/__test-utils__/fold.js.map +1 -0
  16. package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js +1 -1
  17. package/dist/activities/execute-cursor/__test-utils__/gateway-substrate.js.map +1 -1
  18. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.d.ts +52 -14
  19. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js +46 -12
  20. package/dist/activities/execute-cursor/__test-utils__/hermetic-cursor.js.map +1 -1
  21. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.d.ts +21 -28
  22. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js +27 -11
  23. package/dist/activities/execute-cursor/__test-utils__/scripted-agent.js.map +1 -1
  24. package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.d.ts +70 -26
  25. package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.js +82 -32
  26. package/dist/activities/execute-cursor/__test-utils__/scripted-sdk.js.map +1 -1
  27. package/dist/activities/execute-cursor/adapter.d.ts +8 -7
  28. package/dist/activities/execute-cursor/adapter.js +13 -9
  29. package/dist/activities/execute-cursor/adapter.js.map +1 -1
  30. package/dist/activities/execute-cursor/approval-policy.d.ts +10 -10
  31. package/dist/activities/execute-cursor/approval-policy.js +12 -23
  32. package/dist/activities/execute-cursor/approval-policy.js.map +1 -1
  33. package/dist/activities/execute-cursor/approval-state.d.ts +35 -1
  34. package/dist/activities/execute-cursor/approval-state.js +65 -0
  35. package/dist/activities/execute-cursor/approval-state.js.map +1 -1
  36. package/dist/activities/execute-cursor/{message-translator.d.ts → boundary-rows.d.ts} +45 -341
  37. package/dist/activities/execute-cursor/boundary-rows.js +1018 -0
  38. package/dist/activities/execute-cursor/boundary-rows.js.map +1 -0
  39. package/dist/activities/execute-cursor/cursor-capabilities.d.ts +1 -1
  40. package/dist/activities/execute-cursor/cursor-capabilities.js +1 -1
  41. package/dist/activities/execute-cursor/cursor-event-recorder.d.ts +33 -14
  42. package/dist/activities/execute-cursor/cursor-event-recorder.js +43 -21
  43. package/dist/activities/execute-cursor/cursor-event-recorder.js.map +1 -1
  44. package/dist/activities/execute-cursor/prompt-builder.d.ts +3 -3
  45. package/dist/activities/execute-cursor/prompt-builder.js +4 -4
  46. package/dist/activities/execute-cursor/prompt-builder.js.map +1 -1
  47. package/dist/activities/execute-cursor/sdk-warmup.d.ts +15 -6
  48. package/dist/activities/execute-cursor/sdk-warmup.js +15 -6
  49. package/dist/activities/execute-cursor/sdk-warmup.js.map +1 -1
  50. package/dist/activities/execute-cursor/service-tier.js +1 -2
  51. package/dist/activities/execute-cursor/service-tier.js.map +1 -1
  52. package/dist/activities/execute-cursor/session-lifecycle.d.ts +38 -59
  53. package/dist/activities/execute-cursor/session-lifecycle.js +59 -96
  54. package/dist/activities/execute-cursor/session-lifecycle.js.map +1 -1
  55. package/dist/activities/execute-cursor/session-store.d.ts +100 -0
  56. package/dist/activities/execute-cursor/session-store.js +157 -0
  57. package/dist/activities/execute-cursor/session-store.js.map +1 -0
  58. package/dist/activities/execute-cursor/sub-agent-steps.d.ts +79 -0
  59. package/dist/activities/execute-cursor/sub-agent-steps.js +180 -0
  60. package/dist/activities/execute-cursor/sub-agent-steps.js.map +1 -0
  61. package/dist/activities/execute-cursor/tool-result.d.ts +49 -0
  62. package/dist/activities/execute-cursor/tool-result.js +130 -0
  63. package/dist/activities/execute-cursor/tool-result.js.map +1 -0
  64. package/dist/activities/execute-cursor/translator.d.ts +178 -0
  65. package/dist/activities/execute-cursor/translator.js +485 -0
  66. package/dist/activities/execute-cursor/translator.js.map +1 -0
  67. package/dist/activities/execute-cursor/turn-boundary.d.ts +15 -5
  68. package/dist/activities/execute-cursor/turn-boundary.js +10 -14
  69. package/dist/activities/execute-cursor/turn-boundary.js.map +1 -1
  70. package/dist/activities/execute-cursor/turn-settle.d.ts +11 -7
  71. package/dist/activities/execute-cursor/turn-settle.js +47 -34
  72. package/dist/activities/execute-cursor/turn-settle.js.map +1 -1
  73. package/dist/activities/execute-cursor/turn-setup.d.ts +2 -2
  74. package/dist/activities/execute-cursor/turn-setup.js +5 -5
  75. package/dist/activities/execute-cursor/turn-setup.js.map +1 -1
  76. package/dist/activities/execute-cursor/turn-stream.d.ts +23 -14
  77. package/dist/activities/execute-cursor/turn-stream.js +41 -28
  78. package/dist/activities/execute-cursor/turn-stream.js.map +1 -1
  79. package/dist/activities/execute-cursor/turn.d.ts +4 -4
  80. package/dist/activities/execute-cursor/turn.js +5 -5
  81. package/dist/activities/execute-cursor/usage-pricing.d.ts +2 -2
  82. package/dist/activities/execute-cursor/usage-pricing.js +2 -2
  83. package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.d.ts +2 -2
  84. package/dist/activities/execute-deep-agent/__test-utils__/contract-subject.js +2 -2
  85. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.d.ts +16 -11
  86. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js +22 -10
  87. package/dist/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.js.map +1 -1
  88. package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js +1 -1
  89. package/dist/activities/execute-deep-agent/__test-utils__/hitl-script.js.map +1 -1
  90. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.d.ts +2 -3
  91. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js +2 -3
  92. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model-module.js.map +1 -1
  93. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.d.ts +12 -3
  94. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js +18 -4
  95. package/dist/activities/execute-deep-agent/__test-utils__/scripted-model.js.map +1 -1
  96. package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.d.ts +10 -1
  97. package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.js +24 -11
  98. package/dist/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.js.map +1 -1
  99. package/dist/activities/execute-deep-agent/adapter.d.ts +1 -1
  100. package/dist/activities/execute-deep-agent/adapter.js +1 -1
  101. package/dist/activities/execute-deep-agent/approval-file-change.d.ts +19 -19
  102. package/dist/activities/execute-deep-agent/approval-file-change.js +16 -15
  103. package/dist/activities/execute-deep-agent/approval-file-change.js.map +1 -1
  104. package/dist/activities/execute-deep-agent/deep-agent-capabilities.d.ts +2 -2
  105. package/dist/activities/execute-deep-agent/deep-agent-capabilities.js +2 -2
  106. package/dist/activities/execute-deep-agent/hitl.d.ts +2 -2
  107. package/dist/activities/execute-deep-agent/hitl.js +2 -2
  108. package/dist/activities/execute-deep-agent/inline-publisher.d.ts +13 -3
  109. package/dist/activities/execute-deep-agent/inline-publisher.js +3 -3
  110. package/dist/activities/execute-deep-agent/inline-publisher.js.map +1 -1
  111. package/dist/activities/execute-deep-agent/prompt-builder.d.ts +3 -3
  112. package/dist/activities/execute-deep-agent/prompt-builder.js +6 -7
  113. package/dist/activities/execute-deep-agent/prompt-builder.js.map +1 -1
  114. package/dist/activities/execute-deep-agent/streaming-side-effects.d.ts +16 -8
  115. package/dist/activities/execute-deep-agent/streaming-side-effects.js +20 -33
  116. package/dist/activities/execute-deep-agent/streaming-side-effects.js.map +1 -1
  117. package/dist/activities/execute-deep-agent/subagent-transformer.d.ts +3 -3
  118. package/dist/activities/execute-deep-agent/subagent-transformer.js +1 -1
  119. package/dist/activities/execute-deep-agent/translator.d.ts +134 -0
  120. package/dist/activities/execute-deep-agent/translator.js +418 -0
  121. package/dist/activities/execute-deep-agent/translator.js.map +1 -0
  122. package/dist/activities/execute-deep-agent/turn-settle.d.ts +13 -7
  123. package/dist/activities/execute-deep-agent/turn-settle.js +34 -45
  124. package/dist/activities/execute-deep-agent/turn-settle.js.map +1 -1
  125. package/dist/activities/execute-deep-agent/turn-setup.d.ts +8 -8
  126. package/dist/activities/execute-deep-agent/turn-setup.js +7 -7
  127. package/dist/activities/execute-deep-agent/turn-stream.d.ts +13 -10
  128. package/dist/activities/execute-deep-agent/turn-stream.js +44 -41
  129. package/dist/activities/execute-deep-agent/turn-stream.js.map +1 -1
  130. package/dist/activities/execute-deep-agent/turn.d.ts +3 -3
  131. package/dist/activities/execute-deep-agent/turn.js +3 -3
  132. package/dist/config.d.ts +2 -2
  133. package/dist/harness/approval-decisions.d.ts +1 -1
  134. package/dist/harness/approval-decisions.js +1 -1
  135. package/dist/harness/capabilities.d.ts +21 -11
  136. package/dist/harness/capabilities.js +2 -2
  137. package/dist/harness/capture.d.ts +4 -4
  138. package/dist/harness/capture.js +4 -4
  139. package/dist/harness/persist-chokepoint.d.ts +3 -3
  140. package/dist/harness/persist-chokepoint.js +3 -3
  141. package/dist/harness/registry.d.ts +2 -2
  142. package/dist/harness/registry.js +2 -2
  143. package/dist/harness/run-turn.d.ts +6 -4
  144. package/dist/harness/run-turn.js +31 -9
  145. package/dist/harness/run-turn.js.map +1 -1
  146. package/dist/harness/stop-controller.d.ts +1 -1
  147. package/dist/harness/stop-controller.js +1 -1
  148. package/dist/harness/terminal-table.d.ts +7 -7
  149. package/dist/harness/terminal-table.js +7 -7
  150. package/dist/harness/transcript/builder.d.ts +182 -0
  151. package/dist/harness/transcript/builder.js +693 -0
  152. package/dist/harness/transcript/builder.js.map +1 -0
  153. package/dist/harness/transcript/events.d.ts +218 -0
  154. package/dist/harness/transcript/events.js +50 -0
  155. package/dist/harness/transcript/events.js.map +1 -0
  156. package/dist/harness/transcript/state.d.ts +110 -0
  157. package/dist/harness/transcript/state.js +148 -0
  158. package/dist/harness/transcript/state.js.map +1 -0
  159. package/dist/harness/turn-context.d.ts +54 -38
  160. package/dist/harness/turn-context.js +42 -43
  161. package/dist/harness/turn-context.js.map +1 -1
  162. package/dist/harness/types.d.ts +63 -22
  163. package/dist/harness/types.js +12 -11
  164. package/dist/harness/types.js.map +1 -1
  165. package/dist/harness/usage-accumulator.d.ts +2 -2
  166. package/dist/harness/usage-accumulator.js +2 -2
  167. package/dist/harness-adapters.d.ts +5 -4
  168. package/dist/harness-adapters.js +5 -4
  169. package/dist/harness-adapters.js.map +1 -1
  170. package/dist/middleware/approval-gate.d.ts +6 -0
  171. package/dist/middleware/approval-gate.js +7 -57
  172. package/dist/middleware/approval-gate.js.map +1 -1
  173. package/dist/middleware/cost-advisory.d.ts +3 -3
  174. package/dist/middleware/cost-advisory.js +3 -3
  175. package/dist/middleware/index.d.ts +1 -1
  176. package/dist/middleware/index.js +1 -1
  177. package/dist/runner-manager.js +1 -1
  178. package/dist/runner-manager.js.map +1 -1
  179. package/dist/shared/approval-policy.d.ts +53 -0
  180. package/dist/shared/approval-policy.js +76 -0
  181. package/dist/shared/approval-policy.js.map +1 -1
  182. package/dist/shared/args-preview.d.ts +45 -22
  183. package/dist/shared/args-preview.js +51 -41
  184. package/dist/shared/args-preview.js.map +1 -1
  185. package/dist/shared/attachment-resolver.d.ts +4 -4
  186. package/dist/shared/attachment-resolver.js +4 -4
  187. package/dist/shared/attachment-vision.d.ts +2 -1
  188. package/dist/shared/attachment-vision.js.map +1 -1
  189. package/dist/shared/attachment-zip.d.ts +2 -2
  190. package/dist/shared/attachment-zip.js +2 -2
  191. package/dist/shared/cost-guard.d.ts +2 -2
  192. package/dist/shared/cost-guard.js +2 -2
  193. package/dist/shared/exact-apply.d.ts +1 -1
  194. package/dist/shared/exact-apply.js +1 -1
  195. package/dist/shared/execution-context.d.ts +2 -2
  196. package/dist/shared/execution-context.js +2 -2
  197. package/dist/shared/extract-structured-output.d.ts +2 -2
  198. package/dist/shared/extract-structured-output.js +2 -2
  199. package/dist/shared/filereview/cas-touched.d.ts +2 -2
  200. package/dist/shared/filereview/cas-touched.js +2 -2
  201. package/dist/shared/heartbeat.d.ts +1 -1
  202. package/dist/shared/heartbeat.js +1 -1
  203. package/dist/shared/llm-backend.d.ts +0 -4
  204. package/dist/shared/llm-backend.js +0 -4
  205. package/dist/shared/llm-backend.js.map +1 -1
  206. package/dist/shared/model-error.d.ts +1 -2
  207. package/dist/shared/model-error.js +1 -2
  208. package/dist/shared/model-error.js.map +1 -1
  209. package/dist/shared/persist-decision.d.ts +18 -24
  210. package/dist/shared/persist-decision.js +19 -11
  211. package/dist/shared/persist-decision.js.map +1 -1
  212. package/dist/shared/prompt-sections.d.ts +4 -4
  213. package/dist/shared/prompt-sections.js +4 -4
  214. package/dist/shared/skill-resolver.d.ts +3 -3
  215. package/dist/shared/skill-resolver.js +3 -3
  216. package/dist/shared/status-offload.d.ts +1 -1
  217. package/dist/shared/status-offload.js +2 -2
  218. package/dist/shared/status-offload.js.map +1 -1
  219. package/dist/shared/streaming-scheduler.d.ts +2 -7
  220. package/dist/shared/streaming-scheduler.js +6 -14
  221. package/dist/shared/streaming-scheduler.js.map +1 -1
  222. package/dist/shared/subagent-rows.d.ts +2 -2
  223. package/dist/shared/subagent-rows.js +2 -2
  224. package/dist/shared/todos.d.ts +3 -3
  225. package/dist/shared/todos.js +3 -3
  226. package/dist/shared/tool-row.d.ts +19 -1
  227. package/dist/shared/tool-row.js +36 -2
  228. package/dist/shared/tool-row.js.map +1 -1
  229. package/dist/shared/worker-shutdown.d.ts +1 -1
  230. package/dist/shared/worker-shutdown.js +1 -1
  231. package/dist/shared/workspace/session-provision.d.ts +1 -1
  232. package/dist/shared/workspace/session-provision.js +1 -1
  233. package/dist/shared/workspace/sources/empty.d.ts +1 -1
  234. package/dist/shared/workspace/sources/empty.js +1 -2
  235. package/dist/shared/workspace/sources/empty.js.map +1 -1
  236. package/dist/shared/workspace/sources/git.js +4 -4
  237. package/dist/shared/workspace/sources/git.js.map +1 -1
  238. package/dist/shared/workspace/sources/local-path.js +6 -6
  239. package/dist/shared/workspace/sources/local-path.js.map +1 -1
  240. package/dist/shared/workspace/stigmer-link.d.ts +1 -1
  241. package/dist/shared/workspace/stigmer-link.js +1 -1
  242. package/dist/shared/workspace/types.d.ts +2 -5
  243. package/dist/shared/workspace/types.js +0 -6
  244. package/dist/shared/workspace/types.js.map +1 -1
  245. package/dist/shared/workspace/writeback-coordinator.d.ts +17 -4
  246. package/dist/shared/workspace/writeback-coordinator.js +7 -9
  247. package/dist/shared/workspace/writeback-coordinator.js.map +1 -1
  248. package/package.json +5 -5
  249. package/src/__test-utils__/__tests__/execution-record-barrier.test.ts +70 -0
  250. package/src/__test-utils__/__tests__/harness-contract-self-check.test.ts +35 -1
  251. package/src/__test-utils__/approval-contract/contract.ts +1 -1
  252. package/src/__test-utils__/approval-contract/types.ts +1 -1
  253. package/src/__test-utils__/harness-boot-order-child.ts +1 -1
  254. package/src/__test-utils__/harness-contract/contract.ts +8 -8
  255. package/src/__test-utils__/harness-contract/recording-sink.ts +11 -1
  256. package/src/__test-utils__/harness-contract/runtime-contract.ts +52 -16
  257. package/src/__test-utils__/harness-contract/scripted-adapter.ts +47 -43
  258. package/src/__test-utils__/hermetic-activity.ts +113 -9
  259. package/src/__test-utils__/model-registry-fixture.ts +31 -7
  260. package/src/__test-utils__/module-specifiers.ts +32 -3
  261. package/src/__tests__/harness-boot-order.test.ts +1 -1
  262. package/src/__tests__/harness-contract.test.ts +1 -1
  263. package/src/__tests__/runner-manager.test.ts +1 -1
  264. package/src/activities/execute-cursor/__test-utils__/__tests__/scripted-double.test.ts +32 -8
  265. package/src/activities/execute-cursor/__test-utils__/contract-subject.ts +12 -10
  266. package/src/activities/execute-cursor/__test-utils__/fold.ts +116 -0
  267. package/src/activities/execute-cursor/__test-utils__/gateway-substrate.ts +1 -1
  268. package/src/activities/execute-cursor/__test-utils__/hermetic-cursor.ts +72 -19
  269. package/src/activities/execute-cursor/__test-utils__/scripted-agent.ts +35 -29
  270. package/src/activities/execute-cursor/__test-utils__/scripted-sdk.ts +94 -38
  271. package/src/activities/execute-cursor/__tests__/approval-gate.test.ts +2 -1
  272. package/src/activities/execute-cursor/__tests__/approval-state.test.ts +14 -21
  273. package/src/activities/execute-cursor/__tests__/build-prompt.test.ts +3 -3
  274. package/src/activities/execute-cursor/__tests__/coarse-fingerprint.test.ts +2 -1
  275. package/src/activities/execute-cursor/__tests__/cursor-baseurl-routing.test.ts +10 -8
  276. package/src/activities/execute-cursor/__tests__/cursor-event-recorder.test.ts +142 -0
  277. package/src/activities/execute-cursor/__tests__/cursor-fetch-interceptor-bypass.test.ts +24 -12
  278. package/src/activities/execute-cursor/__tests__/cursor-generate-image-live.test.ts +7 -2
  279. package/src/activities/execute-cursor/__tests__/cursor-hook-protocol-live.test.ts +163 -0
  280. package/src/activities/execute-cursor/__tests__/cursor-sdk-auth-smoke.test.ts +23 -20
  281. package/src/activities/execute-cursor/__tests__/cursor-transcript-live.test.ts +298 -0
  282. package/src/activities/execute-cursor/__tests__/deny-gate-exact-apply.test.ts +4 -2
  283. package/src/activities/execute-cursor/__tests__/fetch-interceptor.test.ts +1 -1
  284. package/src/activities/execute-cursor/__tests__/hermetic/deny-and-retry.test.ts +5 -2
  285. package/src/activities/execute-cursor/__tests__/hermetic/file-review-capture.test.ts +5 -2
  286. package/src/activities/execute-cursor/__tests__/hermetic/goldens/mcp-tool-call.status.json +71 -0
  287. package/src/activities/execute-cursor/__tests__/hermetic/goldens/sdk-task-note.status.json +73 -0
  288. package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.error-delta.status.json +78 -0
  289. package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.output-first.status.json +72 -0
  290. package/src/activities/execute-cursor/__tests__/hermetic/goldens/shell-output-delta.status.json +72 -0
  291. package/src/activities/execute-cursor/__tests__/hermetic/goldens/sub-agent-delegation.status.json +109 -0
  292. package/src/activities/execute-cursor/__tests__/hermetic/goldens/thinking-turn.status.json +78 -0
  293. package/src/activities/execute-cursor/__tests__/hermetic/goldens/todo-write.status.json +119 -0
  294. package/src/activities/execute-cursor/__tests__/hermetic/goldens/tool-error.status.json +68 -0
  295. package/src/activities/execute-cursor/__tests__/hermetic/goldens/tool-only-step.status.json +67 -0
  296. package/src/activities/execute-cursor/__tests__/hermetic/goldens/unattributed-hook-block.status.json +1 -1
  297. package/src/activities/execute-cursor/__tests__/hermetic/harness-contract.test.ts +10 -7
  298. package/src/activities/execute-cursor/__tests__/hermetic/mcp-tool-call.test.ts +146 -0
  299. package/src/activities/execute-cursor/__tests__/hermetic/pause-vs-shutdown.test.ts +8 -5
  300. package/src/activities/execute-cursor/__tests__/hermetic/plain-turn.test.ts +6 -2
  301. package/src/activities/execute-cursor/__tests__/hermetic/recovery-fresh-agent.test.ts +4 -1
  302. package/src/activities/execute-cursor/__tests__/hermetic/run-wait-arms.test.ts +6 -2
  303. package/src/activities/execute-cursor/__tests__/hermetic/sdk-task-note.test.ts +122 -0
  304. package/src/activities/execute-cursor/__tests__/hermetic/shell-output-delta.test.ts +276 -0
  305. package/src/activities/execute-cursor/__tests__/hermetic/stream-self-stop-arms.test.ts +12 -9
  306. package/src/activities/execute-cursor/__tests__/hermetic/sub-agent-delegation.test.ts +196 -0
  307. package/src/activities/execute-cursor/__tests__/hermetic/thinking-turn.test.ts +145 -0
  308. package/src/activities/execute-cursor/__tests__/hermetic/thrown-error-arms.test.ts +4 -1
  309. package/src/activities/execute-cursor/__tests__/hermetic/todo-write.test.ts +165 -0
  310. package/src/activities/execute-cursor/__tests__/hermetic/tool-call.test.ts +7 -4
  311. package/src/activities/execute-cursor/__tests__/hermetic/tool-error.test.ts +138 -0
  312. package/src/activities/execute-cursor/__tests__/hermetic/tool-only-step.test.ts +130 -0
  313. package/src/activities/execute-cursor/__tests__/hermetic/unattributed-hook-block.test.ts +17 -2
  314. package/src/activities/execute-cursor/__tests__/hermetic/workspace-lock-timeout.test.ts +5 -2
  315. package/src/activities/execute-cursor/__tests__/hitl-ledger.test.ts +43 -60
  316. package/src/activities/execute-cursor/__tests__/hitl-resume-history.test.ts +23 -28
  317. package/src/activities/execute-cursor/__tests__/hook-script.test.ts +2 -1
  318. package/src/activities/execute-cursor/__tests__/http2-interceptor.test.ts +1 -1
  319. package/src/activities/execute-cursor/__tests__/prompt-goldens.test.ts +5 -5
  320. package/src/activities/execute-cursor/__tests__/same-identity-reproposal.test.ts +11 -13
  321. package/src/activities/execute-cursor/__tests__/sequential-gate-resume.test.ts +8 -11
  322. package/src/activities/execute-cursor/__tests__/session-lifecycle.test.ts +86 -58
  323. package/src/activities/execute-cursor/__tests__/session-store.test.ts +220 -0
  324. package/src/activities/execute-cursor/__tests__/tool-result-image.test.ts +8 -22
  325. package/src/activities/execute-cursor/__tests__/translator.test.ts +594 -0
  326. package/src/activities/execute-cursor/__tests__/turn-boundary.test.ts +8 -5
  327. package/src/activities/execute-cursor/__tests__/turn-stream.test.ts +87 -63
  328. package/src/activities/execute-cursor/adapter.ts +13 -9
  329. package/src/activities/execute-cursor/approval-policy.ts +12 -24
  330. package/src/activities/execute-cursor/approval-state.ts +66 -1
  331. package/src/activities/execute-cursor/boundary-rows.ts +1132 -0
  332. package/src/activities/execute-cursor/cursor-capabilities.ts +1 -1
  333. package/src/activities/execute-cursor/cursor-event-recorder.ts +57 -28
  334. package/src/activities/execute-cursor/fetch-interceptor.ts +1 -1
  335. package/src/activities/execute-cursor/http2-interceptor.ts +1 -1
  336. package/src/activities/execute-cursor/prompt-builder.ts +6 -6
  337. package/src/activities/execute-cursor/sdk-warmup.ts +15 -6
  338. package/src/activities/execute-cursor/service-tier.ts +1 -2
  339. package/src/activities/execute-cursor/session-lifecycle.ts +63 -109
  340. package/src/activities/execute-cursor/session-store.ts +187 -0
  341. package/src/activities/execute-cursor/sub-agent-steps.ts +188 -0
  342. package/src/activities/execute-cursor/tool-result.ts +128 -0
  343. package/src/activities/execute-cursor/translator.ts +541 -0
  344. package/src/activities/execute-cursor/turn-boundary.ts +21 -14
  345. package/src/activities/execute-cursor/turn-settle.ts +46 -34
  346. package/src/activities/execute-cursor/turn-setup.ts +5 -5
  347. package/src/activities/execute-cursor/turn-stream.ts +49 -46
  348. package/src/activities/execute-cursor/turn.ts +5 -5
  349. package/src/activities/execute-cursor/usage-pricing.ts +2 -2
  350. package/src/activities/execute-deep-agent/__test-utils__/contract-subject.ts +2 -2
  351. package/src/activities/execute-deep-agent/__test-utils__/hermetic-deep-agent.ts +23 -11
  352. package/src/activities/execute-deep-agent/__test-utils__/hitl-script.ts +1 -1
  353. package/src/activities/execute-deep-agent/__test-utils__/scripted-model-module.ts +2 -3
  354. package/src/activities/execute-deep-agent/__test-utils__/scripted-model.ts +25 -4
  355. package/src/activities/execute-deep-agent/__test-utils__/v3-event-fixtures.ts +25 -11
  356. package/src/activities/execute-deep-agent/__tests__/adapter-graph-is-sdk-free.test.ts +1 -1
  357. package/src/activities/execute-deep-agent/__tests__/adapter-is-temporal-free.test.ts +1 -1
  358. package/src/activities/execute-deep-agent/__tests__/approval-file-change.test.ts +6 -17
  359. package/src/activities/execute-deep-agent/__tests__/hermetic/file-review-capture.test.ts +25 -8
  360. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn1.status.json +2 -7
  361. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve-all-lease.turn2.status.json +4 -14
  362. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/approve.turn2.status.json +1 -5
  363. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/file-review-capture.status.json +4 -7
  364. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/gate.turn1.status.json +1 -5
  365. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn1.status.json +2 -9
  366. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/inline-artifact.turn2.status.json +2 -9
  367. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.after-tool.status.json +1 -4
  368. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/pause.loop.mid-tool.status.json +1 -4
  369. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/platform-stop.status.json +1 -4
  370. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/recursion-limit.persisted.status.json +109 -76
  371. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/reject.turn2.status.json +1 -5
  372. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn2.status.json +2 -10
  373. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sequential-gates.turn3.status.json +2 -10
  374. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/skip.turn2.status.json +1 -5
  375. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/sub-agent-delegation.status.json +3 -6
  376. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/tool-call.status.json +1 -4
  377. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/worker-shutdown.status.json +1 -4
  378. package/src/activities/execute-deep-agent/__tests__/hermetic/goldens/write-todos.status.json +92 -0
  379. package/src/activities/execute-deep-agent/__tests__/hermetic/harness-contract.test.ts +3 -3
  380. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-approve-all-lease.test.ts +9 -5
  381. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-round-trips.test.ts +3 -3
  382. package/src/activities/execute-deep-agent/__tests__/hermetic/hitl-sequential-gates.test.ts +3 -3
  383. package/src/activities/execute-deep-agent/__tests__/hermetic/inline-artifact-across-gate.test.ts +7 -6
  384. package/src/activities/execute-deep-agent/__tests__/hermetic/pause-vs-shutdown.test.ts +10 -11
  385. package/src/activities/execute-deep-agent/__tests__/hermetic/plain-turn.test.ts +4 -4
  386. package/src/activities/execute-deep-agent/__tests__/hermetic/platform-stop.test.ts +9 -8
  387. package/src/activities/execute-deep-agent/__tests__/hermetic/recursion-limit.test.ts +21 -13
  388. package/src/activities/execute-deep-agent/__tests__/hermetic/resolution-error.test.ts +2 -2
  389. package/src/activities/execute-deep-agent/__tests__/hermetic/structured-output.test.ts +7 -7
  390. package/src/activities/execute-deep-agent/__tests__/hermetic/sub-agent-delegation.test.ts +28 -12
  391. package/src/activities/execute-deep-agent/__tests__/hermetic/tool-call.test.ts +21 -21
  392. package/src/activities/execute-deep-agent/__tests__/hermetic/workspace-lock-timeout.test.ts +5 -5
  393. package/src/activities/execute-deep-agent/__tests__/hermetic/write-todos.test.ts +160 -0
  394. package/src/activities/execute-deep-agent/__tests__/inline-publisher.test.ts +35 -30
  395. package/src/activities/execute-deep-agent/__tests__/prompt-builder.test.ts +3 -4
  396. package/src/activities/execute-deep-agent/__tests__/prompt-goldens.test.ts +12 -10
  397. package/src/activities/execute-deep-agent/__tests__/scripted-model.test.ts +13 -3
  398. package/src/activities/execute-deep-agent/__tests__/streaming-side-effects.test.ts +26 -18
  399. package/src/activities/execute-deep-agent/__tests__/subagent-wiring.test.ts +1 -1
  400. package/src/activities/execute-deep-agent/__tests__/{subagent-tracker.test.ts → translator-subagents.test.ts} +76 -57
  401. package/src/activities/execute-deep-agent/__tests__/{v3-status-builder.test.ts → translator-through-builder.test.ts} +213 -299
  402. package/src/activities/execute-deep-agent/__tests__/translator.test.ts +505 -0
  403. package/src/activities/execute-deep-agent/__tests__/turn-stream.test.ts +11 -29
  404. package/src/activities/execute-deep-agent/adapter.ts +1 -1
  405. package/src/activities/execute-deep-agent/approval-file-change.ts +20 -22
  406. package/src/activities/execute-deep-agent/deep-agent-capabilities.ts +2 -2
  407. package/src/activities/execute-deep-agent/hitl.ts +2 -2
  408. package/src/activities/execute-deep-agent/inline-publisher.ts +16 -5
  409. package/src/activities/execute-deep-agent/prompt-builder.ts +6 -7
  410. package/src/activities/execute-deep-agent/streaming-side-effects.ts +22 -31
  411. package/src/activities/execute-deep-agent/subagent-transformer.ts +3 -3
  412. package/src/activities/execute-deep-agent/translator.ts +463 -0
  413. package/src/activities/execute-deep-agent/turn-settle.ts +35 -43
  414. package/src/activities/execute-deep-agent/turn-setup.ts +8 -8
  415. package/src/activities/execute-deep-agent/turn-stream.ts +53 -51
  416. package/src/activities/execute-deep-agent/turn.ts +3 -3
  417. package/src/config.ts +2 -2
  418. package/src/harness/README.md +335 -0
  419. package/src/harness/__tests__/approval-decisions.test.ts +2 -2
  420. package/src/harness/__tests__/capture.test.ts +3 -3
  421. package/src/harness/__tests__/import-direction.test.ts +3 -2
  422. package/src/harness/__tests__/mount-skills.test.ts +4 -1
  423. package/src/harness/__tests__/readme-index.test.ts +339 -0
  424. package/src/harness/__tests__/run-turn.test.ts +131 -6
  425. package/src/harness/__tests__/transcript-is-engine-free.test.ts +83 -0
  426. package/src/harness/__tests__/transcript-writers.test.ts +191 -0
  427. package/src/harness/__tests__/turn-attachments-vision.test.ts +5 -2
  428. package/src/harness/__tests__/turn-context.test.ts +5 -5
  429. package/src/harness/approval-decisions.ts +1 -1
  430. package/src/harness/capabilities.ts +21 -11
  431. package/src/harness/capture.ts +4 -4
  432. package/src/harness/persist-chokepoint.ts +3 -3
  433. package/src/harness/registry.ts +2 -2
  434. package/src/harness/run-turn.ts +33 -9
  435. package/src/harness/stop-controller.ts +1 -1
  436. package/src/harness/terminal-table.ts +7 -7
  437. package/src/harness/transcript/__tests__/builder.test.ts +975 -0
  438. package/src/harness/transcript/__tests__/state.test.ts +143 -0
  439. package/src/harness/transcript/builder.ts +755 -0
  440. package/src/harness/transcript/events.ts +262 -0
  441. package/src/harness/transcript/state.ts +167 -0
  442. package/src/harness/turn-context.ts +61 -46
  443. package/src/harness/types.ts +64 -22
  444. package/src/harness/usage-accumulator.ts +2 -2
  445. package/src/harness-adapters.ts +5 -4
  446. package/src/middleware/__tests__/cost-advisory.test.ts +2 -2
  447. package/src/middleware/approval-gate.ts +7 -74
  448. package/src/middleware/cost-advisory.ts +3 -3
  449. package/src/middleware/index.ts +1 -1
  450. package/src/runner-manager.ts +1 -1
  451. package/src/shared/__tests__/approval-policy.test.ts +45 -0
  452. package/src/shared/__tests__/args-preview.test.ts +40 -20
  453. package/src/shared/__tests__/attachment-naming.test.ts +1 -1
  454. package/src/shared/__tests__/attachment-resolver.test.ts +5 -5
  455. package/src/shared/__tests__/attachment-zip.test.ts +1 -1
  456. package/src/shared/__tests__/blueprint-resolver.test.ts +1 -1
  457. package/src/shared/__tests__/cost-guard.test.ts +1 -1
  458. package/src/shared/__tests__/exact-apply.test.ts +2 -1
  459. package/src/shared/__tests__/persist-decision.test.ts +19 -33
  460. package/src/shared/__tests__/prompt-sections.test.ts +1 -1
  461. package/src/shared/__tests__/stamp-flowed-rows.test.ts +1 -1
  462. package/src/shared/__tests__/status-offload.test.ts +1 -1
  463. package/src/shared/__tests__/streaming-scheduler.test.ts +8 -9
  464. package/src/shared/__tests__/todos.test.ts +1 -1
  465. package/src/shared/__tests__/tool-row.test.ts +1 -1
  466. package/src/shared/approval-policy.ts +95 -0
  467. package/src/shared/args-preview.ts +51 -42
  468. package/src/shared/attachment-resolver.ts +4 -4
  469. package/src/shared/attachment-vision.ts +2 -1
  470. package/src/shared/attachment-zip.ts +2 -2
  471. package/src/shared/cost-guard.ts +2 -2
  472. package/src/shared/exact-apply.ts +1 -1
  473. package/src/shared/execution-context.ts +2 -2
  474. package/src/shared/extract-structured-output.ts +2 -2
  475. package/src/shared/filereview/__tests__/capture.test.ts +9 -5
  476. package/src/shared/filereview/__tests__/git-substrate.test.ts +4 -1
  477. package/src/shared/filereview/__tests__/proxy-reconcile.test.ts +3 -3
  478. package/src/shared/filereview/cas-touched.ts +2 -2
  479. package/src/shared/heartbeat.ts +1 -1
  480. package/src/shared/llm-backend.ts +0 -4
  481. package/src/shared/model-error.ts +1 -2
  482. package/src/shared/persist-decision.ts +19 -28
  483. package/src/shared/prompt-sections.ts +4 -4
  484. package/src/shared/skill-resolver.ts +3 -3
  485. package/src/shared/status-offload.ts +2 -2
  486. package/src/shared/streaming-scheduler.ts +8 -13
  487. package/src/shared/subagent-rows.ts +2 -2
  488. package/src/shared/todos.ts +3 -3
  489. package/src/shared/tool-row.ts +38 -2
  490. package/src/shared/worker-shutdown.ts +1 -1
  491. package/src/shared/workspace/__tests__/git-source.test.ts +3 -3
  492. package/src/shared/workspace/__tests__/provisioner.test.ts +5 -5
  493. package/src/shared/workspace/__tests__/session-provision.test.ts +2 -2
  494. package/src/shared/workspace/__tests__/writeback-coordinator.integration.test.ts +8 -9
  495. package/src/shared/workspace/__tests__/writeback-coordinator.test.ts +25 -25
  496. package/src/shared/workspace/provisioner.ts +1 -1
  497. package/src/shared/workspace/session-provision.ts +1 -1
  498. package/src/shared/workspace/sources/empty.ts +2 -2
  499. package/src/shared/workspace/sources/git.ts +3 -4
  500. package/src/shared/workspace/sources/local-path.ts +5 -6
  501. package/src/shared/workspace/stigmer-link.ts +1 -1
  502. package/src/shared/workspace/types.ts +2 -5
  503. package/src/shared/workspace/writeback-coordinator.ts +23 -12
  504. package/dist/activities/execute-cursor/delta-enricher.d.ts +0 -87
  505. package/dist/activities/execute-cursor/delta-enricher.js +0 -265
  506. package/dist/activities/execute-cursor/delta-enricher.js.map +0 -1
  507. package/dist/activities/execute-cursor/message-translator.js +0 -2040
  508. package/dist/activities/execute-cursor/message-translator.js.map +0 -1
  509. package/dist/activities/execute-cursor/todo-tracker.d.ts +0 -40
  510. package/dist/activities/execute-cursor/todo-tracker.js +0 -80
  511. package/dist/activities/execute-cursor/todo-tracker.js.map +0 -1
  512. package/dist/activities/execute-deep-agent/execution-state.d.ts +0 -54
  513. package/dist/activities/execute-deep-agent/execution-state.js +0 -68
  514. package/dist/activities/execute-deep-agent/execution-state.js.map +0 -1
  515. package/dist/activities/execute-deep-agent/status-builder-shared.d.ts +0 -65
  516. package/dist/activities/execute-deep-agent/status-builder-shared.js +0 -90
  517. package/dist/activities/execute-deep-agent/status-builder-shared.js.map +0 -1
  518. package/dist/activities/execute-deep-agent/subagent-tracker.d.ts +0 -113
  519. package/dist/activities/execute-deep-agent/subagent-tracker.js +0 -400
  520. package/dist/activities/execute-deep-agent/subagent-tracker.js.map +0 -1
  521. package/dist/activities/execute-deep-agent/v3-events.d.ts +0 -102
  522. package/dist/activities/execute-deep-agent/v3-events.js +0 -35
  523. package/dist/activities/execute-deep-agent/v3-events.js.map +0 -1
  524. package/dist/activities/execute-deep-agent/v3-protocol-normalizer.d.ts +0 -15
  525. package/dist/activities/execute-deep-agent/v3-protocol-normalizer.js +0 -235
  526. package/dist/activities/execute-deep-agent/v3-protocol-normalizer.js.map +0 -1
  527. package/dist/activities/execute-deep-agent/v3-status-builder.d.ts +0 -111
  528. package/dist/activities/execute-deep-agent/v3-status-builder.js +0 -457
  529. package/dist/activities/execute-deep-agent/v3-status-builder.js.map +0 -1
  530. package/dist/shared/execution-status-writer.d.ts +0 -31
  531. package/dist/shared/execution-status-writer.js +0 -43
  532. package/dist/shared/execution-status-writer.js.map +0 -1
  533. package/src/activities/execute-cursor/__tests__/delta-enricher.test.ts +0 -310
  534. package/src/activities/execute-cursor/__tests__/message-translator.test.ts +0 -1033
  535. package/src/activities/execute-cursor/__tests__/todo-tracker.test.ts +0 -498
  536. package/src/activities/execute-cursor/delta-enricher.ts +0 -307
  537. package/src/activities/execute-cursor/message-translator.ts +0 -2319
  538. package/src/activities/execute-cursor/todo-tracker.ts +0 -91
  539. package/src/activities/execute-deep-agent/__tests__/execution-state-extended.test.ts +0 -148
  540. package/src/activities/execute-deep-agent/__tests__/execution-state.test.ts +0 -154
  541. package/src/activities/execute-deep-agent/__tests__/status-builder-shared.test.ts +0 -47
  542. package/src/activities/execute-deep-agent/__tests__/v3-protocol-normalizer.test.ts +0 -324
  543. package/src/activities/execute-deep-agent/execution-state.ts +0 -78
  544. package/src/activities/execute-deep-agent/status-builder-shared.ts +0 -142
  545. package/src/activities/execute-deep-agent/subagent-tracker.ts +0 -479
  546. package/src/activities/execute-deep-agent/v3-events.ts +0 -153
  547. package/src/activities/execute-deep-agent/v3-protocol-normalizer.ts +0 -264
  548. package/src/activities/execute-deep-agent/v3-status-builder.ts +0 -565
  549. package/src/shared/execution-status-writer.ts +0 -56
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Hermetic golden: the agent's TO-DO LIST on the native harness — the model
3
+ * proposes deepagents' built-in `write_todos`, the tools node runs it for
4
+ * real, and the builder projects the list into `status.todos`.
5
+ *
6
+ * Invariant pinned: `TranscriptBuilder.handleToolStarted` classifies
7
+ * the row `ToolKind.TODO` by name; `handleToolFinished` projects `tc.args.todos`
8
+ * into `status.todos` through the shared `applyTodoUpdate` as a FULL REPLACE
9
+ * (deepagents' schema has no `merge`), keyed `todo-<i>`, and KEEPS the row in
10
+ * the transcript — the clients filter `ToolKind.TODO` from the thread. As an
11
+ * ungated built-in it carries `argsPreview` like every row since #1097
12
+ * (until then native stamped a preview on gated rows only).
13
+ *
14
+ * What the golden shows:
15
+ * - The row sits on the AI message whose text proposed it, "Planning the two
16
+ * steps." (since #1097; until then on an empty message between the two
17
+ * texts — see `tool-call.test.ts`'s header).
18
+ * - The row's `result` is the tool's confirmation text, "Updated todo list
19
+ * to [...]" (since #1097). deepagents' `write_todos` returns a
20
+ * LangGraph `Command` (`{ lg_name: "Command", update: { todos, messages:
21
+ * [ToolMessage] } }`); until then the native extractor unwrapped a
22
+ * LangChain `ToolMessage` envelope but not a `Command`, so the row carried
23
+ * the whole serialized Command — the todos array a second time and the
24
+ * text nested inside it (pinned as found when this net opened,
25
+ * regenerated in #1097 with that one hunk).
26
+ *
27
+ * The #1097 moves, as landed (2026-09-14): the
28
+ * row joined `messages[0]` ("Planning the two steps.") and the empty message
29
+ * went; the row gained `argsPreview`, the elided preview of
30
+ * its `args`. `todos` is byte-identical (the builder keeps native's
31
+ * full-replace: `write_todos` never sends `merge`). Any other hunk is a pause.
32
+ *
33
+ * Why this net exists: none of the twenty-three earlier native goldens
34
+ * carried a todo, and #1097 moved the projection from the native builder
35
+ * into the canonical one.
36
+ *
37
+ * Regenerate ONLY after a deliberate behavior change:
38
+ * npx vitest run src/activities/execute-deep-agent/__tests__/hermetic -u
39
+ */
40
+
41
+ import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
42
+ import { toJson } from "@bufbuild/protobuf";
43
+ import { AgentExecutionStatusSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
44
+ import {
45
+ ExecutionPhase,
46
+ MessageType,
47
+ TodoStatus,
48
+ ToolCallStatus,
49
+ ToolKind,
50
+ } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
51
+
52
+ vi.mock("../../../../shared/model-client.js", async () =>
53
+ (await import("../../__test-utils__/scripted-model-module.js")).scriptedModelClientModule(),
54
+ );
55
+ vi.mock("../../../../client/stigmer-client.js", async () =>
56
+ (await import("../../../../__test-utils__/hermetic-activity.js")).hermeticStigmerClientModule(),
57
+ );
58
+
59
+ import {
60
+ ScriptedClock,
61
+ createHermeticEnvironment,
62
+ type HermeticEnvironment,
63
+ } from "../../../../__test-utils__/hermetic-activity.js";
64
+ import { stubRegistryFetch } from "../../../../__test-utils__/model-registry-fixture.js";
65
+ import {
66
+ beginDeepAgentScenario,
67
+ deepAgentExecutionRecord,
68
+ runDeepAgentTurn,
69
+ } from "../../__test-utils__/hermetic-deep-agent.js";
70
+
71
+ const CALL_ID = "call-hermetic-todos-0001";
72
+ const USER_MESSAGE = "Plan the two steps.";
73
+ const TEXT_PLAN = "Planning the two steps.";
74
+ /** deepagents' `write_todos` schema: `{ content, status }` per item, three statuses, no id, no merge. */
75
+ const TODOS = [
76
+ { content: "Read the fixture", status: "pending" },
77
+ { content: "Summarise it", status: "in_progress" },
78
+ ];
79
+ const TEXT_CLOSING = "The plan is written.";
80
+
81
+ describe("ExecuteDeepAgent hermetic — write_todos", () => {
82
+ let env: HermeticEnvironment;
83
+ let registry: ReturnType<typeof stubRegistryFetch>;
84
+ const clock = new ScriptedClock();
85
+
86
+ beforeAll(() => {
87
+ env = createHermeticEnvironment();
88
+ registry = stubRegistryFetch();
89
+ clock.install();
90
+ });
91
+
92
+ afterAll(() => {
93
+ clock.uninstall();
94
+ registry.restore();
95
+ env.dispose();
96
+ });
97
+
98
+ it("projects the completed write into status.todos, keeps the row, and completes", async () => {
99
+ // ── Arrange ──────────────────────────────────────────────────────────────
100
+ const record = deepAgentExecutionRecord({ message: USER_MESSAGE });
101
+ const scenario = beginDeepAgentScenario({
102
+ env,
103
+ clock,
104
+ record,
105
+ script: () => ({
106
+ turns: [
107
+ {
108
+ text: TEXT_PLAN,
109
+ toolCalls: [{ id: CALL_ID, name: "write_todos", args: { todos: TODOS } }],
110
+ usage: { inputTokens: 1_400, outputTokens: 70 },
111
+ },
112
+ { text: TEXT_CLOSING, usage: { inputTokens: 1_600, outputTokens: 20 } },
113
+ ],
114
+ }),
115
+ });
116
+
117
+ // ── Act ──────────────────────────────────────────────────────────────────
118
+ const invocation = await runDeepAgentTurn(scenario);
119
+
120
+ // ── Assert: outcome ──────────────────────────────────────────────────────
121
+ expect(invocation.outcome.kind).toBe("returned");
122
+ expect((invocation.outcome as { value: Record<string, unknown> }).value.phase).toBe("EXECUTION_COMPLETED");
123
+ expect(record.persistedPhases.at(-1)).toBe(ExecutionPhase.EXECUTION_COMPLETED);
124
+
125
+ // ── Assert: the row stays in the transcript, classified TODO ─────────────
126
+ const rows = record.toolCalls();
127
+ expect(rows).toHaveLength(1);
128
+ const row = rows[0];
129
+ expect(row.id).toBe(CALL_ID);
130
+ expect(row.name).toBe("write_todos");
131
+ expect(row.toolKind).toBe(ToolKind.TODO);
132
+ expect(row.status).toBe(ToolCallStatus.TOOL_CALL_COMPLETED);
133
+ expect(row.args).toEqual({ todos: TODOS });
134
+ expect(JSON.parse(row.argsPreview), "every row carries its elided preview").toEqual({ todos: TODOS });
135
+ expect(row.requiresApproval).toBe(false);
136
+ // Since #1097: the ToolMessage's content, never the serialized Command.
137
+ expect(row.result.startsWith("Updated todo list to"), "the tool's own confirmation text is what the row carries").toBe(true);
138
+ expect(row.result).not.toContain("lg_name");
139
+
140
+ // ── Assert: the transcript — the row beside the text that proposed it ──
141
+ const final = record.lastFullStatus!;
142
+ const ai = final.messages.filter((m) => m.type === MessageType.MESSAGE_AI);
143
+ expect(ai.map((m) => [m.content, m.toolCalls.map((tc) => tc.id)])).toEqual([
144
+ [TEXT_PLAN, [CALL_ID]],
145
+ [TEXT_CLOSING, []],
146
+ ]);
147
+
148
+ // ── Assert: the projection, by key (byte-identical across the swap) ─────
149
+ expect(Object.keys(final.todos).sort()).toEqual(["todo-0", "todo-1"]);
150
+ expect([final.todos["todo-0"].content, final.todos["todo-0"].status]).toEqual(["Read the fixture", TodoStatus.TODO_PENDING]);
151
+ expect([final.todos["todo-1"].content, final.todos["todo-1"].status]).toEqual(["Summarise it", TodoStatus.TODO_IN_PROGRESS]);
152
+
153
+ // ── Assert: hermeticity ──────────────────────────────────────────────────
154
+ expect(registry.urls.every((u) => u.includes("/model-registry"))).toBe(true);
155
+
156
+ // ── Assert: the golden ───────────────────────────────────────────────────
157
+ const json = JSON.stringify(toJson(AgentExecutionStatusSchema, final), null, 2) + "\n";
158
+ await expect(json).toMatchFileSnapshot("./goldens/write-todos.status.json");
159
+ });
160
+ });
@@ -4,19 +4,21 @@ import { writeFile, mkdir } from "node:fs/promises";
4
4
  import { join } from "node:path";
5
5
  import { tmpdir } from "node:os";
6
6
  import { create } from "@bufbuild/protobuf";
7
- import { AgentExecutionStatusSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
7
+ import { type AgentExecutionStatus, AgentExecutionStatusSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
8
8
  import { ExecutionArtifactKind } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
9
9
  import { InlinePublisher } from "../inline-publisher.js";
10
- import { V3StatusBuilder } from "../v3-status-builder.js";
10
+ import { TranscriptBuilder } from "../../../harness/transcript/builder.js";
11
11
  import { LocalWorkspaceBackend } from "../../../shared/workspace/local-backend.js";
12
12
  import type { ArtifactStorage } from "../../../shared/artifact-storage.js";
13
13
  import { makeInMemoryArtifactStorage } from "../../../__test-utils__/fake-artifact-storage.js";
14
14
  import type { WorkspaceBackend } from "../../../shared/workspace/types.js";
15
15
 
16
- // The publisher writes artifacts through the transcript builder's
17
- // `ExecutionStatusWriter` face (`addArtifact`); the one builder since S3 M2b.
18
- function makeStatusBuilder(): V3StatusBuilder {
19
- return new V3StatusBuilder("exec-test", create(AgentExecutionStatusSchema, {}));
16
+ // The publisher registers artifacts on the transcript builder (`addArtifact`);
17
+ // the one builder since #1096.
18
+ /** A builder and the status it builds into: the test writes through `sb` and reads `status`, as production reads `TurnSink.status`. */
19
+ function makeStatusBuilder(): { sb: TranscriptBuilder; status: AgentExecutionStatus } {
20
+ const status = create(AgentExecutionStatusSchema, {});
21
+ return { sb: new TranscriptBuilder("exec-test", status), status };
20
22
  }
21
23
 
22
24
  function mockWorkspaceBackend(files: Record<string, string>): WorkspaceBackend {
@@ -55,19 +57,20 @@ function sha256(content: string): string {
55
57
  }
56
58
 
57
59
  describe("InlinePublisher", () => {
58
- let sb: V3StatusBuilder;
60
+ let sb: TranscriptBuilder;
61
+ let status: AgentExecutionStatus;
59
62
  let storage: ReturnType<typeof mockArtifactStorage>;
60
63
  let backend: WorkspaceBackend;
61
64
  let publisher: InlinePublisher;
62
65
 
63
66
  beforeEach(() => {
64
- sb = makeStatusBuilder();
67
+ ({ sb, status } = makeStatusBuilder());
65
68
  storage = mockArtifactStorage();
66
69
  backend = mockWorkspaceBackend({ "src/main.ts": "console.log('hello');" });
67
70
  publisher = new InlinePublisher({
68
71
  workspaceBackend: backend,
69
72
  artifactStorage: storage,
70
- statusWriter: sb,
73
+ artifacts: sb,
71
74
  executionId: "exec-123",
72
75
  });
73
76
  });
@@ -76,9 +79,9 @@ describe("InlinePublisher", () => {
76
79
  await publisher.publish("src/main.ts");
77
80
 
78
81
  expect(storage.uploadedKeys).toEqual(["artifacts/exec-123/main.ts"]);
79
- expect(sb.currentStatus.artifacts).toHaveLength(1);
82
+ expect(status.artifacts).toHaveLength(1);
80
83
 
81
- const artifact = sb.currentStatus.artifacts[0];
84
+ const artifact = status.artifacts[0];
82
85
  expect(artifact.name).toBe("main.ts");
83
86
  expect(artifact.sandboxPath).toBe("src/main.ts");
84
87
  expect(artifact.kind).toBe(ExecutionArtifactKind.FILE);
@@ -90,8 +93,8 @@ describe("InlinePublisher", () => {
90
93
  it("strips leading slashes from paths", async () => {
91
94
  await publisher.publish("/src/main.ts");
92
95
 
93
- expect(sb.currentStatus.artifacts).toHaveLength(1);
94
- expect(sb.currentStatus.artifacts[0].sandboxPath).toBe("src/main.ts");
96
+ expect(status.artifacts).toHaveLength(1);
97
+ expect(status.artifacts[0].sandboxPath).toBe("src/main.ts");
95
98
  });
96
99
 
97
100
  it("deduplicates by path + content hash", async () => {
@@ -99,7 +102,7 @@ describe("InlinePublisher", () => {
99
102
  await publisher.publish("src/main.ts");
100
103
 
101
104
  expect(storage.uploadedKeys).toHaveLength(1);
102
- expect(sb.currentStatus.artifacts).toHaveLength(1);
105
+ expect(status.artifacts).toHaveLength(1);
103
106
  });
104
107
 
105
108
  it("re-publishes when content changes", async () => {
@@ -109,8 +112,8 @@ describe("InlinePublisher", () => {
109
112
  await publisher.publish("src/main.ts");
110
113
 
111
114
  expect(storage.uploadedKeys).toHaveLength(2);
112
- expect(sb.currentStatus.artifacts).toHaveLength(1);
113
- expect(sb.currentStatus.artifacts[0].contentHash).toBe(sha256("updated content"));
115
+ expect(status.artifacts).toHaveLength(1);
116
+ expect(status.artifacts[0].contentHash).toBe(sha256("updated content"));
114
117
  });
115
118
 
116
119
  it("exposes published paths for dedup by auto-publish", async () => {
@@ -128,13 +131,13 @@ describe("InlinePublisher", () => {
128
131
  const pub = new InlinePublisher({
129
132
  workspaceBackend: failBackend,
130
133
  artifactStorage: storage,
131
- statusWriter: sb,
134
+ artifacts: sb,
132
135
  executionId: "exec-err",
133
136
  });
134
137
 
135
138
  await pub.publish("nonexistent.txt");
136
139
 
137
- expect(sb.currentStatus.artifacts).toHaveLength(0);
140
+ expect(status.artifacts).toHaveLength(0);
138
141
  expect(warnSpy).toHaveBeenCalledWith(
139
142
  expect.stringContaining("[InlinePublisher]"),
140
143
  );
@@ -149,7 +152,7 @@ describe("InlinePublisher", () => {
149
152
 
150
153
  await publisher.publish("src/main.ts");
151
154
 
152
- expect(sb.currentStatus.artifacts).toHaveLength(0);
155
+ expect(status.artifacts).toHaveLength(0);
153
156
  expect(warnSpy).toHaveBeenCalled();
154
157
  warnSpy.mockRestore();
155
158
  });
@@ -160,7 +163,7 @@ describe("InlinePublisher", () => {
160
163
  const expected = createHash("sha256")
161
164
  .update(Buffer.from("console.log('hello');", "utf-8"))
162
165
  .digest("hex");
163
- expect(sb.currentStatus.artifacts[0].contentHash).toBe(expected);
166
+ expect(status.artifacts[0].contentHash).toBe(expected);
164
167
  });
165
168
 
166
169
  it("never publishes a secret-like file to artifact storage (design doc 12, D4)", async () => {
@@ -172,14 +175,14 @@ describe("InlinePublisher", () => {
172
175
  const pub = new InlinePublisher({
173
176
  workspaceBackend: secretBackend,
174
177
  artifactStorage: storage,
175
- statusWriter: sb,
178
+ artifacts: sb,
176
179
  executionId: "exec-secret",
177
180
  });
178
181
 
179
182
  await pub.publish(".env");
180
183
 
181
184
  expect(storage.uploadedKeys).toHaveLength(0);
182
- expect(sb.currentStatus.artifacts).toHaveLength(0);
185
+ expect(status.artifacts).toHaveLength(0);
183
186
  expect(readSpy).not.toHaveBeenCalled(); // withheld before the file is even read
184
187
  expect(pub.publishedPaths.size).toBe(0);
185
188
  });
@@ -189,7 +192,7 @@ describe("InlinePublisher", () => {
189
192
  const pub = new InlinePublisher({
190
193
  workspaceBackend: jsonBackend,
191
194
  artifactStorage: storage,
192
- statusWriter: sb,
195
+ artifacts: sb,
193
196
  executionId: "exec-ct",
194
197
  });
195
198
 
@@ -209,21 +212,22 @@ describe("InlinePublisher with LocalWorkspaceBackend (disk-backed)", () => {
209
212
  await mkdir(join(dir, "src"), { recursive: true });
210
213
  await writeFile(join(dir, "src/app.ts"), "export const x = 42;", "utf-8");
211
214
 
212
- const sb = new V3StatusBuilder("exec-disk", create(AgentExecutionStatusSchema, {}));
215
+ const status = create(AgentExecutionStatusSchema, {});
216
+ const sb = new TranscriptBuilder("exec-disk", status);
213
217
  const storage = mockArtifactStorage();
214
218
  const backend = new LocalWorkspaceBackend(dir);
215
219
 
216
220
  const publisher = new InlinePublisher({
217
221
  workspaceBackend: backend,
218
222
  artifactStorage: storage,
219
- statusWriter: sb,
223
+ artifacts: sb,
220
224
  executionId: "exec-disk",
221
225
  });
222
226
 
223
227
  await publisher.publish("src/app.ts");
224
228
 
225
- expect(sb.currentStatus.artifacts).toHaveLength(1);
226
- const artifact = sb.currentStatus.artifacts[0];
229
+ expect(status.artifacts).toHaveLength(1);
230
+ const artifact = status.artifacts[0];
227
231
  expect(artifact.name).toBe("app.ts");
228
232
  expect(artifact.sandboxPath).toBe("src/app.ts");
229
233
  expect(artifact.kind).toBe(ExecutionArtifactKind.FILE);
@@ -237,20 +241,21 @@ describe("InlinePublisher with LocalWorkspaceBackend (disk-backed)", () => {
237
241
  const dir = join(tmpdir(), `stigmer-publisher-test-${Date.now()}`);
238
242
  await mkdir(dir, { recursive: true });
239
243
 
240
- const sb = new V3StatusBuilder("exec-miss", create(AgentExecutionStatusSchema, {}));
244
+ const status = create(AgentExecutionStatusSchema, {});
245
+ const sb = new TranscriptBuilder("exec-miss", status);
241
246
  const storage = mockArtifactStorage();
242
247
  const backend = new LocalWorkspaceBackend(dir);
243
248
 
244
249
  const publisher = new InlinePublisher({
245
250
  workspaceBackend: backend,
246
251
  artifactStorage: storage,
247
- statusWriter: sb,
252
+ artifacts: sb,
248
253
  executionId: "exec-miss",
249
254
  });
250
255
 
251
256
  await publisher.publish("nonexistent.ts");
252
257
 
253
- expect(sb.currentStatus.artifacts).toHaveLength(0);
258
+ expect(status.artifacts).toHaveLength(0);
254
259
  expect(storage.uploadedKeys).toHaveLength(0);
255
260
  expect(warnSpy).toHaveBeenCalledWith(
256
261
  expect.stringContaining("[InlinePublisher]"),
@@ -2,13 +2,12 @@ import { describe, it, expect } from "vitest";
2
2
  import { InteractionMode } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
3
3
  import { buildEnhancedSystemPrompt, composeUserMessage } from "../prompt-builder.js";
4
4
  import { PLAN_MODE_DIRECTIVE } from "../../../shared/plan-mode-prompt.js";
5
- import { SourceType } from "../../../shared/workspace/types.js";
6
5
  import type { ProvisionResult } from "../../../shared/workspace/types.js";
7
6
 
8
7
  function makeProvisionResult(overrides: Partial<ProvisionResult> = {}): ProvisionResult {
9
8
  return {
10
9
  rootDir: "/workspace/project",
11
- sourceType: SourceType.LOCAL_PATH,
10
+ sourceType: "local_path",
12
11
  consumedKeys: [],
13
12
  workspaceDescription: "User project directory at /workspace/project",
14
13
  entryName: "project",
@@ -266,7 +265,7 @@ describe("buildEnhancedSystemPrompt", () => {
266
265
  instructions: "Test",
267
266
  provisionResults: [
268
267
  makeProvisionResult({
269
- sourceType: SourceType.GIT_REPO,
268
+ sourceType: "git_repo",
270
269
  entryName: "my-repo",
271
270
  rootDir: "/workspace/my-repo",
272
271
  gitMetadata: {
@@ -277,7 +276,7 @@ describe("buildEnhancedSystemPrompt", () => {
277
276
  },
278
277
  }),
279
278
  makeProvisionResult({
280
- sourceType: SourceType.EMPTY,
279
+ sourceType: "empty",
281
280
  entryName: "scratch",
282
281
  rootDir: "/workspace/scratch",
283
282
  }),
@@ -2,13 +2,14 @@
2
2
  * The native system prompt, whole, as goldens.
3
3
  *
4
4
  * Every other prompt test in this directory asserts with `toContain`; the
5
- * hermetic goldens are status JSON and never see a prompt. So until S3 M5 no
5
+ * hermetic goldens are status JSON and never see a prompt. So until #1096 no
6
6
  * test pinned a rendered prompt byte for byte, and the relevance-filtered
7
7
  * `## Skills` section (eight or more skills, `turn-setup.ts`
8
8
  * `renderRootSkillsSection`) had no test at all. These goldens are the
9
9
  * photograph taken BEFORE the shared prompt glue moved into
10
- * `shared/prompt-sections.ts` (S3 M5, Q-M5-1), so the move could be proven
11
- * byte-identical — the same discipline M0 applied to the activity's status.
10
+ * `shared/prompt-sections.ts` (#1096), so the move could be proven
11
+ * byte-identical — the same discipline the hermetic net applied to the
12
+ * activity's status.
12
13
  *
13
14
  * Why bytes matter here beyond taste: `ScriptedModel` tells its scripted
14
15
  * roles apart by the system prompt's text (`__test-utils__/scripted-model.ts`
@@ -25,9 +26,10 @@
25
26
  *
26
27
  * The goldens are taken through `turn-setup.ts` `composeSystemPrompt`, the
27
28
  * production mapping from the runtime's resolved record to the builder's
28
- * input, so they pin the mapping too, not a copy of it. (C0 photographed the
29
- * prompt through a field-for-field copy of the mapping as it then sat inline
30
- * in `buildEngine`; C1 extracted it and re-took the goldens through the
29
+ * input, so they pin the mapping too, not a copy of it. (The first cut
30
+ * photographed the prompt through a field-for-field copy of the mapping as
31
+ * it then sat inline in `buildEngine`; the next extracted it and re-took the
32
+ * goldens through the
31
33
  * extraction — byte-identical, which is the proof the extraction is one.)
32
34
  *
33
35
  * A golden moves only under a ruling quoted in this header; never a quiet
@@ -49,7 +51,7 @@ import type { TurnInput } from "../../../harness/types.js";
49
51
  import type { ResolvedAttachment } from "../../../shared/attachment-resolver.js";
50
52
  import type { SkillMetadata } from "../../../shared/skill-resolver.js";
51
53
  import type { RecalledMemoriesContent } from "../../../shared/recalled-memories.js";
52
- import { SourceType, type ProvisionResult } from "../../../shared/workspace/types.js";
54
+ import type { ProvisionResult } from "../../../shared/workspace/types.js";
53
55
  import { buildEnhancedSystemPrompt } from "../prompt-builder.js";
54
56
  import { composeSystemPrompt } from "../turn-setup.js";
55
57
 
@@ -81,7 +83,7 @@ const THREE_SKILLS: readonly SkillMetadata[] = NINE_SKILLS.slice(0, 3);
81
83
  const PROVISION_RESULTS: readonly ProvisionResult[] = [
82
84
  {
83
85
  rootDir: "/ws/app",
84
- sourceType: SourceType.GIT_REPO,
86
+ sourceType: "git_repo",
85
87
  consumedKeys: [],
86
88
  workspaceDescription: "The payments service, cloned from git.",
87
89
  entryName: "app",
@@ -90,7 +92,7 @@ const PROVISION_RESULTS: readonly ProvisionResult[] = [
90
92
  },
91
93
  {
92
94
  rootDir: "/ws/docs",
93
- sourceType: SourceType.LOCAL_PATH,
95
+ sourceType: "local_path",
94
96
  consumedKeys: [],
95
97
  workspaceDescription: "The docs folder on the user's machine.",
96
98
  entryName: "docs",
@@ -209,7 +211,7 @@ async function systemPromptOf(input: TurnInput): Promise<string> {
209
211
  // Goldens
210
212
  // ---------------------------------------------------------------------------
211
213
 
212
- describe("native system prompt goldens (S3 M5, Q-M5-1)", () => {
214
+ describe("native system prompt goldens", () => {
213
215
  it("everything at once, nine skills so the relevance filter fires", async () => {
214
216
  const prompt = await systemPromptOf(everythingInput({ skills: NINE_SKILLS }));
215
217
  await expect(prompt).toMatchFileSnapshot("./goldens/system-prompt.everything.prompt.md");
@@ -25,7 +25,7 @@
25
25
  * deepagents graph aborted mid-hang through the run's own signal, the
26
26
  * parked model unparks, the stream rejects with the abort, and the
27
27
  * process sees no orphaned rejection — the posture the contract kit's
28
- * hang arms and the runtime's stall watchdog rely on (S3 M2a F-M2a-18
28
+ * hang arms and the runtime's stall watchdog rely on (#1096
29
29
  * measured one orphan for a forced mid-step abort of a WEDGED engine;
30
30
  * an engine that honours its signal leaves none, and this arm is where
31
31
  * that fact is pinned).
@@ -102,12 +102,22 @@ describe("ScriptedModel — turns are indexed by the transcript, not by a counte
102
102
  expect(replayed.tool_calls?.[0]?.id).toBe("call_b");
103
103
  });
104
104
 
105
- it("reports the role and round to onTurn before rendering", async () => {
105
+ it("reports the role, the round and the calls it answers to onTurn before rendering", async () => {
106
106
  const seen: ScriptedTurnInfo[] = [];
107
107
  const model = new ScriptedModel(() => script, [], { onTurn: (info) => void seen.push(info) });
108
108
  const bound = model.bindTools([{ name: "probe" }]);
109
109
  await bound.invoke(transcriptWithRounds(2));
110
- expect(seen).toEqual([{ boundToolNames: ["probe"], round: 2 }]);
110
+ // The prior calls are the LAST AI message's — the results this turn
111
+ // answers — read from the transcript, not the script.
112
+ expect(seen).toEqual([{ boundToolNames: ["probe"], round: 2, priorToolCallIds: ["call_1"] }]);
113
+ });
114
+
115
+ it("reports no prior calls on a first turn or after a text-only turn", async () => {
116
+ const seen: ScriptedTurnInfo[] = [];
117
+ const model = new ScriptedModel(() => script, [], { onTurn: (info) => void seen.push(info) });
118
+ await model.invoke(transcriptWithRounds(0));
119
+ await model.invoke([...transcriptWithRounds(1), new AIMessage("a text-only turn"), new HumanMessage("more")]);
120
+ expect(seen.map((s) => s.priorToolCallIds)).toEqual([[], []]);
111
121
  });
112
122
 
113
123
  it("throws a diagnosing error when the script runs out", async () => {
@@ -1,19 +1,27 @@
1
1
  /**
2
- * `StreamingSideEffects`: the v3 `tools` events carry the tool INPUT on
3
- * `tool-started` and the OUTPUT on `tool-finished`, so the trigger correlates
4
- * the two by `tool_call_id` and publishes a file-modifying tool's target path
5
- * once the call has finished.
2
+ * `StreamingSideEffects`: a `tool_started` carries the tool INPUT and a
3
+ * `tool_finished` its completion, so the trigger correlates the two by
4
+ * `callId` and publishes a file-modifying tool's target path once the call
5
+ * has finished. Driven the way the loop drives it (since #1097): raw v3 events
6
+ * through the translator, the canonical events into the trigger.
6
7
  *
7
8
  * Carried from the legacy v3 loop's suite (`streaming-v3.test.ts`, retired
8
- * with the loop at S3 M2b) — the trigger itself never had a test of its own.
9
+ * with the loop in #1096) — the trigger itself never had a test of its own.
9
10
  */
10
11
 
11
12
  import { describe, it, expect, vi } from "vitest";
12
13
 
13
14
  import { StreamingSideEffects } from "../streaming-side-effects.js";
15
+ import { DeepAgentTranslator } from "../translator.js";
14
16
  import type { InlinePublisher } from "../inline-publisher.js";
17
+ import type { V3ProtocolEvent } from "../v3-event-recorder.js";
15
18
  import { makeToolFinished, makeToolStarted, resetSeq } from "../__test-utils__/v3-event-fixtures.js";
16
19
 
20
+ /** What the loop does per raw event: translate, then hand every canonical event to the trigger. */
21
+ function feed(effects: StreamingSideEffects, raw: V3ProtocolEvent): void {
22
+ for (const event of new DeepAgentTranslator(null).translate(raw)) effects.onEvent(event);
23
+ }
24
+
17
25
  function publisherDouble(): { publisher: InlinePublisher; publish: ReturnType<typeof vi.fn> } {
18
26
  const publish = vi.fn(async (_path: string) => undefined);
19
27
  // The trigger reads exactly one member of the publisher.
@@ -26,10 +34,10 @@ describe("StreamingSideEffects", () => {
26
34
  const { publisher, publish } = publisherDouble();
27
35
  const effects = new StreamingSideEffects({ inlinePublisher: publisher });
28
36
 
29
- effects.onProtocolEvent(makeToolStarted("toolu_1", "write_file", { file_path: "/ws/index.ts", content: "x" }));
37
+ feed(effects, makeToolStarted("toolu_1", "write_file", { file_path: "/ws/index.ts", content: "x" }));
30
38
  expect(publish, "not before the call finishes").not.toHaveBeenCalled();
31
39
 
32
- effects.onProtocolEvent(makeToolFinished("toolu_1", "written"));
40
+ feed(effects, makeToolFinished("toolu_1", "written"));
33
41
  expect(publish).toHaveBeenCalledWith("/ws/index.ts");
34
42
  expect(effects.pendingPublishPromises).toHaveLength(1);
35
43
  });
@@ -39,8 +47,8 @@ describe("StreamingSideEffects", () => {
39
47
  const { publisher, publish } = publisherDouble();
40
48
  const effects = new StreamingSideEffects({ inlinePublisher: publisher });
41
49
 
42
- effects.onProtocolEvent(makeToolStarted("toolu_2", "read_file", { path: "/ws/index.ts" }));
43
- effects.onProtocolEvent(makeToolFinished("toolu_2", "contents"));
50
+ feed(effects, makeToolStarted("toolu_2", "read_file", { path: "/ws/index.ts" }));
51
+ feed(effects, makeToolFinished("toolu_2", "contents"));
44
52
  expect(publish).not.toHaveBeenCalled();
45
53
  expect(effects.pendingPublishPromises).toHaveLength(0);
46
54
  });
@@ -50,10 +58,10 @@ describe("StreamingSideEffects", () => {
50
58
  const { publisher, publish } = publisherDouble();
51
59
  const effects = new StreamingSideEffects({ inlinePublisher: publisher });
52
60
 
53
- effects.onProtocolEvent(makeToolStarted("toolu_3", "edit", { filePath: "/ws/a.ts" }));
54
- effects.onProtocolEvent(makeToolFinished("toolu_3", "ok"));
55
- effects.onProtocolEvent(makeToolStarted("toolu_4", "write", JSON.stringify({ path: "/ws/b.ts" })));
56
- effects.onProtocolEvent(makeToolFinished("toolu_4", "ok"));
61
+ feed(effects, makeToolStarted("toolu_3", "edit", { filePath: "/ws/a.ts" }));
62
+ feed(effects, makeToolFinished("toolu_3", "ok"));
63
+ feed(effects, makeToolStarted("toolu_4", "write", JSON.stringify({ path: "/ws/b.ts" })));
64
+ feed(effects, makeToolFinished("toolu_4", "ok"));
57
65
  expect(publish.mock.calls.map((c) => c[0])).toEqual(["/ws/a.ts", "/ws/b.ts"]);
58
66
  });
59
67
 
@@ -62,17 +70,17 @@ describe("StreamingSideEffects", () => {
62
70
  const { publisher, publish } = publisherDouble();
63
71
  const effects = new StreamingSideEffects({ inlinePublisher: publisher });
64
72
 
65
- effects.onProtocolEvent(makeToolFinished("toolu_never_started", "ok"));
66
- effects.onProtocolEvent(makeToolStarted("toolu_5", "write_file", { content: "no path" }));
67
- effects.onProtocolEvent(makeToolFinished("toolu_5", "ok"));
73
+ feed(effects, makeToolFinished("toolu_never_started", "ok"));
74
+ feed(effects, makeToolStarted("toolu_5", "write_file", { content: "no path" }));
75
+ feed(effects, makeToolFinished("toolu_5", "ok"));
68
76
  expect(publish).not.toHaveBeenCalled();
69
77
  });
70
78
 
71
79
  it("does nothing at all without a publisher", () => {
72
80
  resetSeq();
73
81
  const effects = new StreamingSideEffects({});
74
- effects.onProtocolEvent(makeToolStarted("toolu_6", "write_file", { path: "/ws/x" }));
75
- effects.onProtocolEvent(makeToolFinished("toolu_6", "ok"));
82
+ feed(effects, makeToolStarted("toolu_6", "write_file", { path: "/ws/x" }));
83
+ feed(effects, makeToolFinished("toolu_6", "ok"));
76
84
  expect(effects.pendingPublishPromises).toHaveLength(0);
77
85
  });
78
86
  });
@@ -46,7 +46,7 @@ describe("buildSubAgentMiddleware", () => {
46
46
 
47
47
  const subView = stack[4];
48
48
  expect(subView.afterModel).toBeDefined();
49
- expect(subView.wrapToolCall, "the advisory never blocks a tool; the runtime enforces the cap (Q-S3-3)").toBeUndefined();
49
+ expect(subView.wrapToolCall, "the advisory never blocks a tool; the runtime enforces the cap").toBeUndefined();
50
50
  expect(subView.beforeAgent).toBeUndefined();
51
51
  });
52
52