@sema-agent/core 7.51.2 → 7.52.0

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 (363) hide show
  1. package/CHANGELOG.md +504 -2
  2. package/dist/agents/agent-transcript-tool.d.ts +1 -1
  3. package/dist/agents/cascade.js +4 -0
  4. package/dist/agents/cumulative-stats.d.ts +3 -0
  5. package/dist/agents/cumulative-stats.js +3 -0
  6. package/dist/agents/list-agents-tool.d.ts +1 -1
  7. package/dist/agents/read-inbox-tool.d.ts +1 -1
  8. package/dist/agents/repair-loop.js +4 -0
  9. package/dist/agents/send-message-tool.d.ts +11 -16
  10. package/dist/agents/send-message-tool.js +11 -13
  11. package/dist/agents/subagent.js +6 -4
  12. package/dist/agents/tool-filter.d.ts +40 -13
  13. package/dist/agents/tool-filter.js +28 -14
  14. package/dist/bench/metrics.d.ts +1 -0
  15. package/dist/brain/anthropic.js +16 -12
  16. package/dist/brain/model-presets.d.ts +4 -5
  17. package/dist/brain/model-presets.js +4 -4
  18. package/dist/brain/open-responses.js +16 -12
  19. package/dist/brain/openai.js +16 -12
  20. package/dist/brain/request-params.d.ts +12 -33
  21. package/dist/brain/request-params.js +5 -2
  22. package/dist/brain/request-route.d.ts +9 -8
  23. package/dist/brain/request-route.js +1 -0
  24. package/dist/brain/route-adjudicator.d.ts +117 -47
  25. package/dist/brain/route-adjudicator.js +171 -42
  26. package/dist/brain/route-conformance.js +2 -2
  27. package/dist/brain/status-sink.d.ts +18 -0
  28. package/dist/brain/status-sink.js +7 -0
  29. package/dist/core/allow-entry.d.ts +40 -8
  30. package/dist/core/allow-entry.js +23 -16
  31. package/dist/core/auto-compaction.d.ts +23 -20
  32. package/dist/core/auto-compaction.js +37 -16
  33. package/dist/core/auto-promote.d.ts +2 -1
  34. package/dist/core/auto-promote.js +2 -2
  35. package/dist/core/caller-tool-name.d.ts +9 -0
  36. package/dist/core/caller-tool-name.js +13 -0
  37. package/dist/core/checkpoint-requirements.d.ts +7 -1
  38. package/dist/core/checkpoint-requirements.js +2 -0
  39. package/dist/core/checkpoint-store.d.ts +36 -12
  40. package/dist/core/checkpoint-store.js +1 -1
  41. package/dist/core/child-clamp-seats.d.ts +6 -0
  42. package/dist/core/child-clamp-seats.js +2 -1
  43. package/dist/core/credential-vocabulary.d.ts +33 -8
  44. package/dist/core/credential-vocabulary.js +32 -7
  45. package/dist/core/decision-receipt.d.ts +2 -2
  46. package/dist/core/delegation-frames.d.ts +9 -2
  47. package/dist/core/delegation-name.d.ts +18 -0
  48. package/dist/core/delegation-name.js +47 -0
  49. package/dist/core/engine-capabilities.d.ts +8 -1
  50. package/dist/core/engine-capabilities.js +1 -1
  51. package/dist/core/engine-notice.d.ts +36 -19
  52. package/dist/core/frontmatter-fence.d.ts +10 -0
  53. package/dist/core/frontmatter-fence.js +6 -0
  54. package/dist/core/gate-fold.js +5 -23
  55. package/dist/core/gate-lanes.js +356 -270
  56. package/dist/core/governance-codes.d.ts +9 -4
  57. package/dist/core/governance-codes.js +9 -3
  58. package/dist/core/hooks.d.ts +276 -734
  59. package/dist/core/hooks.js +97 -192
  60. package/dist/{tools/fs → core}/image-admission.d.ts +21 -3
  61. package/dist/{tools/fs → core}/image-admission.js +24 -6
  62. package/dist/core/mcp-connection-pool.d.ts +4 -1
  63. package/dist/core/mcp-connection-pool.js +7 -2
  64. package/dist/core/mcp-probe.d.ts +12 -9
  65. package/dist/core/mcp-probe.js +2 -2
  66. package/dist/core/mcp-server-spec.d.ts +16 -0
  67. package/dist/core/mcp.d.ts +11 -7
  68. package/dist/core/mcp.js +11 -5
  69. package/dist/core/memory-engine/data-plane.js +5 -1
  70. package/dist/core/memory-engine/distiller.js +16 -2
  71. package/dist/core/memory-engine/engine.d.ts +8 -11
  72. package/dist/core/memory-engine/engine.js +9 -5
  73. package/dist/core/memory-engine/frontmatter.d.ts +6 -0
  74. package/dist/core/memory-engine/frontmatter.js +19 -16
  75. package/dist/core/memory.d.ts +2 -2
  76. package/dist/core/mode-policy.d.ts +4 -0
  77. package/dist/core/mode-policy.js +7 -5
  78. package/dist/core/model-seat.d.ts +4 -1
  79. package/dist/core/mods/dollar.d.ts +109 -0
  80. package/dist/core/mods/dollar.js +154 -0
  81. package/dist/core/mods/host.d.ts +23 -0
  82. package/dist/core/mods/host.js +21 -0
  83. package/dist/core/mods/kernel/budget.d.ts +43 -0
  84. package/dist/core/mods/kernel/budget.js +83 -0
  85. package/dist/core/mods/kernel/dispatch.d.ts +100 -0
  86. package/dist/core/mods/kernel/dispatch.js +701 -0
  87. package/dist/core/mods/kernel/events.d.ts +242 -0
  88. package/dist/core/mods/kernel/events.js +210 -0
  89. package/dist/core/mods/kernel/index.d.ts +6 -0
  90. package/dist/core/mods/kernel/index.js +5 -0
  91. package/dist/core/mods/kernel/receive.d.ts +65 -0
  92. package/dist/core/mods/kernel/receive.js +123 -0
  93. package/dist/core/mods/kernel/registration.d.ts +131 -0
  94. package/dist/core/mods/kernel/registration.js +102 -0
  95. package/dist/core/mods/kernel/site-rules.d.ts +84 -0
  96. package/dist/core/mods/kernel/site-rules.js +104 -0
  97. package/dist/core/mods/stations.d.ts +350 -0
  98. package/dist/core/mods/stations.js +444 -0
  99. package/dist/core/own-property-receipt.js +11 -23
  100. package/dist/core/parent-spec-seat.d.ts +18 -7
  101. package/dist/core/parent-spec-seat.js +6 -2
  102. package/dist/core/path-identity.js +2 -1
  103. package/dist/core/permission-rule-syntax.d.ts +15 -0
  104. package/dist/core/permission-rule-syntax.js +24 -16
  105. package/dist/core/permission-rules.d.ts +7 -1
  106. package/dist/core/permission-rules.js +26 -15
  107. package/dist/core/prompt-section-seat.d.ts +15 -27
  108. package/dist/core/prompt-section-seat.js +73 -40
  109. package/dist/core/protocol-http-auth.d.ts +3 -1
  110. package/dist/core/protocol-http-auth.js +2 -0
  111. package/dist/core/reminder-mint.d.ts +2 -2
  112. package/dist/core/remote-env.d.ts +24 -12
  113. package/dist/core/remote-env.js +1 -0
  114. package/dist/core/resume-startup-cause.d.ts +16 -1
  115. package/dist/core/resume-startup-cause.js +4 -1
  116. package/dist/core/retired-keys.d.ts +4 -0
  117. package/dist/core/retired-keys.js +3 -0
  118. package/dist/core/runner/announce-once-ledger.d.ts +31 -1
  119. package/dist/core/runner/announce-once-ledger.js +22 -0
  120. package/dist/core/runner/assemble-result.d.ts +9 -0
  121. package/dist/core/runner/assemble-result.js +3 -1
  122. package/dist/core/runner/call-hook-stations.d.ts +23 -27
  123. package/dist/core/runner/call-hook-stations.js +58 -42
  124. package/dist/core/runner/caller-stop-gate.d.ts +25 -0
  125. package/dist/core/runner/caller-stop-gate.js +7 -0
  126. package/dist/core/runner/compaction-seams.d.ts +8 -22
  127. package/dist/core/runner/compaction-seams.js +28 -53
  128. package/dist/core/runner/construction-doors.js +11 -1
  129. package/dist/core/runner/contracts.d.ts +85 -83
  130. package/dist/core/runner/credential-origin-seat.d.ts +2 -0
  131. package/dist/core/runner/credential-origin-seat.js +19 -0
  132. package/dist/core/runner/extra-body-dropped-seat.d.ts +2 -6
  133. package/dist/core/runner/gate-exit.d.ts +47 -36
  134. package/dist/core/runner/gate-exit.js +8 -2
  135. package/dist/core/runner/image.js +1 -2
  136. package/dist/core/runner/inline-image.js +1 -1
  137. package/dist/core/runner/notice-seat-input.d.ts +11 -0
  138. package/dist/core/runner/notice-seat-input.js +1 -0
  139. package/dist/core/runner/person-path-rows.js +1 -0
  140. package/dist/core/runner/prepare-acquire-reconcile.js +5 -1
  141. package/dist/core/runner/prepare-ask-lane.d.ts +5 -7
  142. package/dist/core/runner/prepare-ask-lane.js +6 -15
  143. package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -2
  144. package/dist/core/runner/prepare-caps-and-workflow.js +25 -8
  145. package/dist/core/runner/prepare-config-doors.d.ts +5 -0
  146. package/dist/core/runner/prepare-config-doors.js +9 -0
  147. package/dist/core/runner/prepare-defer-classify.js +3 -4
  148. package/dist/core/runner/prepare-gate-stations.d.ts +8 -11
  149. package/dist/core/runner/prepare-gate-stations.js +11 -10
  150. package/dist/core/runner/prepare-inherited-gate.d.ts +8 -12
  151. package/dist/core/runner/prepare-inherited-gate.js +8 -21
  152. package/dist/core/runner/prepare-memory-engine-session.js +1 -1
  153. package/dist/core/runner/prepare-park-ask.js +10 -14
  154. package/dist/core/runner/prepare-policy-chain.d.ts +17 -15
  155. package/dist/core/runner/prepare-policy-chain.js +95 -100
  156. package/dist/core/runner/prepare-project-context.js +7 -10
  157. package/dist/core/runner/prepare-prompt-assembly.d.ts +45 -40
  158. package/dist/core/runner/prepare-prompt-assembly.js +134 -101
  159. package/dist/core/runner/prepare-prompt-inputs.d.ts +18 -19
  160. package/dist/core/runner/prepare-prompt-inputs.js +5 -7
  161. package/dist/core/runner/prepare-protocol-tools.d.ts +6 -4
  162. package/dist/core/runner/prepare-protocol-tools.js +2 -2
  163. package/dist/core/runner/prepare-safety-scan.js +6 -10
  164. package/dist/core/runner/prepare-suspend-saga.d.ts +6 -0
  165. package/dist/core/runner/prepare-suspend-saga.js +7 -5
  166. package/dist/core/runner/prepare-task.js +33 -15
  167. package/dist/core/runner/prepare-turn-wiring.d.ts +13 -15
  168. package/dist/core/runner/prepare-turn-wiring.js +29 -27
  169. package/dist/core/runner/prepare-wiring-manifest.d.ts +5 -6
  170. package/dist/core/runner/prepare-wiring-manifest.js +7 -7
  171. package/dist/core/runner/resume-apply.d.ts +5 -2
  172. package/dist/core/runner/resume-apply.js +24 -42
  173. package/dist/core/runner/resume-checkpoint-screen.d.ts +1 -0
  174. package/dist/core/runner/resume-checkpoint-screen.js +9 -1
  175. package/dist/core/runner/resume-preflight.js +38 -16
  176. package/dist/core/runner/retired-runner-deps.js +3 -1
  177. package/dist/core/runner/run-brain-sinks.d.ts +3 -2
  178. package/dist/core/runner/run-brain-sinks.js +5 -1
  179. package/dist/core/runner/run-compaction-machinery.d.ts +7 -1
  180. package/dist/core/runner/run-compaction-machinery.js +7 -33
  181. package/dist/core/runner/run-harness-handlers.js +4 -2
  182. package/dist/core/runner/run-identity-wiring.d.ts +3 -1
  183. package/dist/core/runner/run-identity-wiring.js +3 -2
  184. package/dist/core/runner/run-leg.js +62 -84
  185. package/dist/core/runner/run-notification-lane.js +1 -0
  186. package/dist/core/runner/run-recovery-lanes.d.ts +3 -0
  187. package/dist/core/runner/run-recovery-lanes.js +11 -10
  188. package/dist/core/runner/run-settle-and-teardown.js +9 -28
  189. package/dist/core/runner/run-stop-and-final-verify.js +18 -25
  190. package/dist/core/runner/run-terminal-adoption.d.ts +3 -0
  191. package/dist/core/runner/run-terminal-adoption.js +33 -22
  192. package/dist/core/runner/run-tool-mount-facts.js +5 -3
  193. package/dist/core/runner/run-turn-boundary.js +23 -34
  194. package/dist/core/runner/runtask.d.ts +6 -7
  195. package/dist/core/runner/runtask.js +14 -72
  196. package/dist/core/runner/session-rule-policy.d.ts +5 -5
  197. package/dist/core/runner/session-rule-policy.js +13 -8
  198. package/dist/core/runner/side-call-account.d.ts +68 -0
  199. package/dist/core/runner/side-call-account.js +61 -0
  200. package/dist/core/runner/stream-halt-verbs.js +12 -17
  201. package/dist/core/runner/stream-lifecycle-verbs.js +8 -5
  202. package/dist/core/runner/stream-steer-verb.d.ts +1 -1
  203. package/dist/core/runner/stream-steer-verb.js +20 -38
  204. package/dist/core/runner/sub-agent-deny-lists.d.ts +121 -22
  205. package/dist/core/runner/sub-agent-deny-lists.js +228 -71
  206. package/dist/core/runner/tool-end-body.d.ts +5 -6
  207. package/dist/core/runner/tool-end-body.js +6 -4
  208. package/dist/core/runner/tool-not-executed.d.ts +15 -0
  209. package/dist/core/runner/tool-not-executed.js +30 -0
  210. package/dist/core/runner/tool-occurrence.d.ts +8 -7
  211. package/dist/core/runner/tool-occurrence.js +5 -5
  212. package/dist/core/runner/tool-result-media-seat.d.ts +1 -1
  213. package/dist/core/runner-deps.d.ts +20 -28
  214. package/dist/core/safety-merge-corpus.js +18 -2
  215. package/dist/core/secret-env.d.ts +88 -20
  216. package/dist/core/secret-env.js +192 -38
  217. package/dist/core/session-policy-store.d.ts +52 -16
  218. package/dist/core/session-policy-store.js +118 -28
  219. package/dist/core/session-reconcile.d.ts +4 -0
  220. package/dist/core/session-reconcile.js +2 -1
  221. package/dist/core/shell-read-silence.js +3 -32
  222. package/dist/core/side-query.d.ts +5 -3
  223. package/dist/core/skill-grant.d.ts +3 -2
  224. package/dist/core/skill-grant.js +17 -9
  225. package/dist/core/skills-directory.d.ts +31 -11
  226. package/dist/core/skills-directory.js +655 -104
  227. package/dist/core/task-event.d.ts +13 -3
  228. package/dist/core/task-result.d.ts +8 -0
  229. package/dist/core/task-spec.d.ts +20 -19
  230. package/dist/core/task-stream.d.ts +14 -4
  231. package/dist/core/tighten-task-spec.d.ts +4 -3
  232. package/dist/core/tighten-task-spec.js +2 -4
  233. package/dist/core/tool-check-reading.d.ts +74 -0
  234. package/dist/core/tool-check-reading.js +80 -0
  235. package/dist/core/tool-policy.d.ts +59 -18
  236. package/dist/core/tool-policy.js +77 -12
  237. package/dist/core/tool-registry.d.ts +20 -0
  238. package/dist/core/tool-registry.js +4 -0
  239. package/dist/core/tool-spec.d.ts +10 -6
  240. package/dist/core/tools.js +2 -0
  241. package/dist/core/trace.d.ts +51 -32
  242. package/dist/core/unc-spelling.d.ts +10 -0
  243. package/dist/core/unc-spelling.js +3 -0
  244. package/dist/core/untrusted-egress.d.ts +8 -0
  245. package/dist/core/untrusted-egress.js +4 -1
  246. package/dist/core/user-attachment.d.ts +12 -2
  247. package/dist/core/user-attachment.js +17 -2
  248. package/dist/core/wiring-manifest.d.ts +14 -13
  249. package/dist/core/wiring-manifest.js +2 -2
  250. package/dist/engine/compaction/utils.js +1 -2
  251. package/dist/engine/execution-env/node-execution-env.d.ts +4 -3
  252. package/dist/engine/execution-env/symlink-chain.js +1 -1
  253. package/dist/engine/harness/agent-harness.d.ts +1 -1
  254. package/dist/engine/harness/agent-harness.js +3 -3
  255. package/dist/engine/harness/types.d.ts +17 -16
  256. package/dist/engine/harness/types.js +7 -1
  257. package/dist/engine/llm/types.d.ts +12 -7
  258. package/dist/engine/loop/agent-loop.js +1 -1
  259. package/dist/engine/loop/types.d.ts +1 -1
  260. package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
  261. package/dist/engine/session/import-validate.js +3 -10
  262. package/dist/engine/session/session.d.ts +4 -4
  263. package/dist/engine/session/session.js +4 -4
  264. package/dist/index.d.ts +20 -16
  265. package/dist/index.js +13 -11
  266. package/dist/internal/harness.d.ts +1 -1
  267. package/dist/internal/harness.js +1 -1
  268. package/dist/orchestration/run-spec.d.ts +4 -6
  269. package/dist/orchestration/run-spec.js +39 -63
  270. package/dist/orchestration/run-workflow-tool.js +1 -2
  271. package/dist/orchestration/workflow.d.ts +11 -3
  272. package/dist/orchestration/workflow.js +11 -2
  273. package/dist/prompt-assembly/artifact-store.d.ts +37 -56
  274. package/dist/prompt-assembly/artifact-store.js +31 -49
  275. package/dist/prompt-assembly/artifact.d.ts +89 -76
  276. package/dist/prompt-assembly/artifact.js +167 -146
  277. package/dist/prompt-assembly/assemble.d.ts +34 -29
  278. package/dist/prompt-assembly/assemble.js +33 -220
  279. package/dist/prompt-assembly/bands.d.ts +20 -0
  280. package/dist/prompt-assembly/bands.js +18 -0
  281. package/dist/prompt-assembly/catalog/constitution.d.ts +23 -0
  282. package/dist/prompt-assembly/catalog/constitution.js +69 -0
  283. package/dist/prompt-assembly/catalog/core-behavior.d.ts +9 -0
  284. package/dist/prompt-assembly/catalog/core-behavior.js +85 -0
  285. package/dist/prompt-assembly/catalog/index.d.ts +11 -0
  286. package/dist/prompt-assembly/catalog/index.js +59 -0
  287. package/dist/prompt-assembly/catalog/modes.d.ts +15 -0
  288. package/dist/prompt-assembly/catalog/modes.js +137 -0
  289. package/dist/prompt-assembly/catalog/role.d.ts +10 -0
  290. package/dist/prompt-assembly/catalog/role.js +157 -0
  291. package/dist/prompt-assembly/catalog/schema.d.ts +124 -0
  292. package/dist/prompt-assembly/catalog/schema.js +25 -0
  293. package/dist/prompt-assembly/catalog/sections.d.ts +9 -0
  294. package/dist/prompt-assembly/catalog/sections.js +98 -0
  295. package/dist/prompt-assembly/catalog/team.d.ts +4 -0
  296. package/dist/prompt-assembly/catalog/team.js +258 -0
  297. package/dist/prompt-assembly/composer.d.ts +24 -28
  298. package/dist/prompt-assembly/composer.js +124 -46
  299. package/dist/prompt-assembly/epoch.d.ts +89 -79
  300. package/dist/prompt-assembly/epoch.js +115 -142
  301. package/dist/prompt-assembly/explain.d.ts +58 -34
  302. package/dist/prompt-assembly/explain.js +21 -24
  303. package/dist/prompt-assembly/overlay.d.ts +127 -0
  304. package/dist/prompt-assembly/overlay.js +301 -0
  305. package/dist/prompt-assembly/renderers.d.ts +21 -0
  306. package/dist/prompt-assembly/renderers.js +39 -0
  307. package/dist/prompt-assembly/section-usage.d.ts +3 -3
  308. package/dist/prompt-assembly/section-usage.js +1 -1
  309. package/dist/prompt-assembly/select.d.ts +56 -0
  310. package/dist/prompt-assembly/select.js +69 -0
  311. package/dist/prompt-assembly/sugar.d.ts +31 -0
  312. package/dist/prompt-assembly/sugar.js +20 -0
  313. package/dist/prompt-assembly/turn-snapshot.d.ts +3 -2
  314. package/dist/prompt-assembly/types.d.ts +45 -148
  315. package/dist/prompts/coordinator.d.ts +2 -21
  316. package/dist/prompts/coordinator.js +3 -255
  317. package/dist/prompts/cowork.d.ts +27 -16
  318. package/dist/prompts/cowork.js +2 -23
  319. package/dist/prompts/default.d.ts +38 -500
  320. package/dist/prompts/default.js +20 -285
  321. package/dist/prompts/supervisor.d.ts +6 -71
  322. package/dist/prompts/supervisor.js +6 -117
  323. package/dist/tools/fs/bash-readonly-classifier.d.ts +6 -5
  324. package/dist/tools/fs/dir-entries.d.ts +4 -2
  325. package/dist/tools/fs/dir-entries.js +16 -4
  326. package/dist/tools/fs/fs-bash.d.ts +1 -1
  327. package/dist/tools/fs/fs-bash.js +22 -11
  328. package/dist/tools/fs/fs-pdf.js +17 -13
  329. package/dist/tools/fs/fs-read.js +4 -3
  330. package/dist/tools/fs/fs-shared.d.ts +1 -10
  331. package/dist/tools/fs/fs-shared.js +3 -4
  332. package/dist/tools/fs/fs-write.js +2 -1
  333. package/dist/tools/fs/notebook.js +1 -1
  334. package/dist/tools/fs/pdf.d.ts +20 -10
  335. package/dist/tools/fs/pdf.js +19 -10
  336. package/dist/tools/fs/program-read-model.d.ts +68 -8
  337. package/dist/tools/fs/program-read-model.js +112 -33
  338. package/dist/tools/fs/program-read-model.rows.js +30 -10
  339. package/dist/tools/fs/read-deny-home.d.ts +25 -9
  340. package/dist/tools/fs/read-deny-home.js +28 -27
  341. package/dist/tools/fs/read-deny.d.ts +41 -11
  342. package/dist/tools/fs/read-deny.js +51 -5
  343. package/dist/tools/fs/safety.d.ts +4 -26
  344. package/dist/tools/fs/safety.js +10 -32
  345. package/dist/tools/fs/search.js +15 -10
  346. package/dist/tools/fs/shell-read-argv.d.ts +3 -2
  347. package/dist/tools/fs/shell-read-argv.js +118 -38
  348. package/dist/tools/fs/shell-read-establish.d.ts +5 -5
  349. package/dist/tools/fs/shell-read-establish.js +11 -61
  350. package/dist/tools/fs/shell-read-identity.js +6 -3
  351. package/dist/tools/fs/shell-read-judge.d.ts +13 -15
  352. package/dist/tools/fs/shell-read-judge.js +18 -4
  353. package/dist/tools/fs/shell-read-plan.d.ts +2 -2
  354. package/dist/tools/web.js +1 -1
  355. package/package.json +13 -1
  356. package/test/export-surface.snapshot.json +242 -99
  357. package/wire-changes/core@7.52.0.json +5859 -0
  358. package/dist/core/hook-seats.d.ts +0 -66
  359. package/dist/core/hook-seats.js +0 -37
  360. package/dist/prompt-assembly/packs/sema-default.d.ts +0 -2
  361. package/dist/prompt-assembly/packs/sema-default.js +0 -147
  362. package/dist/prompts/simple-sections.d.ts +0 -58
  363. package/dist/prompts/simple-sections.js +0 -43
@@ -4,7 +4,8 @@ import { ASK_USER_QUESTION_TOOL_NAME } from "../ask-question.js";
4
4
  import { CheckpointError, readPendingSteerQueue, realApprovalOrgFact, remainingBudgetMicroUsd } from "../checkpoint-store.js";
5
5
  import { normalizePersistedRuleHit } from "../rule-lane-reads.js";
6
6
  import { decidersNote, SETTLEMENT_NOBODY_JUDGED } from "../gate-outcome.js";
7
- import { formatHookFeedback, hookSeatExpiredError, runHookSeat } from "../hooks.js";
7
+ import { formatHookFeedback } from "../hooks.js";
8
+ import { classicEventBase, failedHandlerClause, screenUserPrompt } from "../mods/stations.js";
8
9
  import { buildAppliedHumanInputEvent, buildHumanInputEvent, projectHumanInput } from "../human-input-projection.js";
9
10
  import { humanInputAttachmentsOf, readObjectiveAttachments, userAttachmentDeclarations } from "../user-attachment.js";
10
11
  import { uuidv7 } from "../../internal/harness.js";
@@ -22,6 +23,7 @@ import { deliverEngineNotice } from "../types.js";
22
23
  import { delimitUntrusted, inlineUntrusted, REVIEWER_NOTE_MAX_BODY, sanitizeUntrustedText } from "../untrusted-text.js";
23
24
  import { errorCodeOf } from "./terminal-account.js";
24
25
  import { DEFAULT_PRECALL_OUTPUT_TOKENS, platformLimitTerminal } from "./clock-and-limits.js";
26
+ import { legContextOverlayOption } from "./compaction-call-options.js";
25
27
  import { mintOutputStyleReminder, owedPostureText } from "./compaction-restate.js";
26
28
  import { deepJsonEqual, resumeContinuation } from "./decide-continuation.js";
27
29
  import { chainCannotJudge } from "./call-hook-stations.js";
@@ -37,10 +39,11 @@ import { maybeHumanRejectionHalt } from "./prepare-gate-stations.js";
37
39
  import { nextHumanInputSeq } from "./steer-admission.js";
38
40
  import { settleTeardownLeg } from "./teardown-bounded.js";
39
41
  import { announceToolCall, emitSettled, toolResultMsg } from "./tool-end-body.js";
42
+ import { rowDetailsOf, withRowNotExecuted } from "./tool-not-executed.js";
40
43
  import { announceListingTruncation } from "../skill-listing-budget.js";
41
44
  import { attachmentEnvelopeTags, collectDateChange, commitAgentListing, commitSkillsListing, reduceToolEnd, renderAgentListingFrame, renderOrphanedBackgroundTasks, renderSkillsListingFrame, stampWriteAnchor } from "./turn-attachments.js";
42
45
  import { flushOwedAnnouncedSnapshot } from "./announce-once-ledger.js";
43
- import { asThrownError, thrownMarksOf } from "../thrown-value.js";
46
+ import { thrownMarksOf } from "../thrown-value.js";
44
47
  import { egressThrownText, egressValue } from "../untrusted-egress.js";
45
48
  import { ruleSourcePhrase } from "../rule-denial-sentence.js";
46
49
  import { wireOf } from "../tool-name-readings.js";
@@ -167,32 +170,21 @@ export async function runLeg(input) {
167
170
  engineSegments.push({ start: hookStart, end: continuation.length });
168
171
  }
169
172
  if (source === "steer") {
170
- const parkedScreen = (spec.hooks ?? runner.deps.hooks)?.userPromptSubmit;
171
- if (parkedScreen !== undefined) {
172
- let outcome;
173
- try {
174
- const seat = await runHookSeat("userPromptSubmit", { timeoutMs: prepared.hookTimeoutMs, signal: prepared.abortController.signal, abortEnds: true }, (sig) => parkedScreen(steer.text, {
175
- identity: prepared.hookIdentity, permissionMode: prepared.permissionMode.observed,
176
- signal: sig,
177
- source: "parked_redelivery",
178
- ...(steer.inputId !== undefined ? { inputId: steer.inputId } : {}),
179
- ...(steer.actor !== undefined ? { actor: snapshotActorAssertion(steer.actor) } : {}),
180
- }));
181
- outcome = seat.expired
182
- ? { blocked: seat.cause === "timeout" ? `the screen did not answer within its ${prepared.hookTimeoutMs}ms bound (fail-closed)` : "the run was cancelled while the screen was still deciding (fail-closed)" }
183
- : seat.value?.block !== undefined && seat.value.block !== ""
184
- ? { blocked: inlineUntrusted(seat.value.block) }
185
- : { ...(seat.value?.additionalContext !== undefined && seat.value.additionalContext !== "" ? { context: seat.value.additionalContext } : {}) };
186
- }
187
- catch (hookErr) {
188
- const err = asThrownError(hookErr);
189
- try {
190
- runner.deps.onError?.(err, { phase: "hook", sessionId: prepared.sessionId });
191
- }
192
- catch {
193
- }
194
- outcome = { blocked: `the screen crashed (${inlineUntrusted(err.message)}; fail-closed)` };
195
- }
173
+ const screen = await screenUserPrompt(prepared.modBus, {
174
+ ...classicEventBase(prepared.hookIdentity, prepared.permissionMode.observed),
175
+ prompt: steer.text,
176
+ source: "parked_redelivery",
177
+ ...(steer.inputId !== undefined ? { inputId: steer.inputId } : {}),
178
+ ...(steer.actor !== undefined ? { actor: snapshotActorAssertion(steer.actor) } : {}),
179
+ }, prepared.abortController.signal);
180
+ if (screen !== undefined) {
181
+ const outcome = screen.kind === "aborted"
182
+ ? { blocked: "the run was cancelled while the screen was still deciding (fail-closed)" }
183
+ : screen.kind === "failed"
184
+ ? { blocked: `the screen ${failedHandlerClause(screen)} (fail-closed)` }
185
+ : screen.block !== undefined && screen.block !== ""
186
+ ? { blocked: inlineUntrusted(screen.block) }
187
+ : { ...(screen.additionalContext !== undefined && screen.additionalContext !== "" ? { context: screen.additionalContext } : {}) };
196
188
  if ("blocked" in outcome) {
197
189
  if (steer.inputId !== undefined)
198
190
  withheldSteerIds.add(steer.inputId);
@@ -290,49 +282,31 @@ export async function runLeg(input) {
290
282
  const projectedObjective = projectHumanInput({ text: spec.objective, actor: objectiveActor, source: "objective" });
291
283
  let effectiveObjective = projectedObjective;
292
284
  let promptBlocked = false;
293
- const userPromptSubmit = (spec.hooks ?? runner.deps.hooks)?.userPromptSubmit;
294
- if (userPromptSubmit) {
295
- try {
296
- const promptSeat = await runHookSeat("userPromptSubmit", { timeoutMs: prepared.hookTimeoutMs, signal: prepared.abortController.signal, abortEnds: true }, (sig) => userPromptSubmit(spec.objective, { identity: prepared.hookIdentity, permissionMode: prepared.permissionMode.observed, signal: sig, source: "objective", ...(objectiveActor !== undefined ? { actor: snapshotActorAssertion(objectiveActor) } : {}), ...(prepared.userAttachments !== undefined ? { userAttachments: userAttachmentDeclarations(prepared.userAttachments) } : {}) }));
297
- if (promptSeat.expired) {
298
- if (promptSeat.cause === "timeout") {
299
- try {
300
- runner.deps.onError?.(hookSeatExpiredError("userPromptSubmit", prepared.hookTimeoutMs, promptSeat.cause, "the prompt was NOT submitted (fail-closed) and the task ends blocked"), { phase: "hook", sessionId: prepared.sessionId });
301
- }
302
- catch {
303
- }
304
- }
305
- const timedOut = promptSeat.cause === "timeout";
306
- holdPrompt(prepared.blockedRef, prepared.reminderMark, timedOut ? "timeout" : "cancelled", timedOut
307
- ? `the deployment's userPromptSubmit hook did not answer within its ${prepared.hookTimeoutMs}ms bound while screening this prompt; ` +
308
- `the prompt was NOT submitted (fail-closed)`
309
- : `the task was cancelled while the deployment's userPromptSubmit hook was still screening this prompt; ` +
310
- `the prompt was NOT submitted (fail-closed)`);
311
- promptBlocked = true;
312
- }
313
- const decision = promptSeat.expired ? undefined : promptSeat.value;
314
- const blockWords = decision?.block;
315
- if (blockWords) {
316
- holdPrompt(prepared.blockedRef, prepared.reminderMark, "block", blockWords);
317
- promptBlocked = true;
318
- }
319
- else if (decision?.additionalContext) {
320
- effectiveObjective = `${formatHookFeedback(decision.additionalContext, prepared.reminderMark)}\n\n${projectedObjective}`;
321
- }
322
- }
323
- catch (hookErr) {
324
- const err = asThrownError(hookErr);
325
- try {
326
- runner.deps.onError?.(err, { phase: "hook", sessionId: prepared.sessionId });
327
- }
328
- catch {
329
- }
330
- holdPrompt(prepared.blockedRef, prepared.reminderMark, "crashed", `the deployment's userPromptSubmit hook crashed while screening this prompt (${err.message}); ` + `the prompt was NOT submitted (fail-closed)`);
331
- promptBlocked = true;
332
- }
285
+ const screen = await screenUserPrompt(prepared.modBus, {
286
+ ...classicEventBase(prepared.hookIdentity, prepared.permissionMode.observed),
287
+ prompt: spec.objective,
288
+ source: "objective",
289
+ ...(objectiveActor !== undefined ? { actor: snapshotActorAssertion(objectiveActor) } : {}),
290
+ ...(prepared.userAttachments !== undefined ? { userAttachments: userAttachmentDeclarations(prepared.userAttachments) } : {}),
291
+ }, prepared.abortController.signal);
292
+ if (screen?.kind === "aborted") {
293
+ holdPrompt(prepared.blockedRef, prepared.reminderMark, "cancelled", `the task was cancelled while the deployment's userPromptSubmit hook was still screening this prompt; ` +
294
+ `the prompt was NOT submitted (fail-closed)`);
295
+ promptBlocked = true;
296
+ }
297
+ else if (screen?.kind === "failed") {
298
+ holdPrompt(prepared.blockedRef, prepared.reminderMark, screen.cause === "timeout" ? "timeout" : "crashed", `the deployment's userPromptSubmit hook ${failedHandlerClause(screen)} while screening this prompt; the prompt was NOT submitted (fail-closed)`);
299
+ promptBlocked = true;
300
+ }
301
+ else if (screen?.block) {
302
+ holdPrompt(prepared.blockedRef, prepared.reminderMark, "block", screen.block);
303
+ promptBlocked = true;
304
+ }
305
+ else if (screen?.additionalContext) {
306
+ effectiveObjective = `${formatHookFeedback(screen.additionalContext, prepared.reminderMark)}\n\n${projectedObjective}`;
333
307
  }
334
308
  const objectiveInputId = uuidv7();
335
- const { frames: attachmentFrames, chars: attachmentChars } = await readObjectiveAttachments(prepared, objectiveInputId, promptBlocked);
309
+ const { frames: attachmentFrames, chars: attachmentChars } = await readObjectiveAttachments(prepared, objectiveInputId, promptBlocked, { overlay: () => legContextOverlayOption(prepared, runner).contextOverlay, objectiveChars: effectiveObjective.length });
336
310
  let gitLegDelivered;
337
311
  if (!promptBlocked) {
338
312
  const gitBody = await resolveGitLegDelivery(prepared, undefined, (err) => {
@@ -587,10 +561,14 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
587
561
  const callStart = { toolCallId: pendingAction.toolCallId, spelledName, wireName: pendingAction.toolName, ...pendingLabel, args: resolvedArgs };
588
562
  announceToolCall(occurrences, callStart, { push: emit });
589
563
  occurrences.gateRound(pendingAction.toolCallId, decidedGate, frozenInputSnapshot(resolvedArgs));
564
+ let notExecuted = false;
565
+ const resultRow = (text, isError) => withRowNotExecuted(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, text, isError), notExecuted);
590
566
  const settleEnd = async (isError, result, refusedBy) => {
591
567
  if (refusedBy !== undefined)
592
568
  occurrences.refuse(pendingAction.toolCallId, refusedBy);
593
- const gate = emitSettled(occurrences, callStart, { result, isError }, { push: emit, structured: prepared.structuredProjector, mediaByteCapBytes: runner.deps.mediaByteCapBytes }).gate ?? decidedGate;
569
+ const settled = emitSettled(occurrences, callStart, { result, isError }, { push: emit, structured: prepared.structuredProjector, mediaByteCapBytes: runner.deps.mediaByteCapBytes });
570
+ notExecuted = settled.notExecuted === true;
571
+ const gate = settled.gate ?? decidedGate;
594
572
  const word = await resume.recordExecutionOutcome(gate);
595
573
  settleExecutionRecord(runner.deps.onNotice, word, { toolName: pendingAction.toolName, gate, sessionId: prepared.sessionId, runId: prepared.runId, scope: resume.cp.scope, ...(resume.cp.checkpointId !== undefined ? { checkpointId: resume.cp.checkpointId } : {}) });
596
574
  };
@@ -604,7 +582,7 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
604
582
  : `No one answered the approval request for the pending tool call "${pendingAction.toolName}" — the approval window elapsed with no answer, so it was not executed.`
605
583
  : humanRefusalSentence("tool use", outcome.reason, prepared.hookIdentity.isDelegatedChild);
606
584
  await settleEnd(true, { content: formatHookFeedback(reason, prepared.reminderMark) });
607
- const eid = await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, formatHookFeedback(reason, prepared.reminderMark), true));
585
+ const eid = await prepared.session.appendMessage(resultRow(formatHookFeedback(reason, prepared.reminderMark), true));
608
586
  emitCommitted(eid, "toolResult", pendingAction.toolCallId);
609
587
  const parkedFallback = pendingAction.denialLimitFallback;
610
588
  if (parkedFallback !== undefined && settlementKind !== undefined && SETTLEMENT_NOBODY_JUDGED[settlementKind]) {
@@ -619,7 +597,7 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
619
597
  if (screened !== undefined && "refused" in screened) {
620
598
  const hookDenial = formatHookFeedback(screened.refused, prepared.reminderMark);
621
599
  await settleEnd(true, { content: hookDenial }, "hook");
622
- emitCommitted(await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, hookDenial, true)), "toolResult", pendingAction.toolCallId);
600
+ emitCommitted(await prepared.session.appendMessage(resultRow(hookDenial, true)), "toolResult", pendingAction.toolCallId);
623
601
  return;
624
602
  }
625
603
  const executedArgs = humanRewrite !== undefined ? resolvedArgs : screened !== undefined ? screened.args : resolvedArgs;
@@ -630,7 +608,7 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
630
608
  if (unjudgeable !== undefined) {
631
609
  const chainDenial = formatHookFeedback(`The approved tool call "${pendingAction.toolName}" was not executed: its input changed after the approval and the inherited ancestor chain cannot judge the changed input (${unjudgeable}). This approval is spent — the call has to be re-issued.`, prepared.reminderMark);
632
610
  await settleEnd(true, { content: chainDenial }, "policy");
633
- emitCommitted(await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, chainDenial, true)), "toolResult", pendingAction.toolCallId);
611
+ emitCommitted(await prepared.session.appendMessage(resultRow(chainDenial, true)), "toolResult", pendingAction.toolCallId);
634
612
  return;
635
613
  }
636
614
  const beltBudget = {
@@ -659,7 +637,7 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
659
637
  : " (the policy rewrote these bytes to a value that was not approved)";
660
638
  const editedDenial = formatHookFeedback(`${outcome.updatedInput !== undefined ? "The approver EDITED this call's input; the edited call" : "A PreToolUse hook REWROTE this approved call's input; the rewritten call"} is refused by the deployment's tool policy and was not executed${why}.`, prepared.reminderMark);
661
639
  await settleEnd(true, { content: editedDenial, ...denialCard(rechecked) }, "policy");
662
- const eid = await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, editedDenial, true));
640
+ const eid = await prepared.session.appendMessage(resultRow(editedDenial, true));
663
641
  emitCommitted(eid, "toolResult", pendingAction.toolCallId);
664
642
  return;
665
643
  }
@@ -669,7 +647,7 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
669
647
  if (gateOrgGoverned && prepared.permissionRuleOrg === undefined) {
670
648
  const unwiredDenial = formatHookFeedback(`The approved tool call "${pendingAction.toolName}" was not executed: its approval was minted under organization governance (${gateRealApproval.origin}), and this worker has no org adjudication wiring — a governed approval may only be redeemed where governance can be enforced. This approval is spent; re-issue the call on an org-wired worker.`, prepared.reminderMark);
671
649
  await settleEnd(true, { content: unwiredDenial }, "org");
672
- const eid = await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, unwiredDenial, true));
650
+ const eid = await prepared.session.appendMessage(resultRow(unwiredDenial, true));
673
651
  emitCommitted(eid, "toolResult", pendingAction.toolCallId);
674
652
  return;
675
653
  }
@@ -703,7 +681,7 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
703
681
  : "";
704
682
  const orgDenial = formatHookFeedback(`The approved tool call "${pendingAction.toolName}" was not executed: ${blocked}.${orgDisclosures} This approval is spent — the call has to be re-issued and ${unanswered ? "decided by a person" : "approved again once organization policy permits it"}.`, prepared.reminderMark);
705
683
  await settleEnd(true, { content: orgDenial }, "org");
706
- const eid = await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, orgDenial, true));
684
+ const eid = await prepared.session.appendMessage(resultRow(orgDenial, true));
707
685
  emitCommitted(eid, "toolResult", pendingAction.toolCallId);
708
686
  return;
709
687
  }
@@ -713,7 +691,7 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
713
691
  if (narrowed.action === "deny") {
714
692
  const narrowedDenial = formatHookFeedback(`The approved tool call "${pendingAction.toolName}" is now denied by ${ruleSourcePhrase("narrowing")} and was not executed${narrowed.message ? `: ${narrowed.message}` : ""}.`, prepared.reminderMark);
715
693
  await settleEnd(true, { content: narrowedDenial, ...denialCard(narrowed) }, "policy");
716
- const eid = await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, narrowedDenial, true));
694
+ const eid = await prepared.session.appendMessage(resultRow(narrowedDenial, true));
717
695
  emitCommitted(eid, "toolResult", pendingAction.toolCallId);
718
696
  return;
719
697
  }
@@ -722,7 +700,7 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
722
700
  if (skillRefusal !== undefined) {
723
701
  const skillDenial = formatHookFeedback(`The approved tool call "${pendingAction.toolName}" was not executed: ${skillRefusal.message}. This approval is spent — the call has to be re-issued.`, prepared.reminderMark);
724
702
  await settleEnd(true, { content: skillDenial }, "policy");
725
- emitCommitted(await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, skillDenial, true)), "toolResult", pendingAction.toolCallId);
703
+ emitCommitted(await prepared.session.appendMessage(resultRow(skillDenial, true)), "toolResult", pendingAction.toolCallId);
726
704
  return;
727
705
  }
728
706
  if (prepared.persistedRuleLane !== undefined) {
@@ -745,7 +723,7 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
745
723
  : `it could not be read against your standing deny/ask rules (${read.reason})`;
746
724
  const ruleDenial = formatHookFeedback(`The approved tool call "${pendingAction.toolName}" was not executed: ${why}. This approval is spent — the call has to be re-issued and approved again.`, prepared.reminderMark);
747
725
  await settleEnd(true, { content: ruleDenial, ...denialCard(tightened.decision) }, "persisted_rule");
748
- const eid = await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, ruleDenial, true));
726
+ const eid = await prepared.session.appendMessage(resultRow(ruleDenial, true));
749
727
  emitCommitted(eid, "toolResult", pendingAction.toolCallId);
750
728
  return;
751
729
  }
@@ -768,7 +746,7 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
768
746
  if (reading.kind === "refuse" || reading.kind === "silence" || (unseen && reading.kind !== "vouch")) {
769
747
  const readDenial = formatHookFeedback(`The approved tool call "${pendingAction.toolName}" was not executed: ${reading.verdict.sentence ?? "the read boundary does not vouch for what it reads on this leg"} This approval is spent — the call has to be re-issued and approved again.`, prepared.reminderMark);
770
748
  await settleEnd(true, { content: readDenial, ...(reading.verdict.details !== undefined ? { details: reading.verdict.details } : {}) }, "read_boundary");
771
- const eid = await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, readDenial, true));
749
+ const eid = await prepared.session.appendMessage(resultRow(readDenial, true));
772
750
  emitCommitted(eid, "toolResult", pendingAction.toolCallId);
773
751
  return;
774
752
  }
@@ -779,7 +757,7 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
779
757
  if (grantRefusal !== undefined) {
780
758
  const grantDenial = formatHookFeedback(grantRefusal, prepared.reminderMark);
781
759
  await settleEnd(true, { content: grantDenial }, "policy");
782
- emitCommitted(await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, grantDenial, true)), "toolResult", pendingAction.toolCallId);
760
+ emitCommitted(await prepared.session.appendMessage(resultRow(grantDenial, true)), "toolResult", pendingAction.toolCallId);
783
761
  return;
784
762
  }
785
763
  const tool = prepared.tools.find((t) => t.name === pendingAction.toolName);
@@ -791,7 +769,7 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
791
769
  const args = executedArgs;
792
770
  screened?.admit();
793
771
  onExecuteStart?.(pendingAction.toolCallId);
794
- occurrences.execute(pendingAction.toolCallId);
772
+ occurrences.release(pendingAction.toolCallId);
795
773
  prepared.suspendProgressRef.executedApproved = true;
796
774
  const finalize = (executed) => prepared.harness.finalizeToolCall({ type: "toolCall", id: pendingAction.toolCallId, name: spelledName, arguments: executedArgs }, executedArgs, executed);
797
775
  let res;
@@ -804,7 +782,7 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
804
782
  const failed = await finalize({ result: { content: [{ type: "text", text: execError }], details: marks ?? {} }, isError: true });
805
783
  const failedText = failed.result.content.flatMap((c) => (c.type === "text" ? [c.text] : [])).join("\n");
806
784
  await settleEnd(true, { content: failedText, ...(marks !== undefined ? { details: marks } : {}) });
807
- const eid = await prepared.session.appendMessage(toolResultMsg(pendingAction.toolCallId, pendingAction.toolName, failedText, true));
785
+ const eid = await prepared.session.appendMessage(resultRow(failedText, true));
808
786
  emitCommitted(eid, "toolResult", pendingAction.toolCallId);
809
787
  return;
810
788
  }
@@ -816,7 +794,7 @@ async function resolvePendingCall(runner, prepared, resume, emit, emitCommitted,
816
794
  toolCallId: pendingAction.toolCallId,
817
795
  toolName: pendingAction.toolName,
818
796
  content: ran.result.content,
819
- details: ran.result.details,
797
+ details: rowDetailsOf(ran.result.details, notExecuted),
820
798
  isError: ran.isError,
821
799
  timestamp: Date.now(),
822
800
  });
@@ -15,6 +15,7 @@ async function runNotificationLaneAs(input, obligations) {
15
15
  suspendedBatch: new Set(resume.cp.pendingAction.kind === "tool_approval" ? resume.cp.pendingAction.batchToolCallIds : []),
16
16
  seed: resume.cp.state,
17
17
  outcome: resume.outcome,
18
+ ...(resume.legMods !== undefined ? { legMods: resume.legMods } : {}),
18
19
  priorSuspendCount: resume.cp.suspendCount,
19
20
  priorLedger: resume.cp.resourceLedger,
20
21
  priorHumanReview: resume.cp.humanReview,
@@ -3,6 +3,7 @@ import { type MaybeCompactOptions } from "../auto-compaction.js";
3
3
  import type { PushQueue } from "../push-queue.js";
4
4
  import type { Brain, TaskEvent, TaskSpec } from "../types.js";
5
5
  import type { InstallingPhaseResult, Prepared, RunnerDepsSeat, RunState } from "./contracts.js";
6
+ import type { CallerStopGate } from "./caller-stop-gate.js";
6
7
  export interface RunRecoveryLanesInput {
7
8
  /** borrowed-readonly — the task spec: the compaction settings / instructions and the key-and-headers seat. */
8
9
  spec: TaskSpec;
@@ -30,6 +31,8 @@ export interface RunRecoveryLanesInput {
30
31
  };
31
32
  /** borrowed-readonly — the window-safety option builder (the compaction-machinery lane's), per pass. */
32
33
  windowSafetyOptions: (mainModel: Model) => Pick<MaybeCompactOptions, "fallbackBudget" | "onWindowSafety">;
34
+ /** borrowed-readonly — the run's caller-stop gate: the shared pass admits on it and carries it. */
35
+ callerStop: CallerStopGate;
33
36
  /** borrowed-readonly — the Runner's deployment deps, read LIVE (`onError`; the compaction seams the pass reaches down
34
37
  * for — compaction-seams.ts — read the summary provider and the hooks slot through it on every pass). */
35
38
  runner: RunnerDepsSeat;
@@ -2,7 +2,7 @@ import { compactionKindOf } from "../task-notification.js";
2
2
  import { planRejectionClears } from "../context-edit.js";
3
3
  import { rosterToolName } from "../tool-roster.js";
4
4
  import { landStaleResultClears } from "./prepare-context-lane.js";
5
- import { DEFAULT_COMPACTION_INSTRUCTIONS, maybeCompact, mintCompactedEvent } from "../auto-compaction.js";
5
+ import { DEFAULT_COMPACTION_INSTRUCTIONS, isCompactionManualCancel, maybeCompact, mintCompactedEvent } from "../auto-compaction.js";
6
6
  import { emitTrace } from "../trace.js";
7
7
  import { isDegenerateCutMessage } from "../../brain/terminal-cause.js";
8
8
  import { rebaseCadenceWindows } from "./turn-attachments.js";
@@ -13,17 +13,19 @@ import { COMPACTION_FREED_EPSILON, COMPACTION_REGROWTH_FACTOR, MAX_CONSECUTIVE_C
13
13
  import { compactionHookOptions, recordCompactionReuse, seamCCompactionOptions } from "./compaction-seams.js";
14
14
  import { asThrownError, thrownText } from "../thrown-value.js";
15
15
  export function runRecoveryLanes(input) {
16
- const { spec, prepared, queue, rs, ident, compactionBrain, compactionBreaker, windowSafetyOptions, runner } = input;
16
+ const { spec, prepared, queue, rs, ident, compactionBrain, compactionBreaker, windowSafetyOptions, callerStop, runner } = input;
17
17
  const runForcedCompactionPass = async (lane, turnSignal) => {
18
18
  if (!compactionEnabled(spec.compaction?.enabled, legContextOverlayOption(prepared, runner).contextOverlay))
19
19
  return false;
20
20
  if (compactionBreaker.failures >= MAX_CONSECUTIVE_COMPACTION_FAILURES)
21
21
  return false;
22
- const passSignal = turnSignal !== undefined ? AbortSignal.any([prepared.abortController.signal, turnSignal]) : prepared.abortController.signal;
22
+ if (callerStop.signal.aborted)
23
+ return false;
24
+ const passSignal = AbortSignal.any([prepared.abortController.signal, callerStop.signal, ...(turnSignal !== undefined ? [turnSignal] : [])]);
23
25
  try {
24
26
  const comp = await maybeCompact({
25
27
  session: prepared.session,
26
- epochDeclaredSections: prepared.epochDeclaredSections,
28
+ promptIdentity: prepared.promptIdentity,
27
29
  ...centerAdoptionOption(prepared),
28
30
  model: prepared.harness.getModel(),
29
31
  ...legContextOverlayOption(prepared, runner),
@@ -35,6 +37,7 @@ export function runRecoveryLanes(input) {
35
37
  settings: legCompactionSettings(spec, legContextOverlayOption(prepared, runner).contextOverlay),
36
38
  customInstructions: spec.compaction?.instructions ?? DEFAULT_COMPACTION_INSTRUCTIONS,
37
39
  signal: passSignal,
40
+ manualCancelSignal: callerStop.signal,
38
41
  minTokens: 0,
39
42
  force: true,
40
43
  overheadTokens: prepared.promptOverheadTokens,
@@ -46,7 +49,7 @@ export function runRecoveryLanes(input) {
46
49
  ...seamCCompactionOptions(runner, prepared),
47
50
  ...compactionRestateOptions(prepared),
48
51
  ...windowSafetyOptions(prepared.harness.getModel()),
49
- ...compactionHookOptions(runner, spec, prepared.sessionId, "forced", prepared.hookIdentity, { timeoutMs: prepared.hookTimeoutMs, signal: passSignal }),
52
+ ...compactionHookOptions(runner, prepared, "forced", passSignal),
50
53
  });
51
54
  if (comp.compacted) {
52
55
  compactionBreaker.failures = 0;
@@ -90,11 +93,9 @@ export function runRecoveryLanes(input) {
90
93
  return comp.compacted === true;
91
94
  }
92
95
  catch (err) {
93
- if (turnSignal?.aborted === true && !prepared.abortController.signal.aborted) {
94
- const interruptReason = lane === "rejection"
95
- ? "prompt-too-long recovery pass cut short by a turn interrupt"
96
- : "guard-chain forced compaction cut short by a turn interrupt";
97
- queue.push({ type: "compaction_outcome", outcome: "failed", trigger: "forced", reason: interruptReason, ...ident() });
96
+ if (isCompactionManualCancel(err) || (turnSignal?.aborted === true && !prepared.abortController.signal.aborted)) {
97
+ emitTrace(rs.telemetry.tracer, () => ({ kind: "compaction.mooted", version: 1, taskId: rs.telemetry.taskId, reason: "cancelled", ts: Date.now() }));
98
+ queue.push({ type: "compaction_outcome", outcome: "mooted", trigger: "forced", reason: "cancelled", ...ident() });
98
99
  return false;
99
100
  }
100
101
  compactionBreaker.failures += 1;
@@ -6,7 +6,7 @@ import { isDegenerateCutMessage } from "../../brain/terminal-cause.js";
6
6
  import { hasBackgroundShell, sweepRunBoundaryBackgroundShells } from "../background-shell.js";
7
7
  import { resolveCheckpointStore } from "../checkpoint-store.js";
8
8
  import { reopenReasonOf, reopenedUnstartedSentence, resumeStartupCauseOf } from "../resume-startup-cause.js";
9
- import { hookSeatExpiredError, runHookSeat } from "../hooks.js";
9
+ import { classicEventBase, observeClassic } from "../mods/stations.js";
10
10
  import { modelCostToPricing } from "../pricing.js";
11
11
  import { hasDestroy, isIsolated } from "../remote-env.js";
12
12
  import { resolveTaskModel } from "../roles.js";
@@ -25,7 +25,6 @@ import { owedDateAnchor } from "./announce-once-ledger.js";
25
25
  import { autoRunConsolidationFromRecommendation, autoRunOnRecommendationEffective, scopeHasUnconsumedRecommendation } from "./memory-consolidation-driver.js";
26
26
  import { amendTerminal, terminalProjection } from "./terminal-projection.js";
27
27
  import { mintCompactedEvent } from "../auto-compaction.js";
28
- import { asThrownError } from "../thrown-value.js";
29
28
  export async function runSettleAndTeardown(input) {
30
29
  const { spec, queue, prepared, resume, internals, rs, stats, ident, loopLatch, timeout, ownCommittedTailRef, emitDelegationLifecycle, taskIdRef, manualCompactRef, drainManualCompact, final, threw, abortedLive, userInterruptedLive, answerSettled, strandedHumanAnswers, reasoningResolution, comp, compactionBreaker, owedUserInput, setResult, onSuggestions, onSuspend, runner, sessions } = input;
31
30
  try {
@@ -57,7 +56,7 @@ export async function runSettleAndTeardown(input) {
57
56
  const cause = rs.degrade.degraded
58
57
  ? `a mid-task model switch (${rs.degrade.degraded.from} → ${rs.degrade.degraded.to}, degradation) reset the prefix cache — this is the likely cause`
59
58
  : cacheWritten > 0
60
- ? `this task reported ${cacheWritten} cache-write tokens across its calls (compaction included) but served almost none back as reads — consistent with a prompt prefix that CHANGES between turns (client-side: volatile content up front, or per-turn tool churn/reorder) and, less often, with server-side eviction. Keep volatile content (memory/timestamps/ids) out of the prefix and the tool list stable in membership AND order`
59
+ ? `this task reported ${cacheWritten} cache-write tokens across its calls (compaction and the classifier's included) but served almost none back as reads — consistent with a prompt prefix that CHANGES between turns (client-side: volatile content up front, or per-turn tool churn/reorder) and, less often, with server-side eviction. Keep volatile content (memory/timestamps/ids) out of the prefix and the tool list stable in membership AND order`
61
60
  : `no call in this task reported any cache-write tokens — and this API family may not report them at all (an openai-shaped usage row carries cached READS only), so the write side is no evidence here; check that the prompt prefix (system prompt + tool list, membership AND order) is byte-stable across turns and that this route caches this model`;
62
61
  runner.deps.onError?.(new Error(`prompt-cache: low prefix-cache hit rate ${(stats.cacheHitRate * 100).toFixed(0)}% over ${stats.turns} turns (${stats.totalInputTokens} prompt tokens) — ${cause}. See design/09.`), { phase: "prompt-cache", sessionId: prepared.sessionId });
63
62
  }
@@ -168,8 +167,7 @@ export async function runSettleAndTeardown(input) {
168
167
  }
169
168
  }
170
169
  }
171
- const stopFailureHook = (spec.hooks ?? runner.deps.hooks)?.stopFailure;
172
- if (stopFailureHook !== undefined &&
170
+ if (prepared.modBus.hasHandlers("classic.StopFailure") &&
173
171
  result.terminal.kind === "failed" &&
174
172
  final?.stopReason === "error" &&
175
173
  !isDegenerateCutMessage(final) &&
@@ -180,29 +178,12 @@ export async function runSettleAndTeardown(input) {
180
178
  !abortedLive &&
181
179
  result.terminal.code !== "conflict") {
182
180
  const failedCause = result.terminal;
183
- try {
184
- const failureSeat = await runHookSeat("stopFailure", { timeoutMs: prepared.hookTimeoutMs }, (sig) => stopFailureHook({
185
- identity: prepared.hookIdentity,
186
- error: failedCause.message ?? "model error",
187
- ...(failedCause.code !== undefined ? { errorKind: failedCause.code } : {}),
188
- turns: stats.turns,
189
- signal: sig,
190
- }));
191
- if (failureSeat.expired) {
192
- try {
193
- runner.deps.onError?.(hookSeatExpiredError("stopFailure", prepared.hookTimeoutMs, failureSeat.cause, "the terminal observation was abandoned; the assembled TaskResult is unchanged"), { phase: "hook", sessionId: prepared.sessionId });
194
- }
195
- catch {
196
- }
197
- }
198
- }
199
- catch (err) {
200
- try {
201
- runner.deps.onError?.(asThrownError(err), { phase: "hook", sessionId: prepared.sessionId });
202
- }
203
- catch {
204
- }
205
- }
181
+ await observeClassic(prepared.modBus, "classic.StopFailure", {
182
+ ...classicEventBase(prepared.hookIdentity),
183
+ error: failedCause.message ?? "model error",
184
+ ...(failedCause.code !== undefined ? { errorKind: failedCause.code } : {}),
185
+ turns: stats.turns,
186
+ }, undefined);
206
187
  }
207
188
  const terminalFace = terminalProjection(result.terminal);
208
189
  emitDelegationLifecycle({
@@ -1,10 +1,12 @@
1
1
  import { openSystemReminder } from "../reminder-mint.js";
2
- import { formatHookFeedback, hookSeatExpiredError, runHookSeat } from "../hooks.js";
2
+ import { formatHookFeedback } from "../hooks.js";
3
+ import { classicEventBase, dispatchClassic, stopEventOf, stringMembersAnswer, stringMembersOf } from "../mods/stations.js";
3
4
  import { asThrownError } from "../thrown-value.js";
4
5
  const STOP_HOOK_BLOCK_CAP = 8;
5
6
  export function runStopAndFinalVerify(input) {
6
7
  const { spec, prepared, queue, rs, stats, ident, walltimeMonotonicDeadline, runner } = input;
7
- const stopHook = (spec.hooks ?? runner.deps.hooks)?.stop;
8
+ const stopEvent = stopEventOf(prepared.hookIdentity);
9
+ const stopArmed = prepared.modBus.hasHandlers(stopEvent);
8
10
  const finalVerificationOn = spec.finalVerification === true;
9
11
  const finalVerifyBudgetFill = () => {
10
12
  let worst = 0;
@@ -22,7 +24,7 @@ export function runStopAndFinalVerify(input) {
22
24
  const emitFinalVerifyEcho = (body) => {
23
25
  queue.push({ type: "steering_injected", source: "final_verification", preview: body.slice(0, 220), ...ident() });
24
26
  };
25
- if (stopHook || finalVerificationOn) {
27
+ if (stopArmed || finalVerificationOn) {
26
28
  let consecutiveBlocks = 0;
27
29
  prepared.harness.setStopGate(async () => {
28
30
  if (prepared.abortController.signal.aborted || prepared.pausedRef.current !== undefined || prepared.batchHaltRef.current !== undefined)
@@ -100,32 +102,23 @@ export function runStopAndFinalVerify(input) {
100
102
  },
101
103
  ];
102
104
  }
103
- if (!stopHook)
105
+ if (!stopArmed)
104
106
  return [];
105
- let result;
106
- try {
107
- const stopSeat = await runHookSeat("stop", { timeoutMs: prepared.hookTimeoutMs, signal: prepared.abortController.signal, abortEnds: true }, (sig) => stopHook({
108
- stopHookActive: consecutiveBlocks > 0,
109
- consecutiveBlocks,
110
- getBranch: () => prepared.session.getBranch(),
111
- backgroundTasks: () => prepared.listBackgroundTasks(),
112
- identity: prepared.hookIdentity,
113
- permissionMode: prepared.permissionMode.observed,
114
- signal: sig,
115
- }));
116
- if (stopSeat.expired) {
117
- if (stopSeat.cause === "timeout") {
118
- runner.deps.onError?.(hookSeatExpiredError("stop", prepared.hookTimeoutMs, stopSeat.cause, "the run was allowed to END (the seat's own no-opinion answer); no pushback and no additional context were injected"), { phase: "hook", sessionId: prepared.sessionId });
119
- }
120
- consecutiveBlocks = 0;
121
- return [];
122
- }
123
- result = stopSeat.value;
124
- }
125
- catch (err) {
107
+ const outcome = await dispatchClassic(prepared.modBus, stopEvent, {
108
+ ...classicEventBase(prepared.hookIdentity, prepared.permissionMode.observed),
109
+ stopHookActive: consecutiveBlocks > 0,
110
+ consecutiveBlocks,
111
+ getBranch: () => prepared.session.getBranch(),
112
+ backgroundTasks: () => prepared.listBackgroundTasks(),
113
+ }, { signal: prepared.abortController.signal, checkAnswer: stringMembersAnswer(stopEvent, ["block", "additionalContext"]) }).catch((err) => {
126
114
  runner.deps.onError?.(asThrownError(err), { phase: "hook", sessionId: prepared.sessionId });
115
+ return undefined;
116
+ });
117
+ if (outcome?.kind !== "answered") {
118
+ consecutiveBlocks = 0;
127
119
  return [];
128
120
  }
121
+ const result = stringMembersOf(outcome.answer, ["block", "additionalContext"]);
129
122
  const messages = [];
130
123
  if (result?.additionalContext) {
131
124
  messages.push({
@@ -22,6 +22,7 @@ import type { PushQueue } from "../push-queue.js";
22
22
  import type { Brain, OwedUserInputAccount, TaskEvent, TaskSpec } from "../types.js";
23
23
  import { type Stats } from "./assemble-result.js";
24
24
  import type { EndOfTaskCompaction, Prepared, RunnerDepsSeat, RunState } from "./contracts.js";
25
+ import type { CallerStopGate } from "./caller-stop-gate.js";
25
26
  export interface RunTerminalAdoptionInput<R> {
26
27
  /** borrowed-readonly — the task spec: the task id the account's notices name; `finish`'s first argument (the end-of-task pass below). */
27
28
  spec: TaskSpec;
@@ -78,6 +79,8 @@ export interface RunTerminalAdoptionInput<R> {
78
79
  abortedLive: boolean;
79
80
  /** borrowed-readonly — the leg's snapshot of `loopLatch.userInterrupted` (gates the interruption marker). */
80
81
  userInterruptedLive: boolean;
82
+ /** borrowed-readonly — the run's caller-stop gate: the end-of-task pass admits on it and carries it (read LIVE, never snapshot). */
83
+ callerStop: CallerStopGate;
81
84
  /** borrowed-readonly — the Runner's deployment deps, read LIVE (`onError`, `checkpointStore`, `onNotice`, `mediaByteCapBytes`); the one home of why it is
82
85
  * a seat and not a captured object is {@link RunnerDepsSeat}. */
83
86
  runner: RunnerDepsSeat;