@sema-agent/core 7.55.0 → 7.57.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 (502) hide show
  1. package/CHANGELOG.md +1054 -0
  2. package/LICENSE +1 -1
  3. package/dist/agents/cascade.js +1 -1
  4. package/dist/agents/cc-peer-directory.js +1 -0
  5. package/dist/agents/child-model-seat.d.ts +0 -11
  6. package/dist/agents/child-model-seat.js +0 -3
  7. package/dist/agents/list-agents-tool.d.ts +3 -1
  8. package/dist/agents/list-agents-tool.js +7 -7
  9. package/dist/agents/org-delivery-gate.js +3 -4
  10. package/dist/agents/peer-directory.d.ts +22 -4
  11. package/dist/agents/peer-directory.js +24 -2
  12. package/dist/agents/peer-held-queue.d.ts +69 -49
  13. package/dist/agents/peer-held-queue.js +255 -106
  14. package/dist/agents/peer-session-drain.js +65 -45
  15. package/dist/agents/repair-loop.js +2 -2
  16. package/dist/agents/send-message-tool.js +7 -6
  17. package/dist/agents/subagent.d.ts +6 -4
  18. package/dist/agents/subagent.js +72 -68
  19. package/dist/agents/tool-filter.d.ts +7 -5
  20. package/dist/agents/tool-filter.js +12 -9
  21. package/dist/agents/verify.d.ts +3 -2
  22. package/dist/agents/verify.js +3 -3
  23. package/dist/brain/anthropic.js +45 -80
  24. package/dist/brain/media-degrade.d.ts +18 -7
  25. package/dist/brain/media-degrade.js +13 -2
  26. package/dist/brain/model-capability.d.ts +37 -0
  27. package/dist/brain/model-capability.js +34 -0
  28. package/dist/brain/model-presets.d.ts +2 -8
  29. package/dist/brain/model-presets.js +1 -6
  30. package/dist/brain/open-responses.js +23 -34
  31. package/dist/brain/openai.js +25 -96
  32. package/dist/brain/provider-dialect.d.ts +3 -2
  33. package/dist/brain/provider-dialect.js +2 -2
  34. package/dist/brain/reasoning-request.d.ts +96 -0
  35. package/dist/brain/reasoning-request.js +174 -0
  36. package/dist/brain/reasoning.d.ts +11 -11
  37. package/dist/brain/reasoning.js +4 -3
  38. package/dist/brain/request-params.d.ts +13 -4
  39. package/dist/brain/request-params.js +21 -5
  40. package/dist/brain/status-sink.d.ts +20 -0
  41. package/dist/brain/status-sink.js +7 -0
  42. package/dist/brain/stream-engine.d.ts +9 -0
  43. package/dist/brain/stream-engine.js +24 -10
  44. package/dist/brain/stream-shared.d.ts +5 -4
  45. package/dist/brain/stream-shared.js +4 -4
  46. package/dist/core/a2a.d.ts +2 -1
  47. package/dist/core/a2a.js +19 -13
  48. package/dist/core/agent-definition.d.ts +10 -0
  49. package/dist/core/allow-entry.d.ts +23 -23
  50. package/dist/core/allow-entry.js +42 -46
  51. package/dist/core/allow-rule-shadow.d.ts +3 -3
  52. package/dist/core/approval-object.d.ts +21 -5
  53. package/dist/core/approval-object.js +44 -17
  54. package/dist/core/ask-origin.d.ts +66 -20
  55. package/dist/core/ask-origin.js +63 -23
  56. package/dist/core/ask-question.d.ts +51 -8
  57. package/dist/core/ask-question.js +3 -4
  58. package/dist/core/ask-unresolvable-notice.d.ts +8 -3
  59. package/dist/core/ask-unresolvable-notice.js +16 -2
  60. package/dist/core/auto-compaction.d.ts +71 -6
  61. package/dist/core/auto-compaction.js +42 -26
  62. package/dist/core/background-agent-store.d.ts +6 -2
  63. package/dist/core/background-agent-store.js +1 -1
  64. package/dist/core/checkpoint-generation.d.ts +53 -0
  65. package/dist/core/checkpoint-generation.js +35 -0
  66. package/dist/core/checkpoint-queries.d.ts +180 -0
  67. package/dist/core/checkpoint-queries.js +272 -0
  68. package/dist/core/checkpoint-requirements.d.ts +19 -1
  69. package/dist/core/checkpoint-requirements.js +6 -0
  70. package/dist/core/checkpoint-store.d.ts +105 -53
  71. package/dist/core/checkpoint-store.js +43 -20
  72. package/dist/core/cross-boundary-taint.d.ts +6 -5
  73. package/dist/core/cross-boundary-taint.js +5 -5
  74. package/dist/core/decision-receipt.d.ts +37 -3
  75. package/dist/core/decision-receipt.js +17 -17
  76. package/dist/core/delegation-not-started.d.ts +6 -0
  77. package/dist/core/delegation-not-started.js +17 -0
  78. package/dist/core/engine-attestation.d.ts +93 -0
  79. package/dist/core/engine-attestation.js +70 -0
  80. package/dist/core/engine-capabilities.d.ts +4 -1
  81. package/dist/core/engine-capabilities.js +1 -1
  82. package/dist/core/engine-notice.d.ts +32 -12
  83. package/dist/core/engine-notice.js +6 -0
  84. package/dist/core/file-history-store.d.ts +104 -22
  85. package/dist/core/file-history-store.js +37 -19
  86. package/dist/core/gate-fold.d.ts +1 -1
  87. package/dist/core/gate-fold.js +22 -10
  88. package/dist/core/gate-lanes.js +73 -65
  89. package/dist/core/gate-outcome.d.ts +26 -5
  90. package/dist/core/gate-outcome.js +26 -0
  91. package/dist/core/governance-codes.d.ts +5 -1
  92. package/dist/core/governance-codes.js +6 -0
  93. package/dist/core/hooks.d.ts +19 -18
  94. package/dist/core/hooks.js +3 -1
  95. package/dist/core/host-floor.d.ts +128 -0
  96. package/dist/core/host-floor.js +206 -0
  97. package/dist/core/host-target.d.ts +38 -3
  98. package/dist/core/host-target.js +38 -5
  99. package/dist/core/mailbox-store.d.ts +62 -1
  100. package/dist/core/mailbox-store.js +59 -0
  101. package/dist/core/mcp-name-judge.d.ts +46 -0
  102. package/dist/core/mcp-name-judge.js +61 -0
  103. package/dist/core/mcp-probe.d.ts +1 -1
  104. package/dist/core/mcp-probe.js +2 -5
  105. package/dist/core/mcp.d.ts +5 -1
  106. package/dist/core/mcp.js +70 -64
  107. package/dist/core/memory-engine/consolidation-driver.js +4 -3
  108. package/dist/core/memory-engine/delegation-settlement.js +15 -24
  109. package/dist/core/memory-engine/distiller.js +26 -17
  110. package/dist/core/memory-engine/engine.js +4 -4
  111. package/dist/core/memory-engine/layout.d.ts +60 -8
  112. package/dist/core/memory-engine/layout.js +70 -8
  113. package/dist/core/model-seat.d.ts +10 -3
  114. package/dist/core/mods/classic-events.d.ts +67 -0
  115. package/dist/core/mods/classic-events.js +1 -0
  116. package/dist/core/mods/dollar.d.ts +13 -0
  117. package/dist/core/mods/extension-call.d.ts +31 -0
  118. package/dist/core/mods/extension-call.js +43 -0
  119. package/dist/core/mods/kernel/dispatch.d.ts +20 -3
  120. package/dist/core/mods/kernel/dispatch.js +140 -69
  121. package/dist/core/mods/kernel/events.d.ts +47 -11
  122. package/dist/core/mods/kernel/events.js +66 -42
  123. package/dist/core/mods/kernel/index.d.ts +4 -4
  124. package/dist/core/mods/kernel/index.js +2 -2
  125. package/dist/core/mods/kernel/receive.d.ts +39 -5
  126. package/dist/core/mods/kernel/receive.js +290 -17
  127. package/dist/core/mods/kernel/registration.d.ts +33 -2
  128. package/dist/core/mods/kernel/registration.js +6 -7
  129. package/dist/core/mods/kernel/site-rules.d.ts +44 -16
  130. package/dist/core/mods/kernel/site-rules.js +24 -42
  131. package/dist/core/mods/spec-seats.d.ts +69 -0
  132. package/dist/core/mods/spec-seats.js +114 -0
  133. package/dist/core/mods/stations.d.ts +28 -8
  134. package/dist/core/mods/stations.js +29 -13
  135. package/dist/core/mods/tool-call.d.ts +79 -0
  136. package/dist/core/mods/tool-call.js +152 -0
  137. package/dist/core/namespaced-rule-name.d.ts +32 -38
  138. package/dist/core/namespaced-rule-name.js +29 -36
  139. package/dist/core/parent-spec-seat.d.ts +6 -1
  140. package/dist/core/parent-spec-seat.js +2 -0
  141. package/dist/core/park-selfcheck.js +3 -0
  142. package/dist/core/permission-rule-consent.d.ts +24 -3
  143. package/dist/core/permission-rule-consent.js +136 -41
  144. package/dist/core/permission-rule-model.d.ts +57 -5
  145. package/dist/core/permission-rule-model.js +90 -31
  146. package/dist/core/permission-rule-org.d.ts +6 -2
  147. package/dist/core/permission-rule-org.js +8 -4
  148. package/dist/core/permission-rule-provider.d.ts +5 -2
  149. package/dist/core/permission-rule-provider.js +41 -11
  150. package/dist/core/permission-rule-store.d.ts +3 -2
  151. package/dist/core/permission-rule-store.js +11 -2
  152. package/dist/core/permission-rule-sync.js +3 -2
  153. package/dist/core/permission-rule-syntax.d.ts +5 -4
  154. package/dist/core/permission-rule-syntax.js +2 -2
  155. package/dist/core/permission-rules.d.ts +4 -4
  156. package/dist/core/permission-rules.js +11 -20
  157. package/dist/core/persisted-rule-arms.d.ts +2 -2
  158. package/dist/core/persisted-rule-arms.js +10 -12
  159. package/dist/core/principal-name.d.ts +20 -0
  160. package/dist/core/principal-name.js +22 -0
  161. package/dist/core/prompt-section-seat.js +4 -6
  162. package/dist/core/protocol-http-auth.d.ts +40 -5
  163. package/dist/core/protocol-http-auth.js +168 -4
  164. package/dist/core/protocol-naming.d.ts +20 -0
  165. package/dist/core/protocol-naming.js +20 -3
  166. package/dist/core/read-only-shell.d.ts +20 -5
  167. package/dist/core/read-only-shell.js +29 -14
  168. package/dist/core/remote-env.d.ts +37 -1
  169. package/dist/core/remote-env.js +11 -0
  170. package/dist/core/resume-startup-cause.d.ts +24 -2
  171. package/dist/core/resume-startup-cause.js +20 -1
  172. package/dist/core/retired-keys.d.ts +16 -0
  173. package/dist/core/retired-keys.js +16 -4
  174. package/dist/core/rewrite-rejudge.d.ts +60 -0
  175. package/dist/core/rewrite-rejudge.js +36 -0
  176. package/dist/core/roles.d.ts +28 -1
  177. package/dist/core/roles.js +81 -26
  178. package/dist/core/rule-lane-reads.d.ts +20 -15
  179. package/dist/core/rule-lane-reads.js +45 -17
  180. package/dist/core/rule-owner.d.ts +3 -3
  181. package/dist/core/rule-owner.js +3 -2
  182. package/dist/core/runner/announce-once-ledger.d.ts +14 -0
  183. package/dist/core/runner/announce-once-ledger.js +5 -0
  184. package/dist/core/runner/assemble-result.d.ts +1 -0
  185. package/dist/core/runner/assemble-result.js +1 -1
  186. package/dist/core/runner/call-hook-stations.d.ts +3 -2
  187. package/dist/core/runner/caller-roster.d.ts +16 -4
  188. package/dist/core/runner/caller-roster.js +33 -6
  189. package/dist/core/runner/capability-withheld-seat.d.ts +5 -0
  190. package/dist/core/runner/capability-withheld-seat.js +24 -0
  191. package/dist/core/runner/classifier-ladder.d.ts +7 -9
  192. package/dist/core/runner/classifier-ladder.js +3 -3
  193. package/dist/core/runner/compact-session.d.ts +10 -0
  194. package/dist/core/runner/compact-session.js +202 -0
  195. package/dist/core/runner/compaction-call-options.d.ts +2 -2
  196. package/dist/core/runner/compaction-seams.d.ts +21 -1
  197. package/dist/core/runner/compaction-seams.js +11 -8
  198. package/dist/core/runner/construction-doors.js +3 -0
  199. package/dist/core/runner/contracts.d.ts +50 -40
  200. package/dist/core/runner/cross-boundary-lane.d.ts +17 -13
  201. package/dist/core/runner/cross-boundary-lane.js +40 -27
  202. package/dist/core/runner/denial-limit-arms.d.ts +2 -2
  203. package/dist/core/runner/denial-limit-arms.js +1 -1
  204. package/dist/core/runner/derived-route-fallback.d.ts +13 -0
  205. package/dist/core/runner/derived-route-fallback.js +6 -0
  206. package/dist/core/runner/env-capability-census.d.ts +3 -2
  207. package/dist/core/runner/env-capability-census.js +9 -3
  208. package/dist/core/runner/file-history-request.d.ts +18 -0
  209. package/dist/core/runner/file-history-request.js +21 -13
  210. package/dist/core/runner/file-history-restore.d.ts +45 -0
  211. package/dist/core/runner/file-history-restore.js +46 -0
  212. package/dist/core/runner/gate-exit.d.ts +3 -3
  213. package/dist/core/runner/gate-exit.js +4 -3
  214. package/dist/core/runner/image.d.ts +7 -17
  215. package/dist/core/runner/image.js +9 -60
  216. package/dist/core/runner/permission-rule-lanes.d.ts +11 -11
  217. package/dist/core/runner/permission-rule-lanes.js +39 -17
  218. package/dist/core/runner/person-path-rows.d.ts +12 -9
  219. package/dist/core/runner/person-path-rows.js +18 -7
  220. package/dist/core/runner/prepare-acquire-reconcile.d.ts +3 -0
  221. package/dist/core/runner/prepare-acquire-reconcile.js +2 -1
  222. package/dist/core/runner/prepare-ask-lane.d.ts +2 -2
  223. package/dist/core/runner/prepare-ask-lane.js +5 -2
  224. package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -6
  225. package/dist/core/runner/prepare-caps-and-workflow.js +4 -3
  226. package/dist/core/runner/prepare-config-doors.d.ts +35 -38
  227. package/dist/core/runner/prepare-config-doors.js +46 -28
  228. package/dist/core/runner/prepare-defer-classify.d.ts +4 -3
  229. package/dist/core/runner/prepare-defer-classify.js +7 -8
  230. package/dist/core/runner/prepare-file-history.d.ts +48 -8
  231. package/dist/core/runner/prepare-file-history.js +7 -39
  232. package/dist/core/runner/prepare-gate-stations.d.ts +1 -1
  233. package/dist/core/runner/prepare-gate-stations.js +10 -1
  234. package/dist/core/runner/prepare-hands-readface.d.ts +5 -9
  235. package/dist/core/runner/prepare-hands-readface.js +17 -14
  236. package/dist/core/runner/prepare-inherited-gate.d.ts +6 -3
  237. package/dist/core/runner/prepare-inherited-gate.js +5 -3
  238. package/dist/core/runner/prepare-memory-engine-session.js +1 -1
  239. package/dist/core/runner/prepare-park-ask.d.ts +2 -0
  240. package/dist/core/runner/prepare-park-ask.js +7 -7
  241. package/dist/core/runner/prepare-policy-chain.d.ts +6 -3
  242. package/dist/core/runner/prepare-policy-chain.js +67 -76
  243. package/dist/core/runner/prepare-prompt-assembly.d.ts +5 -7
  244. package/dist/core/runner/prepare-prompt-assembly.js +10 -8
  245. package/dist/core/runner/prepare-prompt-inputs.d.ts +11 -9
  246. package/dist/core/runner/prepare-prompt-inputs.js +3 -5
  247. package/dist/core/runner/prepare-protocol-tools.d.ts +2 -0
  248. package/dist/core/runner/prepare-protocol-tools.js +3 -3
  249. package/dist/core/runner/prepare-safety-scan.d.ts +1 -1
  250. package/dist/core/runner/prepare-safety-scan.js +0 -17
  251. package/dist/core/runner/prepare-suspend-saga.d.ts +2 -0
  252. package/dist/core/runner/prepare-suspend-saga.js +5 -6
  253. package/dist/core/runner/prepare-task.d.ts +5 -2
  254. package/dist/core/runner/prepare-task.js +48 -43
  255. package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +20 -4
  256. package/dist/core/runner/prepare-tool-disclosure-mount.js +33 -23
  257. package/dist/core/runner/prepare-turn-wiring.d.ts +0 -4
  258. package/dist/core/runner/prepare-turn-wiring.js +2 -7
  259. package/dist/core/runner/prepare-wiring-manifest.d.ts +6 -2
  260. package/dist/core/runner/prepare-wiring-manifest.js +3 -3
  261. package/dist/core/runner/resume-admission.js +1 -1
  262. package/dist/core/runner/resume-apply.js +11 -12
  263. package/dist/core/runner/resume-checkpoint-screen.js +3 -0
  264. package/dist/core/runner/resume-claim.d.ts +4 -2
  265. package/dist/core/runner/resume-claim.js +15 -8
  266. package/dist/core/runner/retired-runner-deps.js +1 -0
  267. package/dist/core/runner/rewind-files.d.ts +12 -0
  268. package/dist/core/runner/rewind-files.js +90 -0
  269. package/dist/core/runner/run-attachment-seats.js +2 -1
  270. package/dist/core/runner/run-brain-sinks.d.ts +4 -1
  271. package/dist/core/runner/run-brain-sinks.js +4 -2
  272. package/dist/core/runner/run-harness-handlers.js +12 -4
  273. package/dist/core/runner/run-leg.d.ts +1 -1
  274. package/dist/core/runner/run-leg.js +40 -39
  275. package/dist/core/runner/run-notification-lane.d.ts +2 -0
  276. package/dist/core/runner/run-notification-lane.js +2 -2
  277. package/dist/core/runner/run-recovery-lanes.js +3 -4
  278. package/dist/core/runner/run-settle-and-teardown.js +7 -12
  279. package/dist/core/runner/run-terminal-adoption.js +3 -4
  280. package/dist/core/runner/run-turn-boundary.js +4 -15
  281. package/dist/core/runner/runtask.d.ts +10 -0
  282. package/dist/core/runner/runtask.js +35 -42
  283. package/dist/core/runner/send-message-continuation.js +1 -1
  284. package/dist/core/runner/session-read-file-states.d.ts +15 -0
  285. package/dist/core/runner/session-read-file-states.js +28 -0
  286. package/dist/core/runner/session-rule-policy.js +4 -3
  287. package/dist/core/runner/session-verb-doors.d.ts +28 -0
  288. package/dist/core/runner/session-verb-doors.js +48 -0
  289. package/dist/core/runner/session-write-ledger.d.ts +30 -0
  290. package/dist/core/runner/session-write-ledger.js +101 -0
  291. package/dist/core/runner/shell-env-withheld.d.ts +33 -0
  292. package/dist/core/runner/shell-env-withheld.js +51 -0
  293. package/dist/core/runner/skills-seat.js +6 -2
  294. package/dist/core/runner/stream-settle-backstop.js +12 -15
  295. package/dist/core/runner/sub-agent-deny-lists.d.ts +25 -3
  296. package/dist/core/runner/sub-agent-deny-lists.js +25 -17
  297. package/dist/core/runner/synthetic-tools.d.ts +6 -0
  298. package/dist/core/runner/synthetic-tools.js +4 -1
  299. package/dist/core/runner/teardown-bounded.d.ts +1 -0
  300. package/dist/core/runner/teardown-bounded.js +1 -0
  301. package/dist/core/runner/tool-disclosure.d.ts +10 -12
  302. package/dist/core/runner/tool-disclosure.js +1 -3
  303. package/dist/core/runner/tool-end-body.d.ts +1 -1
  304. package/dist/core/runner/tool-end-body.js +10 -9
  305. package/dist/core/runner/tool-not-executed.d.ts +5 -0
  306. package/dist/core/runner/tool-not-executed.js +11 -0
  307. package/dist/core/runner/tool-occurrence.d.ts +8 -0
  308. package/dist/core/runner/tool-occurrence.js +7 -0
  309. package/dist/core/runner/turn-attachments.d.ts +33 -15
  310. package/dist/core/runner/turn-attachments.js +62 -37
  311. package/dist/core/runner-deps.d.ts +7 -7
  312. package/dist/core/safety-axis-vocab.d.ts +6 -4
  313. package/dist/core/safety-axis-vocab.js +6 -5
  314. package/dist/core/safety-merge-corpus.js +11 -3
  315. package/dist/core/secret-env.d.ts +30 -3
  316. package/dist/core/secret-env.js +47 -8
  317. package/dist/core/select-model.js +3 -3
  318. package/dist/core/session-policy-store.d.ts +32 -15
  319. package/dist/core/session-policy-store.js +156 -36
  320. package/dist/core/session-store.d.ts +29 -10
  321. package/dist/core/session-store.js +51 -19
  322. package/dist/core/session.d.ts +82 -16
  323. package/dist/core/session.js +53 -0
  324. package/dist/core/shell-read-silence.d.ts +11 -12
  325. package/dist/core/shell-read-silence.js +9 -5
  326. package/dist/core/shell-run-candidates.js +3 -1
  327. package/dist/core/shell-wrapper-projection.d.ts +1 -1
  328. package/dist/core/shell-wrapper-projection.js +1 -1
  329. package/dist/core/shell-wrapper-table.d.ts +14 -7
  330. package/dist/core/shell-wrapper-table.js +5 -4
  331. package/dist/core/side-query.js +10 -1
  332. package/dist/core/skill-grant.d.ts +7 -2
  333. package/dist/core/skill-grant.js +5 -0
  334. package/dist/core/skills-directory.js +6 -2
  335. package/dist/core/store-contracts/background-agent-store-contract.js +1 -0
  336. package/dist/core/store-contracts/checkpoint-store-contract.d.ts +11 -1
  337. package/dist/core/store-contracts/checkpoint-store-contract.js +141 -2
  338. package/dist/core/store-contracts/file-history-store-contract.js +40 -1
  339. package/dist/core/store-contracts/mailbox-store-contract.js +49 -1
  340. package/dist/core/store-contracts/peer-directory-contract.d.ts +7 -2
  341. package/dist/core/store-contracts/peer-directory-contract.js +14 -2
  342. package/dist/core/store-contracts/session-repo-contract.js +51 -0
  343. package/dist/core/store-contracts/session-store-contract.d.ts +2 -1
  344. package/dist/core/store-contracts/session-store-contract.js +150 -14
  345. package/dist/core/stub-env.d.ts +2 -0
  346. package/dist/core/stub-env.js +1 -0
  347. package/dist/core/synthetic-read-verdict.js +3 -3
  348. package/dist/core/task-event.d.ts +32 -4
  349. package/dist/core/task-notification.d.ts +16 -12
  350. package/dist/core/task-registry-agent.d.ts +8 -4
  351. package/dist/core/task-registry-agent.js +14 -8
  352. package/dist/core/task-registry-shared.d.ts +35 -6
  353. package/dist/core/task-registry-shared.js +11 -0
  354. package/dist/core/task-registry.d.ts +10 -1
  355. package/dist/core/task-registry.js +12 -2
  356. package/dist/core/task-result.d.ts +18 -0
  357. package/dist/core/task-spec.d.ts +18 -13
  358. package/dist/core/tighten-task-spec.js +2 -1
  359. package/dist/core/tool-catalog-entries.d.ts +23 -0
  360. package/dist/core/tool-catalog-entries.js +14 -2
  361. package/dist/core/tool-check-reading.d.ts +11 -0
  362. package/dist/core/tool-check-reading.js +11 -6
  363. package/dist/core/tool-model-gate.d.ts +2 -2
  364. package/dist/core/tool-name-aliases.d.ts +48 -18
  365. package/dist/core/tool-name-aliases.js +36 -19
  366. package/dist/core/tool-name-readings.d.ts +6 -32
  367. package/dist/core/tool-name-readings.js +2 -9
  368. package/dist/core/tool-policy.d.ts +78 -204
  369. package/dist/core/tool-policy.js +152 -204
  370. package/dist/core/tool-result-store.js +3 -0
  371. package/dist/core/tool-roster.d.ts +14 -19
  372. package/dist/core/tool-roster.js +11 -44
  373. package/dist/core/tool-spec-members.js +7 -2
  374. package/dist/core/tool-spec.d.ts +19 -11
  375. package/dist/core/tools.js +49 -9
  376. package/dist/core/trace.d.ts +6 -3
  377. package/dist/core/trace.js +2 -1
  378. package/dist/core/types.d.ts +1 -1
  379. package/dist/core/untrusted-egress.d.ts +20 -0
  380. package/dist/core/untrusted-egress.js +77 -3
  381. package/dist/core/user-attachment.d.ts +8 -1
  382. package/dist/core/user-attachment.js +64 -4
  383. package/dist/core/wiring-manifest.d.ts +9 -0
  384. package/dist/core/wiring-manifest.js +1 -0
  385. package/dist/core/workflow-journal-store.js +1 -1
  386. package/dist/engine/compaction/compaction.js +3 -2
  387. package/dist/engine/execution-env/node-execution-env.d.ts +7 -3
  388. package/dist/engine/execution-env/node-execution-env.js +11 -2
  389. package/dist/engine/harness/agent-harness.d.ts +32 -6
  390. package/dist/engine/harness/agent-harness.js +65 -9
  391. package/dist/engine/harness/types.d.ts +29 -2
  392. package/dist/engine/llm/types.d.ts +28 -11
  393. package/dist/engine/loop/agent-loop.d.ts +23 -4
  394. package/dist/engine/loop/agent-loop.js +42 -30
  395. package/dist/engine/loop/types.d.ts +16 -6
  396. package/dist/engine/session/memory-repo.d.ts +9 -2
  397. package/dist/engine/session/memory-repo.js +11 -1
  398. package/dist/engine/session/repo-utils.d.ts +6 -5
  399. package/dist/engine/session/repo-utils.js +14 -6
  400. package/dist/index.d.ts +34 -17
  401. package/dist/index.js +22 -11
  402. package/dist/internal/harness-types.d.ts +1 -1
  403. package/dist/internal/harness.d.ts +2 -1
  404. package/dist/internal/harness.js +1 -0
  405. package/dist/internal/llm.d.ts +1 -1
  406. package/dist/orchestration/run-workflow-tool.d.ts +6 -4
  407. package/dist/orchestration/run-workflow-tool.js +5 -3
  408. package/dist/orchestration/workflow.d.ts +3 -0
  409. package/dist/orchestration/workflow.js +36 -18
  410. package/dist/primitives/credential-ref.d.ts +89 -0
  411. package/dist/primitives/credential-ref.js +125 -0
  412. package/dist/primitives/index.d.ts +2 -0
  413. package/dist/primitives/index.js +1 -0
  414. package/dist/prompt-assembly/artifact.d.ts +2 -2
  415. package/dist/prompt-assembly/artifact.js +5 -3
  416. package/dist/prompt-assembly/assemble.d.ts +3 -2
  417. package/dist/prompt-assembly/assemble.js +1 -1
  418. package/dist/prompt-assembly/catalog/schema.d.ts +43 -12
  419. package/dist/prompt-assembly/catalog/schema.js +34 -2
  420. package/dist/prompt-assembly/catalog/sections.js +0 -1
  421. package/dist/prompt-assembly/composer.d.ts +3 -1
  422. package/dist/prompt-assembly/composer.js +1 -1
  423. package/dist/prompt-assembly/event-registry.js +1 -0
  424. package/dist/prompt-assembly/overlay.js +3 -3
  425. package/dist/prompt-assembly/renderers.d.ts +1 -1
  426. package/dist/prompt-assembly/renderers.js +0 -3
  427. package/dist/prompt-assembly/role-base.d.ts +15 -0
  428. package/dist/prompt-assembly/role-base.js +9 -0
  429. package/dist/prompt-assembly/select.d.ts +39 -14
  430. package/dist/prompt-assembly/select.js +47 -16
  431. package/dist/prompt-assembly/sugar.d.ts +17 -11
  432. package/dist/prompt-assembly/sugar.js +8 -3
  433. package/dist/prompt-assembly/tool-catalog.d.ts +37 -3
  434. package/dist/prompt-assembly/tool-catalog.js +114 -4
  435. package/dist/prompt-assembly/turn-snapshot.d.ts +4 -10
  436. package/dist/prompt-assembly/turn-snapshot.js +0 -3
  437. package/dist/prompt-assembly/types.d.ts +0 -7
  438. package/dist/scenarios/full-body.d.ts +11 -11
  439. package/dist/scenarios/full-body.js +4 -3
  440. package/dist/shell/lex.js +10 -1
  441. package/dist/stores/file/adoption/adopt.js +4 -3
  442. package/dist/stores/file/adoption/marker.js +3 -2
  443. package/dist/stores/file/checkpoint-store.d.ts +21 -4
  444. package/dist/stores/file/checkpoint-store.js +38 -7
  445. package/dist/stores/file/file-history-store.js +18 -11
  446. package/dist/stores/file/index.js +2 -1
  447. package/dist/stores/file/mailbox-store.d.ts +2 -1
  448. package/dist/stores/file/mailbox-store.js +26 -1
  449. package/dist/stores/file/permission-rule-adopt.js +4 -3
  450. package/dist/stores/file/permission-rule-store.js +11 -5
  451. package/dist/stores/file/session-store.d.ts +29 -6
  452. package/dist/stores/file/session-store.js +42 -50
  453. package/dist/tools/artifact/artifact-tool.js +3 -2
  454. package/dist/tools/fs/bash-program-position.d.ts +19 -2
  455. package/dist/tools/fs/bash-program-position.js +56 -9
  456. package/dist/tools/fs/bash-readonly-classifier.d.ts +15 -19
  457. package/dist/tools/fs/bash-readonly-classifier.js +5 -10
  458. package/dist/tools/fs/fs-bash.js +15 -8
  459. package/dist/tools/fs/fs-glob.d.ts +86 -0
  460. package/dist/tools/fs/fs-glob.js +226 -0
  461. package/dist/tools/fs/fs-read.js +14 -14
  462. package/dist/tools/fs/fs-search-tools.js +7 -7
  463. package/dist/tools/fs/pattern-kill-guard.d.ts +23 -0
  464. package/dist/tools/fs/pattern-kill-guard.js +429 -0
  465. package/dist/tools/fs/pdf.d.ts +9 -6
  466. package/dist/tools/fs/pdf.js +3 -3
  467. package/dist/tools/fs/program-read-model.d.ts +57 -7
  468. package/dist/tools/fs/program-read-model.js +11 -1
  469. package/dist/tools/fs/program-read-model.rows.js +78 -21
  470. package/dist/tools/fs/read-deny-home.js +3 -2
  471. package/dist/tools/fs/removal-targets.d.ts +17 -7
  472. package/dist/tools/fs/removal-targets.js +47 -20
  473. package/dist/tools/fs/search.d.ts +10 -0
  474. package/dist/tools/fs/search.js +20 -26
  475. package/dist/tools/fs/shell-read-argv.js +89 -12
  476. package/dist/tools/fs/shell-read-bindings.d.ts +31 -0
  477. package/dist/tools/fs/shell-read-bindings.js +41 -0
  478. package/dist/tools/fs/shell-read-check.d.ts +10 -0
  479. package/dist/tools/fs/shell-read-check.js +13 -20
  480. package/dist/tools/fs/shell-read-environment.d.ts +5 -1
  481. package/dist/tools/fs/shell-read-environment.js +3 -2
  482. package/dist/tools/fs/shell-read-establish.d.ts +15 -0
  483. package/dist/tools/fs/shell-read-establish.js +19 -20
  484. package/dist/tools/fs/shell-read-identity.d.ts +12 -9
  485. package/dist/tools/fs/shell-read-identity.js +9 -4
  486. package/dist/tools/fs/shell-read-plan.js +24 -16
  487. package/dist/tools/fs/shell-read-start.d.ts +6 -1
  488. package/dist/tools/fs/shell-read-write-targets.d.ts +5 -1
  489. package/dist/tools/fs/shell-read-write-targets.js +2 -3
  490. package/dist/tools/fs/shell-reentry-text.d.ts +9 -0
  491. package/dist/tools/fs/shell-reentry-text.js +40 -2
  492. package/dist/tools/todo.js +63 -63
  493. package/dist/tools/web.d.ts +19 -14
  494. package/dist/tools/web.js +46 -61
  495. package/package.json +1 -1
  496. package/test/export-surface.snapshot.json +221 -7
  497. package/wire-changes/core-stores-sql@7.57.0.json +29 -0
  498. package/wire-changes/core@7.56.0.json +3891 -0
  499. package/wire-changes/core@7.57.0.json +1487 -0
  500. package/wire-changes/mods-kernel@7.56.0.json +303 -0
  501. package/wire-changes/mods-kernel@7.57.0.json +29 -0
  502. package/wire-changes/primitives@7.57.0.json +245 -0
@@ -1,3 +1,4 @@
1
+ import { attestationOf } from "./engine-attestation.js";
1
2
  import { isShellFaceToolName } from "./tool-registry.js";
2
3
  export const ASK_ORIGINS = Object.freeze(["content_question", "plan_review", "ancestor_marked", "org_unavailable", "org_rule", "rule_store_unavailable", "hook", "ask_rule", "denial_limit_fallback", "shell_gate_tighten", "safety_tighten", "policy"]);
3
4
  const ASK_ORIGIN_SET = new Set(ASK_ORIGINS);
@@ -15,8 +16,8 @@ const TIGHTEN_ONLY_ORIGINS = new Set(["shell_gate_tighten", "safety_tighten"]);
15
16
  export function stampAskOrigin(decision, facts, classification) {
16
17
  const origin = askOriginOf(decision, facts);
17
18
  const classed = askClassMembersOf(classification);
18
- const { mandate: _selfDeclared, ...unstamped } = decision;
19
- const clearance = ruleClearanceOf(unstamped, facts.mandateMarks);
19
+ const { mandate: _earlierStamp, ...unstamped } = decision;
20
+ const clearance = ruleClearanceOf(withFoldedOf(unstamped, attestationOf(decision, facts.call)), facts.mandateMarks);
20
21
  const mandated = { ...unstamped, ...(clearance.mandated ? { mandated: true } : {}), ...(clearance.mandate !== undefined ? { mandate: clearance.mandate } : {}), ...(facts.mandateMarks.requiresUserInteraction === true ? { requiresRealApproval: true } : {}) };
21
22
  if (mandated.probeReadRootCandidate === undefined || TIGHTEN_ONLY_ORIGINS.has(origin))
22
23
  return { ...mandated, origin, ...classed };
@@ -26,7 +27,7 @@ export function stampAskOrigin(decision, facts, classification) {
26
27
  export const RULE_OFFERS_ABSENCES = Object.freeze(["mandated", "allow_outranked", "ask_rule_matched", "lane_cannot_speak"]);
27
28
  export function ruleClearanceOf(ask, marks) {
28
29
  const marksWord = ask?.crossBoundaryMandated === true ? "cross_boundary_taint" : persistedRuleMandateOf({ ...marks, probeMandated: ask?.probeMandated === true });
29
- const foldedDoor = (ask?.foldedAskClasses ?? []).some((c) => !MODE_ARBITRATION[c].ruleMayClear);
30
+ const foldedDoor = (ask?.foldedClasses ?? []).some((c) => !MODE_ARBITRATION[c].ruleMayClear);
30
31
  const doorOutsideTable = ask?.requiresRealApproval === true || ask?.decisionReason === "hook" || ask?.decisionReason === "mode" || foldedDoor || ask?.authoredBy === "deployment" || ask?.inheritedUnresolved === true || ask?.ancestorResolved === true;
31
32
  const mandated = ask?.mandated === true || doorOutsideTable || marksWord !== undefined;
32
33
  const stampedWord = ask?.mandated === true && isPersistedRuleMandate(ask.mandate) ? ask.mandate : undefined;
@@ -52,6 +53,10 @@ export function ruleClearanceOf(ask, marks) {
52
53
  })();
53
54
  return { ...(word !== undefined ? { word } : {}), mandated, ...(mandate !== undefined ? { mandate } : {}) };
54
55
  }
56
+ export function withFoldedOf(facts, record) {
57
+ const folded = record?.foldedClasses;
58
+ return folded !== undefined && folded.length > 0 ? { ...facts, foldedClasses: [...folded] } : facts;
59
+ }
55
60
  export function askMandateMember(ask) {
56
61
  const { mandated, mandate } = ruleClearanceOf(ask, {});
57
62
  const authored = ask?.authoredBy === "deployment" ? { authoredBy: "deployment" } : {};
@@ -63,18 +68,17 @@ export function withProbeMandate(decision, account) {
63
68
  const { probeReason: _arrivedWith, ...rest } = decision;
64
69
  return { ...rest, probeMandated: true, ...(account !== undefined ? { probeReason: account } : {}) };
65
70
  }
66
- export function ownedClearanceFacts(d) {
67
- const { mandated, requiresRealApproval, decisionReason, matchedAskRule, probeMandated, crossBoundaryMandated, authoredBy, foldedAskClasses } = d;
68
- return {
71
+ export function ownedClearanceFacts(d, call) {
72
+ const { mandated, requiresRealApproval, decisionReason, matchedAskRule, probeMandated, crossBoundaryMandated, authoredBy } = d;
73
+ return withFoldedOf({
69
74
  ...(crossBoundaryMandated === true ? { crossBoundaryMandated } : {}),
70
75
  ...(mandated === true ? { mandated } : {}),
71
- ...(Array.isArray(foldedAskClasses) && foldedAskClasses.length > 0 ? { foldedAskClasses: [...foldedAskClasses] } : {}),
72
76
  ...(authoredBy === "deployment" ? { authoredBy } : {}),
73
77
  ...(requiresRealApproval === true ? { requiresRealApproval } : {}),
74
78
  ...(decisionReason !== undefined ? { decisionReason } : {}),
75
79
  ...(typeof matchedAskRule === "string" ? { matchedAskRule } : {}),
76
80
  ...(probeMandated === true ? { probeMandated } : {}),
77
- };
81
+ }, attestationOf(d, call));
78
82
  }
79
83
  function originLadder(decision, facts) {
80
84
  if (facts.contentQuestion)
@@ -282,9 +286,9 @@ export function screenAskClassMembers(askClass, classes) {
282
286
  return undefined;
283
287
  return { askClass, classes: Object.freeze(ordered) };
284
288
  }
285
- export function decisionAskClassesOf(d) {
289
+ export function ownAskClassesOf(d, record) {
286
290
  const out = new Set();
287
- for (const guard of d.guards ?? [])
291
+ for (const guard of record?.guards ?? [])
288
292
  out.add(guard);
289
293
  if (d.ruleUnreadable !== undefined)
290
294
  out.add("rule_unreadable");
@@ -308,7 +312,12 @@ export function decisionAskClassesOf(d) {
308
312
  out.add("policy_rra");
309
313
  if (out.size === 0 && d.mandated === true)
310
314
  out.add("operator_forced");
311
- for (const c of d.foldedAskClasses ?? [])
315
+ return out;
316
+ }
317
+ export function decisionAskClassesOf(d, call) {
318
+ const record = attestationOf(d, call);
319
+ const out = ownAskClassesOf(d, record);
320
+ for (const c of record?.foldedClasses ?? [])
312
321
  out.add(c);
313
322
  return out;
314
323
  }
@@ -328,7 +337,8 @@ export function foldArbitrationRow(classes, readFace, askFace) {
328
337
  return { bypassImmune, classifierEligible, sandboxAdmission, ruleMayClear, hookAskFloor };
329
338
  }
330
339
  export function classifyAsk(d, facts) {
331
- const classes = decisionAskClassesOf({ ...d, foldedAskClasses: undefined });
340
+ const record = attestationOf(d, facts.call);
341
+ const classes = ownAskClassesOf(d, record);
332
342
  classes.delete("policy_rra");
333
343
  if (facts.contentQuestion)
334
344
  classes.add("content_question");
@@ -365,7 +375,7 @@ export function classifyAsk(d, facts) {
365
375
  classes.add(c);
366
376
  if (d.requiresRealApproval === true && ![...classes].some((c) => RRA_EXPLAINERS.has(c)))
367
377
  classes.add("policy_rra");
368
- for (const c of d.foldedAskClasses ?? [])
378
+ for (const c of record?.foldedClasses ?? [])
369
379
  classes.add(c);
370
380
  if (classes.size === 0 && d.mandated === true)
371
381
  classes.add("operator_forced");
@@ -379,15 +389,45 @@ export function headlessDenialMessage(toolName, askMessage) {
379
389
  }
380
390
  const REFUSED_CAPABILITY_GUIDANCE = "IMPORTANT: you may try to accomplish this with other tools that would naturally be used for it (for example `head` instead of `cat`), but do not work around this denial in malicious ways — for example, do not use your ability to run tests to run non-test actions; only work around it in reasonable ways that keep to the intent behind it. If you believe this capability is essential to complete the user's request, STOP and explain to the user what you were trying to do and why you need this permission, and let the user decide how to proceed.";
381
391
  export function dontAskRefusalMessage(input) {
382
- const remedy = headlessApprovalRemedy({ mode: "dontAsk", classification: input.classification, coveredWrite: input.coveredWrite, ruleShape: input.ruleShape });
392
+ const remedy = headlessApprovalRemedy({ mode: "dontAsk", classification: input.classification, coveredWrite: input.coveredWrite, ruleShape: input.ruleShape }).sentence;
383
393
  return `Permission to use ${input.toolName} has been denied because this run is in the dontAsk permission mode (this call needed approval: ${input.classification.askClass}). ${REFUSED_CAPABILITY_GUIDANCE} To let a call like this run: ${remedy}.`;
384
394
  }
395
+ export const APPROVAL_REMEDY_KINDS = Object.freeze(["approver", "permission_mode"]);
396
+ const APPROVAL_REMEDY_KIND_SET = new Set(APPROVAL_REMEDY_KINDS);
397
+ export function isApprovalRemedyKind(v) {
398
+ return APPROVAL_REMEDY_KIND_SET.has(v);
399
+ }
400
+ export function readApprovalRemedy(v) {
401
+ if (typeof v !== "object" || v === null || Array.isArray(v))
402
+ return undefined;
403
+ const keys = Object.keys(v);
404
+ const field = (k) => (keys.includes(k) ? v[k] : undefined);
405
+ const kind = field("kind");
406
+ if (!isApprovalRemedyKind(kind))
407
+ return undefined;
408
+ switch (kind) {
409
+ case "approver":
410
+ return keys.length === 1 ? { kind } : undefined;
411
+ case "permission_mode": {
412
+ const value = field("value");
413
+ const disclosedOn = field("disclosedOn");
414
+ return keys.length === 3 && value === "bypassPermissions" && disclosedOn === "gate.disposition.released" ? { kind, value, disclosedOn } : undefined;
415
+ }
416
+ default: {
417
+ const _exhaustive = kind;
418
+ return _exhaustive;
419
+ }
420
+ }
421
+ }
422
+ const APPROVER_REMEDY = Object.freeze({ kind: "approver" });
423
+ const RELEASE_REMEDY = Object.freeze({ kind: "permission_mode", value: "bypassPermissions", disclosedOn: "gate.disposition.released" });
385
424
  export function headlessApprovalRemedy(input) {
425
+ const way = (sentence, release = false) => ({ sentence, remedies: Object.freeze(release ? [APPROVER_REMEDY, RELEASE_REMEDY] : [APPROVER_REMEDY]) });
386
426
  if (input.mode === "dontAsk") {
387
427
  const c = input.classification;
388
- return c?.row.ruleMayClear === true
428
+ return way(c?.row.ruleMayClear === true
389
429
  ? `an allow rule covering this call answers it under dontAsk — add one${input.ruleShape !== undefined ? ` in this tool's rule shape (\`${input.ruleShape}\`)` : ""} to the allow rules (a settings file's \`permissions.allow\`, or the request's or the deployment's allow list), or run under a mode with an approver`
390
- : `no allow rule answers this ask${c !== undefined ? ` (${c.askClass})` : ""} — only a person can: run under a mode with an approver, or change the call`;
430
+ : `no allow rule answers this ask${c !== undefined ? ` (${c.askClass})` : ""} — only a person can: run under a mode with an approver, or change the call`);
391
431
  }
392
432
  const approver = input.approverSeat === "unavailable"
393
433
  ? "make a person reachable through the approver that is wired (it answered `unavailable` for this ask)"
@@ -396,21 +436,21 @@ export function headlessApprovalRemedy(input) {
396
436
  : "wire an approver (`onAsk`) to put it to a person";
397
437
  const c = input.classification;
398
438
  if (input.mode === "acceptEdits" && input.unplacedOptions !== undefined && (c === undefined || (c.classes.size === 1 && c.classes.has("ordinary"))))
399
- return `${fileCommandOptionsSentence(input.unplacedOptions.program)} Spell the ${input.unplacedOptions.program} without option words for the mode to answer it, or ${approver}`;
439
+ return way(`${fileCommandOptionsSentence(input.unplacedOptions.program)} Spell the ${input.unplacedOptions.program} without option words for the mode to answer it, or ${approver}`);
400
440
  if (c !== undefined && bypassImmuneOf(c))
401
- return `no permission mode releases this ask (${c.askClass}): ${approver}, or change the call`;
441
+ return way(`no permission mode releases this ask (${c.askClass}): ${approver}, or change the call`);
402
442
  if (input.mode === "plan" && c?.classes.has("mode") === true)
403
- return `the plan permission mode asks before every write and every call to a tool the engine does not define that is not read-only — leave plan mode (\`setPermissionMode\` to another mode, or approve the plan) to run it, or ${approver}`;
443
+ return way(`the plan permission mode asks before every write and every call to a tool the engine does not define that is not read-only — leave plan mode (\`setPermissionMode\` to another mode, or approve the plan) to run it, or ${approver}`);
404
444
  if (c !== undefined && c.classes.size === 1 && c.classes.has("unstated"))
405
- return `no allow entry, stored allow rule or hook granted this tool, and it states no permission of its own — grant it with an allow entry for its name (\`RunnerDeps.allowedTools\` / \`TaskSpec.allowedTools\`), run with \`permissionMode: "bypassPermissions"\`, or ${approver}`;
445
+ return way(`no allow entry, stored allow rule or hook granted this tool, and it states no permission of its own — grant it with an allow entry for its name (\`RunnerDeps.allowedTools\` / \`TaskSpec.allowedTools\`), or ${approver}`, true);
406
446
  const onlyOrdinary = c === undefined || (c.classes.size === 1 && c.classes.has("ordinary"));
407
447
  if (input.coveredWrite && onlyOrdinary) {
408
448
  if (input.mode === "acceptEdits")
409
- return `under \`permissionMode: "acceptEdits"\` the mode asks only for a write outside the working directories — if this target is outside them, add its directory to \`additionalDirectories\`; otherwise (or besides) ${approver}`;
449
+ return way(`under \`permissionMode: "acceptEdits"\` the mode asks only for a write outside the working directories — if this target is outside them, add its directory to \`additionalDirectories\`; otherwise (or besides) ${approver}`);
410
450
  if (input.mode === undefined || input.mode === "default" || input.mode === "auto")
411
- return `the mode's write gate asks every write under \`default\`: \`permissionMode: "acceptEdits"\` lets writes inside the working directories (the task root and \`additionalDirectories\`) through without asking (a question another policy raised still stands), or ${approver}`;
451
+ return way(`the mode's write gate asks every write under \`default\`: \`permissionMode: "acceptEdits"\` lets writes inside the working directories (the task root and \`additionalDirectories\`) through without asking (a question another policy raised still stands), or ${approver}`);
412
452
  }
413
- return `run with \`permissionMode: "bypassPermissions"\` to release this ask (the release is disclosed on the call), or ${approver}`;
453
+ return way(approver, true);
414
454
  }
415
455
  export function fileCommandOptionsSentence(program) {
416
456
  return `${program} with flags requires manual approval to ensure path safety: the mode cannot automatically validate ${program} commands that use flags, as some flags like --target-directory=PATH can bypass path validation.`;
@@ -3,15 +3,23 @@ import type { ToolPolicy } from "./tool-policy.js";
3
3
  /** The reserved tool name for AskUserQuestion — shared so the durable-resume path (runtask) can recognize it
4
4
  * as a content-ask whose SHOWN questions must not be rewritten by an operator `updatedInput` (design/80 D-F).
5
5
  *
6
- * RESERVED means the whole engine keys content-ask semantics on this name: a policy `ask` on it is NEVER
7
- * routed to a synchronous PERMISSION approver — on the main gate, the degraded fall-through, and the
8
- * inherited ancestor wrappers alike (a permission frame's allow/deny cannot carry an ANSWER; CC parity:
9
- * AskUserQuestion never raises a permission card). What it DOES reach, in this order, is the run's own
10
- * content-ask channel: a LIVE question face answers it in-stream (the gate routes the question, not a
11
- * verdict), and only with no live face — or with the durable gate forced — does it park durably or answer
12
- * the typed refusal. Permission-GATING this tool stays unsupported by design; content-ROUTING it is the
13
- * supported path. A caller-supplied tool reusing this name inherits the same routing; don't. */
6
+ * The engine mounts its own question tool under this name, and the gate's content-ask semantics belong to THAT tool,
7
+ * read off the call's face ({@link isEngineQuestionFace}), never off this name: a policy `ask` on it is NEVER routed to
8
+ * a synchronous PERMISSION approver (a permission frame's allow/deny cannot carry an ANSWER; CC parity: AskUserQuestion
9
+ * never raises a permission card). What it DOES reach, in this order, is the run's own content-ask channel: a LIVE
10
+ * question face answers it in-stream (the gate routes the question, not a verdict), and only with no live face — or
11
+ * with the durable gate forced — does it park durably or answer the typed refusal. Permission-GATING this tool stays
12
+ * unsupported by design; content-ROUTING it is the supported path. A caller-supplied tool reusing this name is an
13
+ * ordinary caller tool to the gate, its park decline, an ancestor's settlement and a person's edit of its parked call — asked, cleared by an allow rule,
14
+ * released by a mode or refused like any other; the approval card a call carries is still chosen by this name. */
14
15
  export declare const ASK_USER_QUESTION_TOOL_NAME = "AskUserQuestion";
16
+ /** "Is this call the engine's own question tool?" — the catalog's one mount judge ({@link engineMountedAs}) for the
17
+ * question definition: every station that treats a call as a content ask (the gate's content-question class and route,
18
+ * the park's sync-first decline, the ancestor adapters' question float, {@link createDurableQuestionPolicy}) reads this answer. */
19
+ export declare const isEngineQuestionFace: (face: {
20
+ readonly engineMounted?: true;
21
+ readonly contractId: string;
22
+ } | undefined) => boolean;
15
23
  /**
16
24
  * AskUserQuestion (design/64 §5). A model-callable tool that lets the agent ask the USER a structured
17
25
  * multiple-choice question (which approach? which of these?) — distinct from the design/37 permission `ask`
@@ -278,6 +286,41 @@ export interface AskUserQuestionToolOptions {
278
286
  * would let a LATER question inherit the claim that an operator approved it. */
279
287
  redeemedApprovalQuestionsHash?: string;
280
288
  }
289
+ /**
290
+ * Durable ask (design/64 TC-5.4 — ABOVE CC, the disconnected-human case): instead of the headless
291
+ * "proceed with your best judgment" default, an AskUserQuestion **suspends the task durably** and the
292
+ * answer resumes it — built ENTIRELY from existing primitives, no new gate kind.
293
+ *
294
+ * **The park is the fallback, not the mandate.** An adjudicated question parks durably UNLESS this run
295
+ * has a live question face (see {@link isLiveQuestionFace}), in which case the engine routes the question
296
+ * to that face and the answer arrives in-stream — same turn, no checkpoint, no rebuild. The park is what
297
+ * happens when nobody is there: no live face, the face affirming nobody is reachable, or a control-plane
298
+ * `forceDurableGate` that mandates the durable breakpoint regardless. A deployment that wired a live face
299
+ * AND wants every question parked anyway states that with `forceDurableGate` (or by not wiring the face).
300
+ *
301
+ * 1. Run the task with `durableApproval` + a durable `CheckpointStore` (+ durable session/offload
302
+ * stores) and `combinePolicies(createDurableQuestionPolicy(), yourPolicy)`. The policy adjudicates
303
+ * the AskUserQuestion call `ask`; in durable mode that suspends BEFORE the tool executes —
304
+ * `onQuestion` is never called on the suspend side, so mount the tool with
305
+ * {@link QUESTION_AWAITS_RESUME} when no live human is connected.
306
+ * 2. The HITL surface reads the questions from `checkpoint.pendingAction.args.questions` and collects
307
+ * the human's {@link QuestionAnswer} out-of-band (hours/days later, any replica).
308
+ * 3. `runner.resume(token, { gate: "policy_ask", decision: "allow", boundCallId:
309
+ * checkpoint.pendingAction.toolCallId }, { ...taskConfig, onQuestion: async () => answer })` — the resume
310
+ * re-mounts the tool with the answer closure; the pending call executes against it and the model
311
+ * continues with "The user answered: …". `boundCallId` (design/80 D-1) must name the pending call the
312
+ * human answered, or the resume is rejected (`checkpoint.invalid_outcome`).
313
+ *
314
+ * A deployment that wants the CC-style threshold form ("wait N minutes for a live human, then go
315
+ * durable") implements it inside its own policy: return `allow` while a human is connected (the live
316
+ * `onQuestion` answers synchronously) and `ask` when none is — the sync-vs-durable choice is exactly
317
+ * one policy decision. Composing this policy's answer is how such a policy keeps the one judge (an `ask`
318
+ * from here means the call is the engine's question tool).
319
+ *
320
+ * The call it asks about is the ENGINE's question tool, read off the request's face ({@link isEngineQuestionFace}):
321
+ * a caller's tool that took the name is not asked about here, and neither is a bare request (no face — a host
322
+ * driving a policy outside a Runner stamps the face itself, `toolCallFaceOf(roster, name)`).
323
+ */
281
324
  export declare function createDurableQuestionPolicy(): ToolPolicy;
282
325
  /**
283
326
  * Placeholder {@link OnQuestion} that mounts the AskUserQuestion tool on a worker with NO live human
@@ -3,10 +3,10 @@ import { uuidv7 } from "../engine/session/uuid.js";
3
3
  import { boundInputHashOf, capturedJsonOf } from "./canonical-json.js";
4
4
  import { defineTool, errorResult } from "./tools.js";
5
5
  import { delimitUntrusted, inlineUntrusted } from "./untrusted-text.js";
6
- import { mountRuleFace, toolFace } from "./tool-catalog-entries.js";
6
+ import { engineMountedAs, mountRuleFace, toolFace } from "./tool-catalog-entries.js";
7
7
  import { thrownText } from "./thrown-value.js";
8
- import { heldBy } from "./tool-name-readings.js";
9
8
  export const ASK_USER_QUESTION_TOOL_NAME = "AskUserQuestion";
9
+ export const isEngineQuestionFace = engineMountedAs(["ask-user-question"]);
10
10
  export function classifyQuestionOutcome(outcome) {
11
11
  let unavailable;
12
12
  let answers;
@@ -69,11 +69,10 @@ export function validateAskQuestions(questions) {
69
69
  }
70
70
  return undefined;
71
71
  }
72
- const QUESTION_TOOL_NAMES = new Set([ASK_USER_QUESTION_TOOL_NAME]);
73
72
  export function createDurableQuestionPolicy() {
74
73
  return {
75
74
  check(req) {
76
- if (!heldBy("policy.durableQuestion", QUESTION_TOOL_NAMES, req)) {
75
+ if (!isEngineQuestionFace(req.face)) {
77
76
  return { action: "allow" };
78
77
  }
79
78
  return { action: "ask", message: "AskUserQuestion: awaiting a human answer (durable)" };
@@ -28,7 +28,7 @@
28
28
  * is pure.
29
29
  */
30
30
  import type { EngineNotice } from "./engine-notice.js";
31
- import type { AssertAllKeysHandled, HeadlessApproverSeat } from "./ask-origin.js";
31
+ import { type ApprovalRemedy, type AssertAllKeysHandled, type HeadlessApproverSeat } from "./ask-origin.js";
32
32
  /** WHY the ask could not be resolved — the closed set (see the module note for each word). */
33
33
  export declare const ASK_UNRESOLVABLE_CAUSES: readonly ["approver_unavailable", "no_approver_wired", "mandate_unreconstructible"];
34
34
  export type AskUnresolvableCause = (typeof ASK_UNRESOLVABLE_CAUSES)[number];
@@ -52,6 +52,10 @@ export interface AskUnresolvableFacts {
52
52
  * for arguments no approval can be bound to, the binding's own sentence, which is that text — the remedy's approver half would
53
53
  * not let them run) — carried verbatim, never re-composed here. */
54
54
  readonly remedy?: string;
55
+ /** The ways out of that same refusal as data ({@link ApprovalRemedy}) — the approver, and the permission mode where the refusal could be
56
+ * released by one — for a host that chooses which to offer. Rides exactly when {@link remedy} is the headless remedy's sentence
57
+ * (`headlessApprovalRemedy`); a binding's own sentence, which has no way out to offer, carries none. */
58
+ readonly remedies?: readonly ApprovalRemedy[];
55
59
  }
56
60
  /**
57
61
  * Which causes take the caller-side remedy (`headlessApprovalRemedy`, ask-origin.ts), and in which seat's clause — the table IS
@@ -82,8 +86,9 @@ export declare function askUnresolvableRemedySeat(cause: AskUnresolvableCause):
82
86
  * an empty session or tool name, or a cause outside the closed set, is refused at the mint with a
83
87
  * `TypeError` rather than shaped into a notice that would route nowhere or say nothing.
84
88
  *
85
- * `detail: { sessionId, toolName, toolCallId, cause, parkLaneExisted, remedy? }` — `remedy` rides the causes that say nobody
86
- * could be asked ({@link askUnresolvableRemedySeat}: the sentence the refusal's tool text carries); `sessionId` is lifted onto the typed key by {@link import("./engine-notice.js").deliverEngineNotice}, the one throat.
89
+ * `detail: { sessionId, toolName, toolCallId, cause, parkLaneExisted, remedy?, remedies? }` — `remedy` rides the causes that say nobody
90
+ * could be asked ({@link askUnresolvableRemedySeat}: the sentence the refusal's tool text carries) and `remedies` beside it, the same
91
+ * way out as data ({@link ApprovalRemedy}); `sessionId` is lifted onto the typed key by {@link import("./engine-notice.js").deliverEngineNotice}, the one throat.
87
92
  */
88
93
  export declare function askUnresolvableNotice(facts: AskUnresolvableFacts): EngineNotice;
89
94
  export {};
@@ -1,3 +1,4 @@
1
+ import { APPROVAL_REMEDY_KINDS, readApprovalRemedy } from "./ask-origin.js";
1
2
  export const ASK_UNRESOLVABLE_CAUSES = Object.freeze(["approver_unavailable", "no_approver_wired", "mandate_unreconstructible"]);
2
3
  Object.freeze(ASK_UNRESOLVABLE_CAUSES);
3
4
  const ASK_UNRESOLVABLE_CAUSE_SET = new Set(ASK_UNRESOLVABLE_CAUSES);
@@ -18,7 +19,7 @@ export function askUnresolvableRemedySeat(cause) {
18
19
  return CAUSE_REMEDY_SEAT[cause];
19
20
  }
20
21
  export function askUnresolvableNotice(facts) {
21
- const { sessionId, toolName, toolCallId, cause, parkLaneExisted, remedy } = facts;
22
+ const { sessionId, toolName, toolCallId, cause, parkLaneExisted, remedy, remedies } = facts;
22
23
  if (typeof sessionId !== "string" || sessionId.length === 0) {
23
24
  throw new TypeError("delegation.ask_unresolvable: sessionId is required — a user-audience notice with no session routes nowhere");
24
25
  }
@@ -31,12 +32,25 @@ export function askUnresolvableNotice(facts) {
31
32
  if (!isAskUnresolvableCause(cause)) {
32
33
  throw new TypeError(`delegation.ask_unresolvable: cause ${JSON.stringify(cause)} is not one of ${ASK_UNRESOLVABLE_CAUSES.join("/")}`);
33
34
  }
35
+ let remedyList;
36
+ if (remedies !== undefined) {
37
+ if (typeof remedy !== "string" || remedy.length === 0 || !Array.isArray(remedies) || remedies.length === 0) {
38
+ throw new TypeError("delegation.ask_unresolvable: remedies are a non-empty list of ways out riding beside the remedy sentence they restate");
39
+ }
40
+ remedyList = [];
41
+ for (let i = 0; i < remedies.length; i++) {
42
+ const read = Object.hasOwn(remedies, i) ? readApprovalRemedy(remedies[i]) : undefined;
43
+ if (read === undefined)
44
+ throw new TypeError(`delegation.ask_unresolvable: remedies[${i}] is not one way out of the closed set (${APPROVAL_REMEDY_KINDS.join("/")}) with exactly its own fields`);
45
+ remedyList.push(read);
46
+ }
47
+ }
34
48
  const park = parkLaneExisted ? "the durable approval park did not take it" : "no durable approval park is armed for this run";
35
49
  return {
36
50
  code: "delegation.ask_unresolvable",
37
51
  message: `approval for "${toolName}" could not be resolved: ${CAUSE_CLAUSE[cause]} and ${park} — ` +
38
52
  `the call was denied fail-closed and did not run. ${typeof remedy === "string" && remedy.length > 0 ? `To let it run: ${remedy}. ` : ""}To let such approvals wait for a person, run with a checkpoint store and a ` +
39
53
  `durable approval opt-in (or a live approver reachable for delegated children).`,
40
- detail: { sessionId, toolName, toolCallId, cause, parkLaneExisted: parkLaneExisted === true, ...(typeof remedy === "string" && remedy.length > 0 ? { remedy } : {}) },
54
+ detail: { sessionId, toolName, toolCallId, cause, parkLaneExisted: parkLaneExisted === true, ...(typeof remedy === "string" && remedy.length > 0 ? { remedy } : {}), ...(remedyList !== undefined ? { remedies: remedyList } : {}) },
41
55
  };
42
56
  }
@@ -3,8 +3,8 @@ import { type Message, type Model, type Tool } from "../internal/llm.js";
3
3
  import type { ContextWindowOverlay } from "./context-settings.js";
4
4
  import type { PostCompactContext, PreCompactContext, PreCompactResult } from "./hooks.js";
5
5
  import type { TraceEvent } from "./trace.js";
6
- import type { Brain } from "./types.js";
7
- import type { TaskEvent, TaskEventIdentity } from "./task-event.js";
6
+ import type { Brain, ModelRef, TaskSpec } from "./types.js";
7
+ import type { CompactOutcome, TaskEvent, TaskEventIdentity } from "./task-event.js";
8
8
  import type { CompactionEffect } from "./frame-settlement.js";
9
9
  import type { MintedAttachmentFrame } from "./user-attachment.js";
10
10
  /**
@@ -39,13 +39,18 @@ export type CompactionPhaseDurations = Omit<Extract<TraceEvent, {
39
39
  kind: "compaction.phase_timings";
40
40
  }>, "kind" | "version" | "taskId" | "ts" | "durationMs">;
41
41
  /** True iff `err` is a compaction failure caused by a manual compact() caller WITHDRAWING its
42
- * request — see {@link MaybeCompactOptions.manualCancelSignal}. Two mint sites since the
43
- * design/374 slice-3 commit-boundary re-check (C16): the summary call's own abort outcome, and
44
- * the pre-persist "cancelled before commit" throw (a brain that ignored the abort finished the
45
- * summary, but the withdrawal still fired before anything landed). Absence of the marker means
42
+ * request — see {@link MaybeCompactOptions.manualCancelSignal}. Minted at every cut point of the
43
+ * pass: before the pass commits, while the summary provider or the credential callback is
44
+ * answering ({@link untilPassCut}), the summary call's own abort outcome, and the pre-persist
45
+ * "cancelled before commit" throw (design/374 slice-3, C16: a brain that ignored the abort finished
46
+ * the summary, but the withdrawal still fired before anything landed). Absence of the marker means
46
47
  * the failure was NOT the withdrawal: a real summarizer error racing a late cancel stays
47
48
  * unmarked so the caller's breaker/onError accounting still sees it. */
48
49
  export declare function isCompactionManualCancel(err: unknown): boolean;
50
+ /** The ONE reason a failed compaction pass reports, read by every lane that accounts for one (the turn boundary, the end-of-task pass,
51
+ * the prompt-too-long recovery) for its trace frame and its `compaction_outcome{failed}` event: the thrown value's words through the
52
+ * same-principal tier, THEN bounded — minted before the cut, so the cut can leave no part of a value. */
53
+ export declare function compactionFailureReason(err: unknown): string;
49
54
  /**
50
55
  * design/145 §1/§3 — the window-safety decision surfaced to the caller BEFORE the summary call
51
56
  * (same pre-call posture as `onInputTruncated`: the disclosure must survive a later summary
@@ -734,6 +739,66 @@ export interface CompactedFrameSource {
734
739
  export declare function mintCompactedEvent(comp: CompactedFrameSource, trigger: "auto" | "manual" | "forced", identity: TaskEventIdentity): Extract<TaskEvent, {
735
740
  type: "compacted";
736
741
  }>;
742
+ /** `Runner.compactSession`'s request — the out-of-run manual compaction of a session no leg of the Runner holds. A plain
743
+ * data object; the keys are a closed set. */
744
+ export interface CompactSessionRequest {
745
+ /** The session to compact. It must exist. */
746
+ sessionId: string;
747
+ /** The model the session's next turn runs on — its window bounds the pass (resolved like `TaskSpec.model`). */
748
+ model: ModelRef;
749
+ /** This pass's summarization instructions: they REPLACE `compaction.instructions` and the default for this pass (the
750
+ * `TaskStream.compact` reading); sanitized and capped like every instructions channel. */
751
+ instructions?: string;
752
+ /** The members of `TaskSpec.compaction` a pass reads, as a run would carry them. */
753
+ compaction?: Pick<NonNullable<TaskSpec["compaction"]>, "enabled" | "reserveTokens" | "keepRecentTokens" | "instructions" | "clampTolerance">;
754
+ /** The independent summary model (`TaskSpec.compactionModel`); absent ⇒ the deployment's `summarize` role (or its tier
755
+ * default), else the main model. A role-derived model whose key↔URL pairing is broken falls back to the main model,
756
+ * announced, as on a run. */
757
+ compactionModel?: ModelRef;
758
+ /** Per-model credentials (`TaskSpec.getApiKeyAndHeaders`). */
759
+ getApiKeyAndHeaders?: TaskSpec["getApiKeyAndHeaders"];
760
+ /** Withdraws the pass: aborted before the session's lock is taken, the answer is `"mooted"` with nothing done; while the pass
761
+ * runs the summary call and the credential wait read it (store reads and appends, and the pre-flight's own 5 s timer, do not); a pass that already persisted is not undone. */
762
+ signal?: AbortSignal;
763
+ }
764
+ /** `Runner.compactSession`'s answer. */
765
+ export interface CompactSessionResult {
766
+ /** What the pass did — the closed set `TaskStream.compact` resolves with. */
767
+ outcome: CompactOutcome;
768
+ /**
769
+ * The pass's frames, in order, each with its own `eventId` and no task attribution: `compaction_started` once the
770
+ * pass committed, then the frame that ends it — `compacted` (`trigger: "manual"`) on a landing, else
771
+ * `compaction_outcome` (`trigger: "manual"`). Empty when the pass never ran (a withdrawn request). Returned, not
772
+ * streamed: a `compaction_started` here is a record of the pass, not a live progress signal.
773
+ */
774
+ events: Array<Extract<TaskEvent, {
775
+ type: "compaction_started" | "compacted" | "compaction_outcome";
776
+ }>>;
777
+ /** The model calls the pass made (the summary, a hook's `$.model.complete`), priced as a run's side calls are; absent
778
+ * when none was made. `usageMissing` ⇒ a reply reported no usage (a lower bound); `unpriced` ⇒ a call ran on a model
779
+ * the deployment could not price. */
780
+ usage?: {
781
+ tokens: number;
782
+ totalInputTokens: number;
783
+ promptTokens: number;
784
+ cachedTokens: number;
785
+ cacheWriteTokens: number;
786
+ outputTokens: number;
787
+ costMicroUsd: number;
788
+ usageMissing?: true;
789
+ unpriced?: true;
790
+ };
791
+ }
792
+ /**
793
+ * The MANUAL outcome of a pass that returned (did not throw) — the one reading for every manual pass: the turn
794
+ * boundary serving a `TaskStream.compact` request and the out-of-run `Runner.compactSession`. A manual pass forces
795
+ * (`force` + `minTokens: 0`), so the floor's `suppressedByFloor` cannot occur and is not a case here.
796
+ */
797
+ export declare function manualCompactOutcomeOf(comp: {
798
+ compacted: boolean;
799
+ blocked?: boolean;
800
+ disabled?: boolean;
801
+ }): CompactOutcome;
737
802
  /**
738
803
  * THE mint of the `compaction_started` wire frame — the opening half of the pair whose closing half is the
739
804
  * `compacted` frame above (or a `compaction_outcome` that carries the same `pass`). One function, three
@@ -8,6 +8,7 @@ import { brainToRuntime } from "./runtime.js";
8
8
  import { defuseFenceMarkers, sanitizeUntrustedText } from "./untrusted-text.js";
9
9
  import { createSafeNotifier, observeThenableRejection } from "./safe-notify.js";
10
10
  import { thrownText } from "./thrown-value.js";
11
+ import { egressThrownText } from "./untrusted-egress.js";
11
12
  export const DEFAULT_COMPACTION_INSTRUCTIONS = "Preserve verbatim every code, identifier, name, number, file path, error message, credential " +
12
13
  "reference, and explicit user instruction or decision mentioned anywhere in the conversation. " +
13
14
  "When in doubt, keep the specific detail rather than generalizing it.";
@@ -21,9 +22,33 @@ export function sanitizeCompactionInstructions(text) {
21
22
  : defused;
22
23
  }
23
24
  const COMPACTION_MANUAL_CANCEL_FLAG = "semaCompactionManualCancel";
25
+ const PASS_CUT = Symbol("compaction-pass-cut");
26
+ async function untilPassCut(start, signal) {
27
+ if (signal?.aborted === true)
28
+ return PASS_CUT;
29
+ if (signal === undefined)
30
+ return await start();
31
+ let release = () => undefined;
32
+ const cut = new Promise((resolve) => {
33
+ const onAbort = () => resolve(PASS_CUT);
34
+ signal.addEventListener("abort", onAbort, { once: true });
35
+ release = () => signal.removeEventListener("abort", onAbort);
36
+ });
37
+ try {
38
+ return await Promise.race([Promise.resolve(start()), cut]);
39
+ }
40
+ finally {
41
+ release();
42
+ }
43
+ }
24
44
  export function isCompactionManualCancel(err) {
25
45
  return (typeof err === "object" && err !== null && err[COMPACTION_MANUAL_CANCEL_FLAG] === true);
26
46
  }
47
+ const COMPACTION_FAILURE_REASON_MAX = 512;
48
+ export function compactionFailureReason(err) {
49
+ const words = egressThrownText("same-principal", err);
50
+ return words.length > COMPACTION_FAILURE_REASON_MAX ? `${words.slice(0, COMPACTION_FAILURE_REASON_MAX)}…` : words;
51
+ }
27
52
  function summarizationCharsCapacity(model) {
28
53
  return model.contextWindow > 0
29
54
  ? model.contextWindow * (model.charsPerToken ?? DEFAULT_CHARS_PER_TOKEN)
@@ -161,29 +186,15 @@ export async function maybeCompact(opts) {
161
186
  let providerSummary;
162
187
  if (opts.summaryProvider && !forceRealSummary && !prep.value.isSplitTurn) {
163
188
  const providerModifiedFiles = computeFileLists(prep.value.fileOps).modifiedFilesByRecency;
164
- const signal = opts.signal;
165
- const cut = Symbol("cut");
166
- let release = () => undefined;
167
- const cutByAbort = new Promise((resolve) => {
168
- if (signal === undefined || signal.aborted)
169
- return;
170
- const onAbort = () => resolve(cut);
171
- signal.addEventListener("abort", onAbort, { once: true });
172
- release = () => signal.removeEventListener("abort", onAbort);
173
- });
189
+ const summaryProvider = opts.summaryProvider;
190
+ const boundary = prep.value;
174
191
  let consulted;
175
192
  try {
176
- consulted =
177
- signal?.aborted === true
178
- ? cut
179
- : await Promise.race([
180
- Promise.resolve(opts.summaryProvider({
181
- messagesToSummarize: prep.value.messagesToSummarize,
182
- previousSummary: prep.value.previousSummary,
183
- modifiedFiles: providerModifiedFiles,
184
- })),
185
- cutByAbort,
186
- ]);
193
+ consulted = await untilPassCut(() => summaryProvider({
194
+ messagesToSummarize: boundary.messagesToSummarize,
195
+ previousSummary: boundary.previousSummary,
196
+ modifiedFiles: providerModifiedFiles,
197
+ }), opts.signal);
187
198
  const trimmed = typeof consulted === "string" ? consulted.trim() : "";
188
199
  if (trimmed) {
189
200
  providerSummary = trimmed;
@@ -191,10 +202,7 @@ export async function maybeCompact(opts) {
191
202
  }
192
203
  catch {
193
204
  }
194
- finally {
195
- release();
196
- }
197
- if (consulted === cut) {
205
+ if (consulted === PASS_CUT) {
198
206
  throw Object.assign(new CompactionError("aborted", "compaction cancelled while the summary provider was answering — nothing was persisted"), opts.manualCancelSignal?.aborted === true ? { [COMPACTION_MANUAL_CANCEL_FLAG]: true } : {});
199
207
  }
200
208
  }
@@ -298,7 +306,12 @@ export async function maybeCompact(opts) {
298
306
  });
299
307
  }
300
308
  }
301
- const auth = await opts.getApiKeyAndHeaders?.(summaryModel);
309
+ const getApiKeyAndHeaders = opts.getApiKeyAndHeaders;
310
+ const authed = getApiKeyAndHeaders === undefined ? undefined : await untilPassCut(() => getApiKeyAndHeaders(summaryModel), opts.signal);
311
+ if (authed === PASS_CUT) {
312
+ throw Object.assign(new CompactionError("aborted", "compaction cancelled while the summary model's credentials were being fetched — nothing was summarized or persisted"), opts.manualCancelSignal?.aborted === true ? { [COMPACTION_MANUAL_CANCEL_FLAG]: true } : {});
313
+ }
314
+ const auth = authed;
302
315
  const summarySignal = opts.signal;
303
316
  const runtime = brainToRuntime(opts.brain);
304
317
  const forkCandidate = opts.compactionModel === undefined ? opts.forkContext?.() : undefined;
@@ -601,6 +614,9 @@ export function mintCompactedEvent(comp, trigger, identity) {
601
614
  ...identity,
602
615
  };
603
616
  }
617
+ export function manualCompactOutcomeOf(comp) {
618
+ return comp.compacted ? "compacted" : comp.blocked ? "blocked" : comp.disabled ? "disabled" : "noop";
619
+ }
604
620
  export function mintCompactionStartedEvent(start, identity) {
605
621
  return { type: "compaction_started", trigger: start.trigger, pass: start.pass, startedAt: start.startedAt, ...identity };
606
622
  }
@@ -37,7 +37,11 @@ export interface BackgroundAgentRecord {
37
37
  * keys on THIS field (listBySession matches it as a second arm), not on an alias walk. */
38
38
  rootSessionId?: string;
39
39
  parentTaskId?: string;
40
- name?: string;
40
+ /** The agent's name — the spawner's explicit one, or the one the engine derives from `handle`
41
+ * (`engineAgentName`) when the spawn named none. Written by the registration that creates the row, so
42
+ * every row core writes carries one; a revival re-reads it verbatim. A host store that reads a row an
43
+ * earlier version wrote without one derives it from `handle` with the same function. */
44
+ name: string;
41
45
  agentType?: string;
42
46
  description?: string;
43
47
  /** Revival lookup key (CC meta-sidecar parity); populated when known, never required. The team
@@ -180,7 +184,7 @@ export interface BackgroundAgentRowSummary {
180
184
  sessionId?: string;
181
185
  parentSessionId?: string;
182
186
  rootSessionId?: string;
183
- name?: string;
187
+ name: string;
184
188
  agentType?: string;
185
189
  status: BackgroundAgentRecord["status"];
186
190
  spawnedAt: number;
@@ -183,7 +183,7 @@ function toSummary(r) {
183
183
  ...(r.sessionId !== undefined ? { sessionId: r.sessionId } : {}),
184
184
  ...(r.parentSessionId !== undefined ? { parentSessionId: r.parentSessionId } : {}),
185
185
  ...(r.rootSessionId !== undefined ? { rootSessionId: r.rootSessionId } : {}),
186
- ...(r.name !== undefined ? { name: r.name } : {}),
186
+ name: r.name,
187
187
  ...(r.agentType !== undefined ? { agentType: r.agentType } : {}),
188
188
  status: r.status,
189
189
  spawnedAt: r.spawnedAt,