@sema-agent/core 7.52.0 → 7.54.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 (357) hide show
  1. package/CHANGELOG.md +470 -0
  2. package/LICENSE +3 -1
  3. package/README.md +3 -1
  4. package/dist/agents/cross-session-envelope.d.ts +8 -0
  5. package/dist/agents/cross-session-envelope.js +6 -0
  6. package/dist/agents/cross-session-judge.d.ts +21 -1
  7. package/dist/agents/cross-session-judge.js +8 -0
  8. package/dist/agents/cross-session-ref.d.ts +5 -0
  9. package/dist/agents/cross-session-ref.js +1 -0
  10. package/dist/agents/org-delivery-gate.d.ts +122 -0
  11. package/dist/agents/org-delivery-gate.js +69 -0
  12. package/dist/agents/peer-held-queue.d.ts +9 -4
  13. package/dist/agents/peer-held-queue.js +6 -5
  14. package/dist/agents/peer-session-drain.d.ts +35 -6
  15. package/dist/agents/peer-session-drain.js +271 -182
  16. package/dist/agents/read-inbox-tool.d.ts +7 -0
  17. package/dist/agents/read-inbox-tool.js +5 -1
  18. package/dist/agents/send-message-tool.js +3 -4
  19. package/dist/agents/subagent.d.ts +6 -5
  20. package/dist/agents/subagent.js +117 -83
  21. package/dist/agents/tool-filter.d.ts +25 -4
  22. package/dist/agents/tool-filter.js +13 -3
  23. package/dist/brain/anthropic.d.ts +6 -1
  24. package/dist/brain/anthropic.js +4 -4
  25. package/dist/brain/model-presets.js +2 -1
  26. package/dist/brain/route-adjudicator.d.ts +6 -0
  27. package/dist/brain/routing.d.ts +24 -1
  28. package/dist/brain/routing.js +54 -19
  29. package/dist/brain/timeout.js +5 -4
  30. package/dist/core/a2a.d.ts +5 -2
  31. package/dist/core/a2a.js +33 -14
  32. package/dist/core/allow-entry.d.ts +3 -1
  33. package/dist/core/allow-entry.js +3 -2
  34. package/dist/core/approval-object.d.ts +87 -0
  35. package/dist/core/approval-object.js +85 -0
  36. package/dist/core/arg-summary.d.ts +3 -2
  37. package/dist/core/arg-summary.js +17 -11
  38. package/dist/core/ask-origin.d.ts +43 -27
  39. package/dist/core/ask-origin.js +20 -11
  40. package/dist/core/ask-question.d.ts +0 -1
  41. package/dist/core/ask-question.js +4 -67
  42. package/dist/core/ask-unresolvable-notice.d.ts +3 -2
  43. package/dist/core/auto-compaction.d.ts +106 -50
  44. package/dist/core/auto-compaction.js +69 -53
  45. package/dist/core/auto-mode-prompt.d.ts +4 -2
  46. package/dist/core/auto-mode-prompt.js +4 -3
  47. package/dist/core/canonical-json.d.ts +69 -0
  48. package/dist/core/canonical-json.js +130 -8
  49. package/dist/core/checkpoint-requirements.d.ts +13 -7
  50. package/dist/core/checkpoint-requirements.js +4 -1
  51. package/dist/core/checkpoint-store.d.ts +60 -36
  52. package/dist/core/checkpoint-store.js +7 -6
  53. package/dist/core/child-clamp-seats.d.ts +45 -6
  54. package/dist/core/child-clamp-seats.js +56 -4
  55. package/dist/core/compliance.js +3 -1
  56. package/dist/core/consolidate-scope.d.ts +1 -1
  57. package/dist/core/cross-boundary-taint.d.ts +213 -0
  58. package/dist/core/cross-boundary-taint.js +196 -0
  59. package/dist/core/decision-receipt.d.ts +44 -1
  60. package/dist/core/decision-receipt.js +16 -0
  61. package/dist/core/effective-path-target.d.ts +28 -6
  62. package/dist/core/effective-path-target.js +28 -2
  63. package/dist/core/engine-notice.d.ts +47 -4
  64. package/dist/core/engine-notice.js +17 -1
  65. package/dist/core/engine-storage-backend.d.ts +73 -0
  66. package/dist/core/engine-storage-backend.js +1 -0
  67. package/dist/core/file-history-store.d.ts +6 -2
  68. package/dist/core/file-history-store.js +1 -0
  69. package/dist/core/gate-fold.js +13 -4
  70. package/dist/core/gate-lanes.js +41 -34
  71. package/dist/core/gate-outcome.d.ts +18 -9
  72. package/dist/core/governance-codes.d.ts +9 -2
  73. package/dist/core/governance-codes.js +9 -0
  74. package/dist/core/hands-band-screen.d.ts +7 -0
  75. package/dist/core/hands-band-screen.js +32 -0
  76. package/dist/core/hooks.d.ts +21 -19
  77. package/dist/core/hooks.js +6 -5
  78. package/dist/core/locked-config.d.ts +110 -31
  79. package/dist/core/locked-config.js +155 -42
  80. package/dist/core/lsp.d.ts +1 -1
  81. package/dist/core/mcp-probe.js +1 -1
  82. package/dist/core/mcp-server-spec.d.ts +152 -17
  83. package/dist/core/mcp-server-spec.js +223 -40
  84. package/dist/core/mcp.d.ts +21 -14
  85. package/dist/core/mcp.js +59 -54
  86. package/dist/core/memory-engine/engine.d.ts +14 -19
  87. package/dist/core/memory-engine/engine.js +9 -6
  88. package/dist/core/memory-engine/export-bundle.d.ts +1 -1
  89. package/dist/core/memory-engine/export-bundle.js +1 -1
  90. package/dist/core/memory-engine/file-backend.d.ts +2 -6
  91. package/dist/core/memory-engine/file-backend.js +1 -12
  92. package/dist/core/memory.d.ts +3 -3
  93. package/dist/core/mode-policy.d.ts +16 -26
  94. package/dist/core/mode-policy.js +5 -18
  95. package/dist/core/mods/kernel/dispatch.js +13 -15
  96. package/dist/core/mods/kernel/events.d.ts +9 -6
  97. package/dist/core/mods/kernel/events.js +2 -2
  98. package/dist/core/mods/kernel/receive.d.ts +41 -11
  99. package/dist/core/mods/kernel/receive.js +124 -54
  100. package/dist/core/mods/kernel/site-rules.d.ts +80 -15
  101. package/dist/core/mods/kernel/site-rules.js +232 -40
  102. package/dist/core/mods/stations.d.ts +0 -6
  103. package/dist/core/mods/stations.js +0 -7
  104. package/dist/core/mounted-mcp.d.ts +57 -0
  105. package/dist/core/mounted-mcp.js +71 -2
  106. package/dist/core/own-property-receipt.d.ts +13 -0
  107. package/dist/core/own-property-receipt.js +3 -1
  108. package/dist/core/parent-spec-seat.d.ts +12 -15
  109. package/dist/core/parent-spec-seat.js +14 -6
  110. package/dist/core/pause-registry.d.ts +35 -1
  111. package/dist/core/pause-registry.js +10 -0
  112. package/dist/core/permission-rule-consent.d.ts +18 -5
  113. package/dist/core/permission-rule-consent.js +13 -8
  114. package/dist/core/permission-rule-model.d.ts +87 -15
  115. package/dist/core/permission-rule-model.js +87 -8
  116. package/dist/core/permission-rule-org.d.ts +200 -33
  117. package/dist/core/permission-rule-org.js +217 -91
  118. package/dist/core/permission-rule-session.js +2 -2
  119. package/dist/core/permission-rule-store.d.ts +8 -0
  120. package/dist/core/permission-rule-store.js +1 -0
  121. package/dist/core/permission-rule-sync.js +3 -2
  122. package/dist/core/permission-rules.d.ts +7 -1
  123. package/dist/core/permission-rules.js +37 -8
  124. package/dist/core/read-only-shell.d.ts +1 -1
  125. package/dist/core/read-only-shell.js +30 -9
  126. package/dist/core/remote-env.d.ts +41 -1
  127. package/dist/core/remote-env.js +18 -0
  128. package/dist/core/resume-startup-cause.d.ts +18 -0
  129. package/dist/core/resume-startup-cause.js +12 -0
  130. package/dist/core/retention.js +7 -2
  131. package/dist/core/retired-keys.d.ts +8 -2
  132. package/dist/core/retired-keys.js +12 -1
  133. package/dist/core/roles.js +60 -10
  134. package/dist/core/rule-lane-reads.js +1 -1
  135. package/dist/core/runner/approval-feedback.d.ts +46 -0
  136. package/dist/core/runner/approval-feedback.js +41 -0
  137. package/dist/core/runner/compaction-call-options.d.ts +3 -3
  138. package/dist/core/runner/compaction-call-options.js +2 -2
  139. package/dist/core/runner/contracts.d.ts +34 -41
  140. package/dist/core/runner/cross-boundary-lane.d.ts +87 -0
  141. package/dist/core/runner/cross-boundary-lane.js +190 -0
  142. package/dist/core/runner/decide-continuation.d.ts +4 -4
  143. package/dist/core/runner/decide-continuation.js +3 -1
  144. package/dist/core/runner/gate-exit.d.ts +32 -12
  145. package/dist/core/runner/gate-exit.js +77 -34
  146. package/dist/core/runner/inherited-ask-grants.js +2 -2
  147. package/dist/core/runner/mcp-redial.d.ts +52 -10
  148. package/dist/core/runner/mcp-redial.js +38 -9
  149. package/dist/core/runner/permission-rule-lanes.d.ts +5 -2
  150. package/dist/core/runner/permission-rule-lanes.js +22 -10
  151. package/dist/core/runner/person-path-rows.d.ts +5 -3
  152. package/dist/core/runner/person-path-rows.js +2 -2
  153. package/dist/core/runner/prepare-acquire-reconcile.d.ts +3 -4
  154. package/dist/core/runner/prepare-acquire-reconcile.js +3 -3
  155. package/dist/core/runner/prepare-ask-lane.js +3 -3
  156. package/dist/core/runner/prepare-caps-and-workflow.d.ts +6 -5
  157. package/dist/core/runner/prepare-caps-and-workflow.js +3 -3
  158. package/dist/core/runner/prepare-config-doors.d.ts +58 -15
  159. package/dist/core/runner/prepare-config-doors.js +167 -146
  160. package/dist/core/runner/prepare-context-lane.js +6 -3
  161. package/dist/core/runner/prepare-defer-classify.js +4 -7
  162. package/dist/core/runner/prepare-delegation-surface.d.ts +5 -4
  163. package/dist/core/runner/prepare-delegation-surface.js +8 -7
  164. package/dist/core/runner/prepare-execution-env.d.ts +1 -2
  165. package/dist/core/runner/prepare-execution-env.js +2 -1
  166. package/dist/core/runner/prepare-gate-stations.d.ts +2 -0
  167. package/dist/core/runner/prepare-gate-stations.js +4 -3
  168. package/dist/core/runner/prepare-hands-readface.d.ts +3 -3
  169. package/dist/core/runner/prepare-hands-readface.js +3 -2
  170. package/dist/core/runner/prepare-inherited-gate.d.ts +2 -0
  171. package/dist/core/runner/prepare-inherited-gate.js +3 -2
  172. package/dist/core/runner/prepare-listings.d.ts +1 -1
  173. package/dist/core/runner/prepare-listings.js +4 -2
  174. package/dist/core/runner/prepare-memory-engine-session.d.ts +0 -6
  175. package/dist/core/runner/prepare-memory-engine-session.js +19 -6
  176. package/dist/core/runner/prepare-memory.d.ts +3 -2
  177. package/dist/core/runner/prepare-memory.js +6 -2
  178. package/dist/core/runner/prepare-offload-wrappers.d.ts +4 -4
  179. package/dist/core/runner/prepare-offload-wrappers.js +2 -1
  180. package/dist/core/runner/prepare-park-ask.d.ts +1 -1
  181. package/dist/core/runner/prepare-park-ask.js +9 -3
  182. package/dist/core/runner/prepare-policy-chain.d.ts +1 -1
  183. package/dist/core/runner/prepare-policy-chain.js +14 -19
  184. package/dist/core/runner/prepare-project-context.d.ts +1 -1
  185. package/dist/core/runner/prepare-project-context.js +6 -4
  186. package/dist/core/runner/prepare-prompt-assembly.d.ts +1 -1
  187. package/dist/core/runner/prepare-prompt-assembly.js +20 -16
  188. package/dist/core/runner/prepare-prompt-inputs.d.ts +12 -6
  189. package/dist/core/runner/prepare-prompt-inputs.js +6 -3
  190. package/dist/core/runner/prepare-protocol-tools.d.ts +7 -5
  191. package/dist/core/runner/prepare-protocol-tools.js +19 -12
  192. package/dist/core/runner/prepare-question-face.d.ts +4 -2
  193. package/dist/core/runner/prepare-question-face.js +4 -3
  194. package/dist/core/runner/prepare-safety-scan.d.ts +7 -2
  195. package/dist/core/runner/prepare-safety-scan.js +34 -27
  196. package/dist/core/runner/prepare-suspend-saga.d.ts +2 -2
  197. package/dist/core/runner/prepare-suspend-saga.js +6 -2
  198. package/dist/core/runner/prepare-task.js +22 -19
  199. package/dist/core/runner/prepare-turn-wiring.d.ts +10 -5
  200. package/dist/core/runner/prepare-turn-wiring.js +14 -49
  201. package/dist/core/runner/prepare-wiring-manifest.d.ts +10 -5
  202. package/dist/core/runner/prepare-wiring-manifest.js +9 -6
  203. package/dist/core/runner/prepare-workspace-restore.js +2 -2
  204. package/dist/core/runner/resume-admission.d.ts +4 -1
  205. package/dist/core/runner/resume-admission.js +16 -14
  206. package/dist/core/runner/resume-apply.js +4 -4
  207. package/dist/core/runner/resume-internals-and-config.d.ts +3 -3
  208. package/dist/core/runner/resume-internals-and-config.js +3 -8
  209. package/dist/core/runner/resume-policy-outcome.d.ts +2 -2
  210. package/dist/core/runner/resume-policy-outcome.js +18 -15
  211. package/dist/core/runner/resume-preflight.js +2 -2
  212. package/dist/core/runner/resume-review-outcome.js +3 -3
  213. package/dist/core/runner/retired-runner-deps.d.ts +5 -6
  214. package/dist/core/runner/retired-runner-deps.js +1 -4
  215. package/dist/core/runner/run-leg.js +97 -43
  216. package/dist/core/runner/run-recovery-lanes.js +5 -3
  217. package/dist/core/runner/run-settle-and-teardown.js +2 -0
  218. package/dist/core/runner/run-terminal-adoption.js +21 -9
  219. package/dist/core/runner/run-turn-boundary.js +9 -3
  220. package/dist/core/runner/runtask.js +1 -1
  221. package/dist/core/runner/session-file-state-replay.d.ts +5 -2
  222. package/dist/core/runner/session-file-state-replay.js +3 -2
  223. package/dist/core/runner/skills-seat.d.ts +15 -0
  224. package/dist/core/runner/skills-seat.js +57 -0
  225. package/dist/core/runner/stream-steer-verb.js +2 -2
  226. package/dist/core/runner/sub-agent-deny-lists.d.ts +13 -11
  227. package/dist/core/runner/sub-agent-deny-lists.js +7 -5
  228. package/dist/core/runner/synthetic-tools.d.ts +5 -2
  229. package/dist/core/runner/synthetic-tools.js +2 -12
  230. package/dist/core/runner/tool-face-overlay.d.ts +24 -6
  231. package/dist/core/runner/tool-face-overlay.js +24 -15
  232. package/dist/core/runner-deps.d.ts +37 -22
  233. package/dist/core/session-policy-store.d.ts +19 -0
  234. package/dist/core/session-policy-store.js +22 -2
  235. package/dist/core/session-store.d.ts +35 -16
  236. package/dist/core/session-store.js +20 -12
  237. package/dist/core/{shell-lexer.d.ts → shell-run-candidates.d.ts} +36 -12
  238. package/dist/core/{shell-lexer.js → shell-run-candidates.js} +145 -225
  239. package/dist/core/shell-wrapper-table.d.ts +5 -3
  240. package/dist/core/shell-wrapper-table.js +1 -1
  241. package/dist/core/store-contracts/checkpoint-store-contract.js +2 -2
  242. package/dist/core/store-contracts/mailbox-store-contract.js +13 -0
  243. package/dist/core/store-contracts/session-store-contract.d.ts +49 -0
  244. package/dist/core/store-contracts/session-store-contract.js +639 -0
  245. package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +12 -0
  246. package/dist/core/store-contracts/session-store-incarnation-contract.js +5 -2
  247. package/dist/core/task-event.d.ts +44 -6
  248. package/dist/core/task-notification.js +2 -2
  249. package/dist/core/task-registry-agent.js +1 -0
  250. package/dist/core/task-registry-shared.d.ts +5 -0
  251. package/dist/core/task-registry.d.ts +7 -0
  252. package/dist/core/task-registry.js +17 -0
  253. package/dist/core/task-result.d.ts +1 -1
  254. package/dist/core/task-spec.d.ts +7 -7
  255. package/dist/core/tighten-task-spec.d.ts +6 -4
  256. package/dist/core/tighten-task-spec.js +2 -2
  257. package/dist/core/tool-catalog-entries.d.ts +1 -1
  258. package/dist/core/tool-catalog-entries.js +52 -52
  259. package/dist/core/tool-face-reader.d.ts +49 -0
  260. package/dist/core/tool-face-reader.js +94 -0
  261. package/dist/core/tool-face.d.ts +17 -8
  262. package/dist/core/tool-face.js +1 -0
  263. package/dist/core/tool-policy.d.ts +67 -23
  264. package/dist/core/tool-policy.js +72 -60
  265. package/dist/core/tool-roster.d.ts +46 -28
  266. package/dist/core/tool-roster.js +91 -14
  267. package/dist/core/tool-spec-members.js +2 -2
  268. package/dist/core/tool-spec.d.ts +20 -4
  269. package/dist/core/tools.js +2 -0
  270. package/dist/core/trace.d.ts +24 -2
  271. package/dist/core/types.d.ts +3 -3
  272. package/dist/core/types.js +1 -1
  273. package/dist/core/untrusted-text.d.ts +23 -0
  274. package/dist/core/untrusted-text.js +10 -10
  275. package/dist/core/user-attachment.d.ts +56 -2
  276. package/dist/core/user-attachment.js +139 -56
  277. package/dist/core/wiring-manifest.d.ts +4 -2
  278. package/dist/engine/compaction/compaction.d.ts +2 -2
  279. package/dist/engine/compaction/utils.d.ts +2 -2
  280. package/dist/engine/harness/agent-harness.js +2 -1
  281. package/dist/engine/harness/types.d.ts +10 -4
  282. package/dist/engine/llm/types.d.ts +7 -2
  283. package/dist/engine/llm/types.js +2 -1
  284. package/dist/engine/loop/agent-loop.d.ts +12 -1
  285. package/dist/engine/loop/agent-loop.js +17 -5
  286. package/dist/engine/loop/types.d.ts +7 -1
  287. package/dist/engine/session/repo-utils.d.ts +5 -0
  288. package/dist/engine/session/repo-utils.js +9 -0
  289. package/dist/engine/session/storage-base.js +2 -2
  290. package/dist/index.d.ts +37 -17
  291. package/dist/index.js +31 -14
  292. package/dist/internal/harness.d.ts +1 -0
  293. package/dist/internal/harness.js +1 -0
  294. package/dist/internal/llm.d.ts +1 -1
  295. package/dist/internal/llm.js +1 -1
  296. package/dist/orchestration/goal.d.ts +24 -1
  297. package/dist/orchestration/goal.js +3 -2
  298. package/dist/orchestration/run-workflow-tool.d.ts +3 -0
  299. package/dist/orchestration/run-workflow-tool.js +1 -0
  300. package/dist/orchestration/workflow-governance.d.ts +1 -1
  301. package/dist/orchestration/workflow.d.ts +3 -0
  302. package/dist/orchestration/workflow.js +2 -1
  303. package/dist/prompt-assembly/artifact-store.d.ts +44 -9
  304. package/dist/prompt-assembly/artifact-store.js +38 -12
  305. package/dist/prompt-assembly/artifact.d.ts +12 -11
  306. package/dist/prompt-assembly/artifact.js +52 -21
  307. package/dist/prompt-assembly/assemble.d.ts +2 -0
  308. package/dist/prompt-assembly/assemble.js +2 -1
  309. package/dist/prompt-assembly/catalog/index.js +2 -1
  310. package/dist/prompt-assembly/catalog/memory.d.ts +13 -0
  311. package/dist/prompt-assembly/catalog/memory.js +6 -0
  312. package/dist/prompt-assembly/catalog/schema.d.ts +19 -2
  313. package/dist/prompt-assembly/catalog/schema.js +3 -0
  314. package/dist/prompt-assembly/composer.d.ts +2 -0
  315. package/dist/prompt-assembly/composer.js +1 -1
  316. package/dist/prompt-assembly/overlay.d.ts +21 -11
  317. package/dist/prompt-assembly/overlay.js +57 -19
  318. package/dist/prompt-assembly/select.d.ts +21 -6
  319. package/dist/prompt-assembly/select.js +41 -4
  320. package/dist/prompts/default.d.ts +1 -12
  321. package/dist/prompts/default.js +0 -3
  322. package/dist/shell/lex.d.ts +87 -8
  323. package/dist/shell/lex.js +283 -49
  324. package/dist/stores/file/index.d.ts +8 -6
  325. package/dist/stores/file/permission-rule-store.d.ts +1 -1
  326. package/dist/stores/file/permission-rule-store.js +2 -1
  327. package/dist/tools/artifact/artifact-tool.js +14 -3
  328. package/dist/tools/fs/bash-program-position.d.ts +3 -15
  329. package/dist/tools/fs/bash-program-position.js +3 -10
  330. package/dist/tools/fs/bash-readonly-classifier.js +2 -0
  331. package/dist/tools/fs/fs-bash.d.ts +3 -3
  332. package/dist/tools/fs/fs-bash.js +72 -101
  333. package/dist/tools/fs/fs-read.d.ts +12 -0
  334. package/dist/tools/fs/fs-read.js +10 -9
  335. package/dist/tools/fs/fs-shared.d.ts +27 -31
  336. package/dist/tools/fs/fs-shared.js +12 -15
  337. package/dist/tools/fs/fs-write.js +1 -1
  338. package/dist/tools/fs/index.js +2 -2
  339. package/dist/tools/fs/read-deny-home.d.ts +1 -1
  340. package/dist/tools/fs/read-deny-home.js +5 -4
  341. package/dist/tools/fs/read-deny.d.ts +16 -3
  342. package/dist/tools/fs/read-deny.js +12 -9
  343. package/dist/tools/fs/safety.d.ts +7 -6
  344. package/dist/tools/fs/shell-read-bindings.d.ts +5 -3
  345. package/dist/tools/fs/shell-read-bindings.js +15 -16
  346. package/dist/tools/fs/shell-read-device.js +1 -1
  347. package/dist/tools/fs/shell-read-plan.js +36 -47
  348. package/dist/tools/fs/shell-read-word.d.ts +1 -6
  349. package/dist/tools/fs/shell-read-word.js +2 -20
  350. package/dist/tools/fs/shell-reentry-text.js +1 -1
  351. package/dist/tools/web.d.ts +2 -2
  352. package/package.json +4 -1
  353. package/test/export-surface.snapshot.json +5651 -5457
  354. package/wire-changes/core@7.53.0.json +1968 -0
  355. package/wire-changes/core@7.54.0.json +2870 -0
  356. package/dist/core/shell-scan.d.ts +0 -60
  357. package/dist/core/shell-scan.js +0 -183
@@ -1,5 +1,7 @@
1
1
  import { createHash } from "node:crypto";
2
+ import { types } from "node:util";
2
3
  import { Type } from "typebox";
4
+ import { findToolByName } from "../internal/llm.js";
3
5
  import { getToolContract } from "../prompt-assembly/tool-catalog.js";
4
6
  import { protocolOf } from "./protocol-table.js";
5
7
  import { describeToolCatalog } from "./tool-registry.js";
@@ -7,6 +9,8 @@ import { RENDER_HINT_ACTIVITY_MAX_CHARS, RENDER_HINT_MAX_CHARS, RENDER_HINT_MAX_
7
9
  import { ASK_USER_QUESTION_TOOL_NAME } from "./ask-question.js";
8
10
  import { PRESENT_PLAN_TOOL_NAME } from "./present-plan-tool.js";
9
11
  import { wireOf } from "./tool-name-readings.js";
12
+ import { BOUNDARY_LEGS, rosterBoundaryLegs } from "./cross-boundary-taint.js";
13
+ import { isPlainRecord, receive } from "./mods/kernel/receive.js";
10
14
  function lit(values) {
11
15
  return Type.Union(values.map((v) => Type.Literal(v)));
12
16
  }
@@ -46,6 +50,7 @@ export const ToolRosterEntry = Type.Object({
46
50
  contentOrigin: lit(["local", "execution", "external"]),
47
51
  contentOriginProvenance: lit(["declared", "server", "exempted", "default"]),
48
52
  family: lit(TOOL_FAMILIES),
53
+ boundaryLegs: Type.Union([Type.Literal("per_call"), Type.Array(lit(BOUNDARY_LEGS), { uniqueItems: true })]),
49
54
  pathTarget: Type.Optional(Type.Object({
50
55
  param: Key,
51
56
  aliases: Type.Array(Key),
@@ -122,9 +127,7 @@ export function parkedToolIdentity(roster, toolName) {
122
127
  if (roster === undefined)
123
128
  return {};
124
129
  const e = rosterEntryNamed(roster, toolName);
125
- if (e === undefined)
126
- return {};
127
- return { capabilityId: e.capabilityId, contractId: e.contract.contractId, shapeDigest: e.shapeDigest, implementationRevision: e.contract.implementationRevision, rosterDigest: roster.digest };
130
+ return e === undefined ? {} : toolIdentityOf(e);
128
131
  }
129
132
  export function parkedToolFace(roster, req) {
130
133
  if (roster === undefined)
@@ -301,6 +304,18 @@ export function survivorsByName(mounted) {
301
304
  return winner;
302
305
  }
303
306
  export const faceOf = (t) => t;
307
+ const setOrClear = (m, key, value) => {
308
+ if (value === undefined)
309
+ m.delete(key);
310
+ else
311
+ m.set(key, value);
312
+ };
313
+ const memberIf = (s, key, member) => {
314
+ if (member)
315
+ s.add(key);
316
+ else
317
+ s.delete(key);
318
+ };
304
319
  function configError(code, message) {
305
320
  const e = new Error(message);
306
321
  e.code = code;
@@ -311,8 +326,10 @@ export class RosterBuilder {
311
326
  #engineLane = [];
312
327
  #meta = new WeakMap();
313
328
  #effects;
314
- constructor(effects) {
329
+ #axes;
330
+ constructor(effects, axes) {
315
331
  this.#effects = effects;
332
+ this.#axes = axes;
316
333
  }
317
334
  get tools() {
318
335
  return this.#tools;
@@ -324,12 +341,18 @@ export class RosterBuilder {
324
341
  return this.#meta.get(tool);
325
342
  }
326
343
  mount(tool, meta) {
344
+ const displaced = this.#survivorNamed(tool.name);
327
345
  this.#admit(tool, meta);
328
346
  this.#tools.push(tool);
347
+ if (meta.mountedBy !== "scenario")
348
+ this.#resettleAliases([...(displaced?.aliases ?? []), ...(tool.aliases ?? [])]);
329
349
  }
330
350
  mountEngineLane(tool, meta) {
351
+ const displaced = this.#survivorNamed(tool.name);
331
352
  this.#admit(tool, meta);
332
353
  this.#engineLane.push(tool);
354
+ if (meta.mountedBy !== "scenario")
355
+ this.#resettleAliases([...(displaced?.aliases ?? []), ...(tool.aliases ?? [])]);
333
356
  }
334
357
  #admit(tool, meta) {
335
358
  if ((meta.source === "mcp" || meta.source === "a2a" || meta.source === "external") !== (meta.origin !== undefined)) {
@@ -342,6 +365,32 @@ export class RosterBuilder {
342
365
  if (eff !== undefined && meta.mountedBy !== "scenario")
343
366
  this.#effects.set(tool.name, eff);
344
367
  }
368
+ #survivorNamed(name) {
369
+ return survivorsByName([...this.#tools, ...this.#engineLane]).get(name);
370
+ }
371
+ #resettleAliases(aliases) {
372
+ if (aliases.length === 0)
373
+ return;
374
+ const live = [...survivorsByName([...this.#tools, ...this.#engineLane]).values()];
375
+ for (const a of new Set(aliases)) {
376
+ const owner = findToolByName(live, a);
377
+ if (owner?.name === a)
378
+ continue;
379
+ this.#repoint(a, owner?.name);
380
+ }
381
+ }
382
+ #repoint(key, from) {
383
+ const pick = (m) => (from === undefined ? undefined : m.get(from));
384
+ const marks = this.#axes === undefined ? undefined : pick(this.#axes.toolMarkSources);
385
+ setOrClear(this.#effects, key, pick(this.#effects));
386
+ if (this.#axes === undefined)
387
+ return;
388
+ setOrClear(this.#axes.irreversibilityTier, key, pick(this.#axes.irreversibilityTier));
389
+ setOrClear(this.#axes.reversibilityProbes, key, pick(this.#axes.reversibilityProbes));
390
+ setOrClear(this.#axes.toolMarkSources, key, marks === undefined ? undefined : new Set(marks));
391
+ memberIf(this.#axes.irreversibleTools, key, from !== undefined && this.#axes.irreversibleTools.has(from));
392
+ memberIf(this.#axes.egressTools, key, from !== undefined && this.#axes.egressTools.has(from));
393
+ }
345
394
  mountAll(tools, meta) {
346
395
  for (const t of tools)
347
396
  this.mount(t, meta);
@@ -355,6 +404,10 @@ export class RosterBuilder {
355
404
  removed.unshift(t);
356
405
  }
357
406
  }
407
+ for (const t of removed)
408
+ if (this.#survivorNamed(t.name) === undefined)
409
+ this.#effects.delete(t.name);
410
+ this.#resettleAliases(removed.flatMap((t) => t.aliases ?? []));
358
411
  return removed;
359
412
  }
360
413
  replaceAt(index, tool) {
@@ -449,18 +502,50 @@ export function callerCardIdOf(tool) {
449
502
  const t = tool;
450
503
  return rosterCardId(callerMountSource(t), t.name, null, t.name, getToolContract(t, "caller").contractId);
451
504
  }
505
+ export function protocolToolOf(toolName) {
506
+ return protocolOf(toolName)?.parse(toolName)?.tool ?? toolName;
507
+ }
508
+ export function boundaryLegsRefusal(toolName) {
509
+ const named = typeof toolName === "string" ? JSON.stringify(toolName.slice(0, 128)) : `(a ${typeof toolName} name)`;
510
+ return configError("config.tool_face_invalid", `tool ${named}: its boundaryLegs declaration is neither "per_call" nor a list of ${BOUNDARY_LEGS.join(" | ")}`);
511
+ }
512
+ const ROSTER_LEGS_RECEIPT = Object.freeze({ accessors: "refuse", depth: 3, others: "as-is", contain: true, isProxy: (v) => types.isProxy(v) });
513
+ const SLOT = /^(?:0|[1-9]\d*)$/;
514
+ export function assertToolBoundaryLegs(tools) {
515
+ const got = receive(tools, ROSTER_LEGS_RECEIPT);
516
+ if (!got.ok || !Array.isArray(got.value))
517
+ return;
518
+ const unread = new Set();
519
+ for (const f of got.faults ?? []) {
520
+ const [at, member, slot] = f.path;
521
+ if (at !== undefined && (member === "name" || (member === "boundaryLegs" && slot !== undefined && SLOT.test(slot))))
522
+ unread.add(at);
523
+ }
524
+ got.value.forEach((t, i) => {
525
+ if (!isPlainRecord(t) || unread.has(String(i)))
526
+ return;
527
+ const legs = t["boundaryLegs"];
528
+ if (Array.isArray(legs) && Object.getPrototypeOf(legs) !== Array.prototype)
529
+ return;
530
+ if (rosterBoundaryLegs("caller", legs, "write") === undefined)
531
+ throw boundaryLegsRefusal(t["name"]);
532
+ });
533
+ }
452
534
  export function mintRosterEntry(tool, meta, facts) {
453
535
  const face = faceOf(tool);
454
536
  const fallbackOrigin = meta.source === "builtin" ? "core" : meta.source === "synthetic" ? "synthetic" : meta.source === "mcp" || meta.source === "a2a" ? meta.source : "caller";
455
537
  const d = getToolContract(tool, fallbackOrigin);
456
538
  const peer = meta.origin?.peer ?? null;
457
- const protocolTool = peer !== null ? protocolOf(tool.name)?.parse(tool.name)?.tool ?? tool.name : tool.name;
539
+ const protocolTool = peer !== null ? protocolToolOf(tool.name) : tool.name;
458
540
  const cardId = rosterCardId(meta.source, tool.name, peer, protocolTool, d.contractId);
459
541
  const { keys: inputKeys } = inputKeysOf(tool.parameters);
460
542
  const declaredEffect = face.effect;
461
543
  const foldedEffect = facts.effects.get(tool.name);
462
544
  const effect = declaredEffect ?? foldedEffect ?? "write";
463
545
  const effectProvenance = declaredEffect !== undefined ? (meta.source === "synthetic" ? "synthetic" : "declared") : foldedEffect !== undefined && (meta.source === "mcp" || meta.source === "a2a") ? "caller" : "default";
546
+ const boundaryLegs = rosterBoundaryLegs(meta.source, face.boundaryLegs, effect);
547
+ if (boundaryLegs === undefined)
548
+ throw boundaryLegsRefusal(tool.name);
464
549
  const egress = face.egress === true || facts.egress.has(tool.name);
465
550
  const egressProvenance = face.egress === true ? "declared" : egress ? "caller" : "default";
466
551
  const irreversibility = face.irreversibility ?? facts.irreversibilityTier.get(tool.name);
@@ -505,6 +590,7 @@ export function mintRosterEntry(tool, meta, facts) {
505
590
  contentOrigin,
506
591
  contentOriginProvenance,
507
592
  family: face.family !== undefined && TOOL_FAMILIES.includes(face.family) ? face.family : "other",
593
+ boundaryLegs: boundaryLegs === "per_call" ? boundaryLegs : [...boundaryLegs],
508
594
  ...(pathTarget !== undefined
509
595
  ? {
510
596
  pathTarget: {
@@ -608,15 +694,6 @@ export function diffToolRoster(prev, next) {
608
694
  removed.push(name);
609
695
  return { fromDigest: prev.digest, roster: next, summary: { added, removed, changed } };
610
696
  }
611
- export function judgeParkedToolIdentity(pending, row) {
612
- const carried = pending.capabilityId !== undefined || pending.contractId !== undefined || pending.shapeDigest !== undefined || pending.implementationRevision !== undefined;
613
- if (row === undefined)
614
- return "absent";
615
- if (!carried)
616
- return "name_only";
617
- const id = toolIdentityOf(row);
618
- return pending.capabilityId === id.capabilityId && pending.contractId === id.contractId && pending.shapeDigest === id.shapeDigest && pending.implementationRevision === id.implementationRevision ? "match" : "mismatch";
619
- }
620
697
  export function offendingResultCard(hints, cardId, engineCards) {
621
698
  for (const c of hints?.resultCards ?? []) {
622
699
  if (typeof c !== "string")
@@ -5,9 +5,9 @@ export const TOOL_SPEC_MEMBERS = Object.keys({
5
5
  contentOrigin: true, offload: true, offloadThresholdChars: true, defer: true, alwaysLoad: true, prepareArguments: true,
6
6
  validateInput: true, approvalPreview: true, family: true, pathTarget: true, ruleFace: true, renderHints: true, compactable: true,
7
7
  budgetExempt: true, modelGate: true, contract: true, agentListing: true, agentModels: true, agentToolFaces: true,
8
- agentToolLevelAllowTools: true, agentToolLevelDenyTools: true, agentToolPool: true, agentToolInheritsMcp: true, withAgents: true,
8
+ agentToolLevelAllowTools: true, agentToolLevelDenyTools: true, agentToolPool: true, agentToolInheritsMcp: true, withAgents: true, boundaryLegs: true, boundaryLegsFor: true,
9
9
  });
10
- const FUNCTION_MEMBERS = new Set(["execute", "prepareArguments", "validateInput", "approvalPreview", "reversibilityProbe", "isConcurrencySafe", "withAgents"]);
10
+ const FUNCTION_MEMBERS = new Set(["execute", "prepareArguments", "validateInput", "approvalPreview", "reversibilityProbe", "isConcurrencySafe", "withAgents", "boundaryLegsFor"]);
11
11
  const NAME_LIST_MEMBERS = new Set(["aliases", "agentModels", "agentToolLevelAllowTools", "agentToolLevelDenyTools"]);
12
12
  const FACE_LIST_KEYS = new Set(["allowTools", "denyTools"]);
13
13
  const FACE_PLACES = { elementKeys: FACE_LIST_KEYS };
@@ -306,10 +306,10 @@ export interface ToolSpec<TParams extends TSchema = TSchema> {
306
306
  egress?: true;
307
307
  /**
308
308
  * The tool's PERMISSION SEAT. `"passthrough"`: the tool states no permission of its own — under an asking permission mode
309
- * (`default` / `acceptEdits` / `plan` / `auto` / `dontAsk`) a call to it runs only when some layer STATES an allow (an allow
310
- * rule or allow-list entry naming it, an approver's yes, a PreToolUse hook's own `allow`); a policy fold in which nobody
311
- * stated it ("no objection") gets the mode's question (class `unstated`, origin `policy`), which dontAsk refuses, auto's
312
- * classifier may answer, and `bypassPermissions` never raises. The MCP and A2A materializers set it on a remote peer's
309
+ * (`default` / `acceptEdits` / `plan` / `auto` / `dontAsk`) a policy fold's allow is "no objection" and gets the mode's
310
+ * question (class `unstated`, origin `policy`) unless an approver's yes was given for the bytes that run; the allow layer
311
+ * answers it (an allow entry in `RunnerDeps.allowedTools` / `TaskSpec.allowedTools`, a stored row, a skill's list, a PreToolUse
312
+ * hook's own `allow`), dontAsk refuses it, auto's classifier may answer it, and `bypassPermissions` never raises it. The MCP and A2A materializers set it on a remote peer's
313
313
  * tool. Absent: the tool answers for itself (the engine's own stations and the deployment's declarations). Tightening only —
314
314
  * it can make a tool ask, never let one run.
315
315
  */
@@ -524,6 +524,18 @@ export interface ToolSpec<TParams extends TSchema = TSchema> {
524
524
  * missing declaration rather than defaulting it).
525
525
  */
526
526
  family?: ToolFamily;
527
+ /**
528
+ * The legs a call of this tool travels across the device boundary — the engine's own definitions declare it on their catalog face
529
+ * ({@link import("./tool-face.js").ToolFaceDeclaration.boundaryLegs}, required there), and this member carries it onto the mounted
530
+ * instance. Read only on a roster row of source `builtin` / `synthetic` (a `TaskSpec.tools` entry is one only when it carries a core
531
+ * contract); any other tool's row states legs from its `effect`. A value that is neither `"per_call"` nor a list of legs is refused
532
+ * (`config.tool_face_invalid`): for a `TaskSpec.tools` entry where the roster enters, whether or not the entry mounts.
533
+ */
534
+ boundaryLegs?: import("./cross-boundary-taint.js").BoundaryLegsDeclaration;
535
+ /** The per-call half of a `"per_call"` {@link boundaryLegs} declaration, written beside the code that dispatches the call: the legs one
536
+ * call travels, given its arguments as the tool reads them ({@link import("./cross-boundary-taint.js").BoundaryLegsFor}). Read only for
537
+ * a row that declares `"per_call"`; such a row with no resolver, or a resolver that throws, reads as every leg off-target. */
538
+ boundaryLegsFor?: import("./cross-boundary-taint.js").BoundaryLegsFor;
527
539
  /**
528
540
  * design/388 §2.2 ② — the parameter that names this tool's filesystem TARGET and how it is touched.
529
541
  * Present ⇔ the tool can be confirmed BY PATH: write confinement (`allowDirs`, the fs-write gate,
@@ -1156,6 +1168,10 @@ export interface ToolExecuteContext {
1156
1168
  * tool runs outside a Runner task.
1157
1169
  */
1158
1170
  inheritedGateForChildren?: () => import("./runner/contracts.js").InheritedGate;
1171
+ /** The run tree's cross-boundary token ({@link import("./runner/contracts.js").RunInternals.crossBoundaryTree}) — Runner-filled, opaque
1172
+ * and frozen; a delegation or workflow tool hands this SAME token into its child's trusted internals (and records it on a background
1173
+ * handle), so the child joins the tree and a bit any leg sets is read by every other. No tool reads or writes the state through it. */
1174
+ crossBoundaryTreeForChildren?: import("./cross-boundary-taint.js").CrossBoundaryTreeToken;
1159
1175
  /**
1160
1176
  * design/180 half A — the delegation runtime-provenance ARMING face. Runner-filled; a delegation
1161
1177
  * tool calls it at spawn time: a non-undefined return means this (parent) run is armed (it mounts
@@ -95,6 +95,8 @@ function buildProduct(spec, owner, options) {
95
95
  ...(spec.alwaysLoad !== undefined ? { alwaysLoad: spec.alwaysLoad } : {}),
96
96
  ...(spec.prepareArguments ? { prepareArguments: spec.prepareArguments } : {}),
97
97
  ...(spec.family !== undefined ? { family: spec.family } : {}),
98
+ ...(spec.boundaryLegs !== undefined ? { boundaryLegs: spec.boundaryLegs } : {}),
99
+ ...(spec.boundaryLegsFor !== undefined ? { boundaryLegsFor: spec.boundaryLegsFor } : {}),
98
100
  ...(spec.pathTarget !== undefined ? { pathTarget: spec.pathTarget } : {}),
99
101
  ...(spec.ruleFace !== undefined ? { ruleFace: spec.ruleFace } : {}),
100
102
  ...(spec.renderHints !== undefined ? { renderHints: spec.renderHints } : {}),
@@ -332,8 +332,11 @@ export type TraceEvent = {
332
332
  * `tool.call.turn`. Lets a bridge put a `chat` span and the `execute_tool` spans of the tools that
333
333
  * call requested under one parent without re-deriving turn boundaries from event order.
334
334
  *
335
- * ABSENT on the compaction summarizer's own call: that call fires from the turn-boundary hook and
336
- * is not a loop turn, so any number here would be a different measurement wearing the same name.
335
+ * ABSENT on every provider call fired beside the loop — the compaction summarizer (it fires from the turn-boundary hook), the
336
+ * classifier gate, a mod's own call: none is a loop turn, so any number here would be a different measurement wearing the same
337
+ * name. So `turn` present ⇔ the call is the main loop's own; absent ⇔ a call outside the loop. Those rows also carry
338
+ * `latencyMs: 0` (no wall time is measured for them), so a latency average taken over the rows that carry a `turn` is not diluted
339
+ * by them.
337
340
  */
338
341
  turn?: number;
339
342
  /** Normalized prompt tokens that MISSED the cache (Anthropic-protocol `input_tokens`
@@ -555,6 +558,25 @@ export type TraceEvent = {
555
558
  * joined — provider failure, refused snapshot, rollback refusal, missing durable persistence. */
556
559
  message: string;
557
560
  ts: number;
561
+ } | {
562
+ /**
563
+ * The device lane's cross-boundary TAINT on a tree that executes on a target device: once when a leg is prepared on an armed
564
+ * tree (`phase: "prepare"`; `"resume"` on a durable resume's leg), and once when this leg first lets an off-target read into the
565
+ * tree (`"observed"`, with the call). A tree that never armed emits none. Metadata only.
566
+ */
567
+ kind: "permission.cross_boundary_taint";
568
+ version: 1;
569
+ taskId: string;
570
+ runId: string;
571
+ phase: "prepare" | "resume" | "observed";
572
+ /** The tree's taint bits after the event. */
573
+ taint: readonly import("./cross-boundary-taint.js").CrossBoundaryTaintBit[];
574
+ /** The tree has run under the `multi_tenant` posture since it armed. */
575
+ governed: boolean;
576
+ /** The call that let the off-target read in (`observed` only). */
577
+ toolName?: string;
578
+ toolCallId?: string;
579
+ ts: number;
558
580
  } | {
559
581
  /**
560
582
  * F-012 L2 — a pending ask was AUTO-ADMITTED by the sandbox-admission leg: the deployment's
@@ -18,8 +18,8 @@ export type { PermissionMode } from "./ask-origin.js";
18
18
  export type { ToolEffect, ToolContentOrigin, ReversibilityVerdict, ReadRootGrantCandidate, ToolSpec, ToolReturn, NestedUsage, NestedUsageAccum, ToolExecuteContext } from "./tool-spec.js";
19
19
  export type { BeforeWriteRequest, BeforeWriteResult, BeforeWriteHook, TrackEditRequest, TrackEditResult, TrackFileEditHook, FileEditedNotice, FileEditedHook, HandsBandOptions } from "./hands-band.js";
20
20
  export type { AgentDefinition, SkillSpec } from "./agent-definition.js";
21
- export type { McpServerSpec, A2aServerSpec, McpElicitRequest, McpElicitResponse, OnElicit, McpRevocationLedger, McpMountIdentity, McpToolAxesRead } from "./mcp-server-spec.js";
22
- export { readMcpToolAxes } from "./mcp-server-spec.js";
21
+ export type { McpServerSpec, A2aServerSpec, McpElicitRequest, McpElicitResponse, OnElicit, McpRevocationLedger, McpMountIdentity, DeclarationFault, DeclarationPathRule, DeclarationRead, ToolAxesRead, ToolAxesSurface } from "./mcp-server-spec.js";
22
+ export { DECLARATION_PATH_RULES, NO_DECLARATION_PATH_RULES, dataKind, declarationFaultOf, declarerWord, perToolEmptyName, perToolEntryRefusal, quotedName, readMcpToolAxes, readToolAxes, receiveDeclaration, receivePerToolDeclaration, toolAxesRefusal } from "./mcp-server-spec.js";
23
23
  export type { TaskLimits } from "./task-limits.js";
24
24
  export type { TaskStatus, RemoteEnvFailureNote, EffectiveMemoryScopes, TaskResult, HumanReviewGateRow } from "./task-result.js";
25
25
  export type { TerminalCause, PausedCause } from "./terminal-cause.js";
@@ -30,6 +30,6 @@ export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./runtime-caps.js"
30
30
  export type { BackgroundChildEvent, BackgroundChildRow, DelegationLifecycleEvent } from "./delegation-frames.js";
31
31
  export { __resetMalformedDelegationSeatAnnouncement, backgroundChildTerminal, deliverDelegationLifecycle, emitsChildRowFrames, taskStartedFrame } from "./delegation-frames.js";
32
32
  export type { ProjectMemoryLoad, ResumePreflightInfo, ResumePreflightVerdict, RunnerDeps } from "./runner-deps.js";
33
- export type { EngineNotice, OwedUserInputAccount, UserInputUndrainedCause } from "./engine-notice.js";
33
+ export type { ApprovalCarryRefusal, EngineNotice, OwedUserInputAccount, UserInputUndrainedCause } from "./engine-notice.js";
34
34
  export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_INPUT_UNDRAINED_CAUSES, USER_INPUT_UNDRAINED_FAMILIES } from "./engine-notice.js";
35
35
  export type { AgentTool, Model, StreamFn, ThinkingLevel, ToolInputValidationContext, ToolInputVerdict };
@@ -1,5 +1,5 @@
1
1
  export { MODEL_ROLES } from "./model-seat.js";
2
- export { readMcpToolAxes } from "./mcp-server-spec.js";
2
+ export { DECLARATION_PATH_RULES, NO_DECLARATION_PATH_RULES, dataKind, declarationFaultOf, declarerWord, perToolEmptyName, perToolEntryRefusal, quotedName, readMcpToolAxes, readToolAxes, receiveDeclaration, receivePerToolDeclaration, toolAxesRefusal } from "./mcp-server-spec.js";
3
3
  export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./runtime-caps.js";
4
4
  export { __resetMalformedDelegationSeatAnnouncement, backgroundChildTerminal, deliverDelegationLifecycle, emitsChildRowFrames, taskStartedFrame } from "./delegation-frames.js";
5
5
  export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_INPUT_UNDRAINED_CAUSES, USER_INPUT_UNDRAINED_FAMILIES } from "./engine-notice.js";
@@ -238,6 +238,13 @@ export declare function defuseExactMarkInSegments(segments: readonly string[], m
238
238
  * {@link FENCED_LANE_ENVELOPE_TAGS}) and at each envelope's own mint site (the registry's guard column).
239
239
  */
240
240
  export declare function sanitizeUntrustedText(text: string, extraTags?: string[]): string;
241
+ /**
242
+ * THE sentence every arm speaks when it refuses a person's text because {@link sanitizeUntrustedText} would change it — the engine's own
243
+ * sentinel tag, opening (with or without attributes) or closing, which the judge refuses alike. `subject` names what carried it. Produced
244
+ * once, here beside the judge, so the sentence and the rule cannot drift apart by arm (the decide's deny / reject `reason`, a plan's
245
+ * `editedPlan`, an allow's `feedback`, a trusted live steer).
246
+ */
247
+ export declare function sentinelTagRefusal(subject: string): string;
241
248
  /**
242
249
  * [c209-C] 收口 C1/C2 (metadata-driven, replaces the shape-anchored
243
250
  * `stripLeadingSystemReminders`) — cut the engine-prepended prefix off a user-lane message using the
@@ -397,6 +404,12 @@ export declare function defuseControlChars(text: string): string;
397
404
  * Defense-in-depth, NOT a guarantee (same posture as the rest of this module).
398
405
  */
399
406
  export declare function inlineUntrusted(text: string, maxLen?: number): string;
407
+ /** The mark a cut text ends in: {@link inlineUntrusted}'s, and a notice's machine-read rule text's
408
+ * ({@link import("./permission-rule-model.js").noticeRuleText}) — one ellipsis, spelled once. */
409
+ export declare const INLINE_TRUNCATION_MARK = "\u2026";
410
+ /** The code points {@link inlineUntrusted} may return beyond its content cap: the one truncation mark. The longest result for a cap
411
+ * of `maxLen` is `maxLen` plus this. */
412
+ export declare const INLINE_TRUNCATION_MARK_CODEPOINTS: number;
400
413
  /** The per-ENTRY ceiling inside a `ProbeCause` operand family (checkpoint-store's
401
414
  * structured probe account), sized like the descriptor's own `touchedPaths` entries (the same thing
402
415
  * on the same card). Per entry, not per cause: that is the whole point of the structured shape —
@@ -414,6 +427,16 @@ export declare const PROBE_CAUSE_PATH_MAX = 200;
414
427
  * (tools/fs) and must fit every load-bearing part inside this bound, the gate, the persist boundary — and
415
428
  * a value import from tools/fs into checkpoint-store closes an ESM cycle. */
416
429
  export declare const PROBE_REASON_MAX = 200;
430
+ /**
431
+ * Whether `text` is a probe's one-sentence account the engine itself could have minted: every mint passes the sentence through
432
+ * {@link inlineUntrusted} at {@link PROBE_REASON_MAX}, so the longest one is the cap's content plus the truncation ellipsis
433
+ * ({@link INLINE_TRUNCATION_MARK_CODEPOINTS}), counted in code points. A host that relays the sentence (`RiskDescriptor.probeReason`,
434
+ * `AskRequest.probeReason`) and meets a longer one has met text the engine did not mint (a third-party producer, a generation
435
+ * with another cap) — to be dropped whole, not cut, because a cut is another sentence. The bound lives here once; a host asks, it does not count.
436
+ * The question is total: a value that is not a string is not a sentence the engine mints (every mint is a string), so it answers
437
+ * `false` — the relay's answer to it, dropping it whole, is the same as to an over-long one.
438
+ */
439
+ export declare function isMintableProbeReason(text: unknown): boolean;
417
440
  /** The one body bound every "reviewer note" relay passes to {@link delimitUntrusted} — the decider's
418
441
  * free text attached to a deny (sync `AskOutcome.reason` and the durable `ResumeOutcome` `reason`
419
442
  * legs alike). A note is steering, not payload: unbounded it can flood the transcript/context the
@@ -66,14 +66,6 @@ export const ENGINE_ENVELOPES = Object.freeze([
66
66
  fenced: true,
67
67
  disclosed: true,
68
68
  },
69
- {
70
- tag: "working-file",
71
- kind: "framing",
72
- mint: "core/auto-compaction.ts (post-compaction working-file snapshot)",
73
- guard: "sanitizeUntrustedText(WORKING_FILE_BREAKOUT_TAGS) + escapeWorkingFilePathAttr",
74
- fenced: false,
75
- disclosed: false,
76
- },
77
69
  {
78
70
  tag: "summary",
79
71
  kind: "framing",
@@ -482,6 +474,9 @@ export function defuseExactMarkInSegments(segments, mark) {
482
474
  export function sanitizeUntrustedText(text, extraTags = []) {
483
475
  return text.replace(breakoutRe(extraTags), (m) => ESCAPED_LT + m.slice(1));
484
476
  }
477
+ export function sentinelTagRefusal(subject) {
478
+ return `${subject} must not contain a <system-reminder> tag (opening or closing)`;
479
+ }
485
480
  export function cutEnginePrefix(text, enginePrefixChars) {
486
481
  if (typeof enginePrefixChars === "number" &&
487
482
  Number.isInteger(enginePrefixChars) &&
@@ -568,18 +563,23 @@ const LABEL_MAX = 160;
568
563
  export function inlineUntrusted(text, maxLen = LABEL_MAX) {
569
564
  const oneLine = text.replace(/[\s\u0000-\u001f\u007f-\u009f]+/g, " ").trim();
570
565
  const cps = [...oneLine];
571
- const capped = cps.length > maxLen ? cps.slice(0, maxLen).join("") + "…" : oneLine;
566
+ const capped = cps.length > maxLen ? cps.slice(0, maxLen).join("") + INLINE_TRUNCATION_MARK : oneLine;
572
567
  const out = neutralizeForFence(capped);
573
568
  if (maxLen <= 0)
574
569
  return "";
575
570
  const outCps = [...out];
576
- return outCps.length > maxLen + 1 ? outCps.slice(0, maxLen).join("") + "…" : out;
571
+ return outCps.length > maxLen + INLINE_TRUNCATION_MARK_CODEPOINTS ? outCps.slice(0, maxLen).join("") + INLINE_TRUNCATION_MARK : out;
577
572
  }
573
+ export const INLINE_TRUNCATION_MARK = "…";
574
+ export const INLINE_TRUNCATION_MARK_CODEPOINTS = [...INLINE_TRUNCATION_MARK].length;
578
575
  function sanitizeLabel(label) {
579
576
  return inlineUntrusted(label, LABEL_MAX);
580
577
  }
581
578
  export const PROBE_CAUSE_PATH_MAX = 200;
582
579
  export const PROBE_REASON_MAX = 200;
580
+ export function isMintableProbeReason(text) {
581
+ return typeof text === "string" && [...text].length <= PROBE_REASON_MAX + INLINE_TRUNCATION_MARK_CODEPOINTS;
582
+ }
583
583
  export const REVIEWER_NOTE_MAX_BODY = 2048;
584
584
  export function delimitUntrusted(label, text, maxBody) {
585
585
  return delimitUntrustedWithClip(label, text, maxBody).text;
@@ -27,6 +27,8 @@ import type { HumanInputAttachment } from "./task-event.js";
27
27
  import { type ModelFileReader } from "../tools/fs/fs-read.js";
28
28
  import type { SyntheticReadJudge } from "./synthetic-read-verdict.js";
29
29
  import { type ReminderDisclosureCounts } from "./reminder-disclosure.js";
30
+ import { type AgentMessage } from "../internal/harness.js";
31
+ import type { ReadEntry } from "../tools/fs/safety.js";
30
32
  import type { ContextWindowOverlay } from "./context-settings.js";
31
33
  /** At most this many attachments on one objective. */
32
34
  export declare const USER_ATTACHMENTS_MAX = 20;
@@ -73,9 +75,20 @@ export type ScreenedUserAttachment = {
73
75
  readonly data: string;
74
76
  readonly mimeType: string;
75
77
  };
76
- /** The door's refusal: one code, the field named first. */
77
- export declare function userAttachmentRefusal(field: string, detail: string): Error & {
78
+ /**
79
+ * The field a refusal names, as one value: `path` is the field path the sentence opens with, and `index` the attachment's
80
+ * position in the seat (0-based, the `[i]` of that path) — present exactly when the sentence names one attachment; a refusal of
81
+ * the seat as a whole (not a list, too many, a resume, the window) has no index. Built only by {@link SEAT_REF} /
82
+ * {@link entryRef} / {@link memberRef}, so the index and the path can never name two attachments.
83
+ */
84
+ export interface UserAttachmentFieldRef {
85
+ readonly path: string;
86
+ readonly index?: number;
87
+ }
88
+ /** The door's refusal: one code, the field named first in the sentence and again in `detail` ({@link UserAttachmentFieldRef}). */
89
+ export declare function userAttachmentRefusal(at: UserAttachmentFieldRef, problem: string): Error & {
78
90
  code: "config.user_attachment_invalid";
91
+ detail: UserAttachmentFieldRef;
79
92
  };
80
93
  /**
81
94
  * The door: screen the seat's value (synchronous; the caller's object is read once, member by member, before the
@@ -105,6 +118,13 @@ export declare function userAttachmentDeclarations(screened: readonly ScreenedUs
105
118
  * run on the captured values before any attachment is read or delivered. Throws `config.user_attachment_invalid`.
106
119
  */
107
120
  export declare function admitUserAttachmentImages(screened: readonly ScreenedUserAttachment[]): Promise<ReadonlyMap<number, ImageContent>>;
121
+ /** The transmission an attachment frame is (the read-state entry its delivery records carries it): when the frame leaves
122
+ * the request — a trim drops it — the entry retires with it. One spelling for the mint and every remover. */
123
+ export declare function attachmentTransmissionId(a: Pick<UserMessageAttachment, "inputId" | "ordinal">): string;
124
+ /** The transmissions a request-view drop took out: those of `view`'s messages that no message of `kept` still carries (a
125
+ * reused call id kept elsewhere is not gone). The guard trim retires the read-state entries they delivered (so the next
126
+ * Read sends the contents again); a later read of the same file is a transmission of its own and stays. */
127
+ export declare function droppedTransmissions(view: ReadonlyArray<AgentMessage>, kept: ReadonlyArray<AgentMessage>): string[];
108
128
  /** One minted frame: the trailing message's seed, and the commit its delivery owes (absent ⇒ nothing to commit). */
109
129
  export interface MintedAttachmentFrame {
110
130
  readonly seed: {
@@ -149,6 +169,40 @@ export declare function readObjectiveAttachments(prepared: Pick<import("./runner
149
169
  frames: MintedAttachmentFrame[];
150
170
  chars: number;
151
171
  }>;
172
+ /** What a compaction's restore reads with: the leg's one file reader (the Read tool's) and the run's synthetic-Read judge,
173
+ * and where a file it does not deliver is reported (a restored file's outcome has no wire face of its own). */
174
+ export interface CompactionRestoreSeat {
175
+ readonly reader: ModelFileReader;
176
+ readonly judge: SyntheticReadJudge;
177
+ readonly cwd: () => string | undefined;
178
+ readonly mark: string | undefined;
179
+ readonly counts: ReminderDisclosureCounts | undefined;
180
+ readonly signal: AbortSignal;
181
+ readonly report: (path: string, reason: string) => void;
182
+ }
183
+ /** One restore: the files to re-read (most recent first) and its bounds. */
184
+ export interface CompactionRestoreRequest {
185
+ readonly candidates: readonly string[];
186
+ readonly maxFiles: number;
187
+ /** What one file may deliver, in its own characters (before the Read's line numbers); an image the estimator's fixed
188
+ * weight × `charsPerToken`. A file over it, or whose frame would send more of its contents (line numbers included)
189
+ * than what is left of `totalChars`, is named, not sent. */
190
+ readonly perFileChars: number;
191
+ readonly totalChars: number;
192
+ readonly charsPerToken: number;
193
+ /** The read state of the context the summary leaves (`readFileStateAfterSummary`): what the reads dedup against. */
194
+ readonly dedupAgainst: ReadonlyMap<string, ReadEntry>;
195
+ }
196
+ /** The synthetic-Read judge's probe face for the restore (probe id `compaction-restore-visibility-probe`). */
197
+ export declare const COMPACTION_RESTORE_PROBE_FACE = "compaction-restore";
198
+ /**
199
+ * Re-read the files a compaction restores and mint their frames — each a Read on the model's behalf ({@link readRestored}),
200
+ * deduplicated against the context the summary leaves, so a file the summary takes out of view is never answered
201
+ * "unchanged"; the frame is the attachment seat's own. A file the context still holds is skipped; a file over
202
+ * its share is a frame that names it and says it is too large (no part of its contents); a refused file is a frame with
203
+ * the reason. Side-effect free toward the run: each frame carries the commit its delivery owes.
204
+ */
205
+ export declare function readCompactionRestore(seat: CompactionRestoreSeat, req: CompactionRestoreRequest): Promise<MintedAttachmentFrame[]>;
152
206
  /** The last attachment frame of the group the message `id` opens, or `id` when it has none (a `resumeAt` that keeps the
153
207
  * message keeps its group). The frames of one input are appended one after another under its message (each the child of
154
208
  * the one before), all carrying its input id. */