@sema-agent/core 7.55.0 → 7.56.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 (418) hide show
  1. package/CHANGELOG.md +513 -0
  2. package/dist/agents/cascade.js +1 -1
  3. package/dist/agents/cc-peer-directory.js +1 -0
  4. package/dist/agents/child-model-seat.d.ts +0 -11
  5. package/dist/agents/child-model-seat.js +0 -3
  6. package/dist/agents/list-agents-tool.d.ts +3 -1
  7. package/dist/agents/list-agents-tool.js +7 -7
  8. package/dist/agents/peer-directory.d.ts +22 -4
  9. package/dist/agents/peer-directory.js +24 -2
  10. package/dist/agents/peer-session-drain.js +2 -2
  11. package/dist/agents/repair-loop.js +2 -2
  12. package/dist/agents/send-message-tool.js +4 -4
  13. package/dist/agents/subagent.d.ts +6 -4
  14. package/dist/agents/subagent.js +64 -60
  15. package/dist/agents/tool-filter.d.ts +7 -5
  16. package/dist/agents/tool-filter.js +12 -9
  17. package/dist/agents/verify.d.ts +3 -2
  18. package/dist/agents/verify.js +3 -3
  19. package/dist/brain/anthropic.js +30 -73
  20. package/dist/brain/media-degrade.d.ts +18 -7
  21. package/dist/brain/media-degrade.js +13 -2
  22. package/dist/brain/model-capability.d.ts +37 -0
  23. package/dist/brain/model-capability.js +34 -0
  24. package/dist/brain/model-presets.d.ts +2 -8
  25. package/dist/brain/model-presets.js +1 -6
  26. package/dist/brain/open-responses.js +13 -26
  27. package/dist/brain/openai.js +14 -87
  28. package/dist/brain/reasoning-request.d.ts +96 -0
  29. package/dist/brain/reasoning-request.js +174 -0
  30. package/dist/brain/reasoning.d.ts +11 -11
  31. package/dist/brain/reasoning.js +4 -3
  32. package/dist/brain/request-params.d.ts +7 -4
  33. package/dist/brain/request-params.js +7 -4
  34. package/dist/brain/status-sink.d.ts +20 -0
  35. package/dist/brain/status-sink.js +7 -0
  36. package/dist/core/a2a.d.ts +2 -1
  37. package/dist/core/a2a.js +19 -13
  38. package/dist/core/agent-definition.d.ts +10 -0
  39. package/dist/core/allow-entry.d.ts +20 -13
  40. package/dist/core/allow-entry.js +26 -22
  41. package/dist/core/allow-rule-shadow.d.ts +3 -3
  42. package/dist/core/ask-origin.d.ts +64 -18
  43. package/dist/core/ask-origin.js +63 -23
  44. package/dist/core/ask-question.d.ts +51 -8
  45. package/dist/core/ask-question.js +3 -4
  46. package/dist/core/ask-unresolvable-notice.d.ts +8 -3
  47. package/dist/core/ask-unresolvable-notice.js +16 -2
  48. package/dist/core/checkpoint-generation.d.ts +53 -0
  49. package/dist/core/checkpoint-generation.js +35 -0
  50. package/dist/core/checkpoint-queries.d.ts +180 -0
  51. package/dist/core/checkpoint-queries.js +272 -0
  52. package/dist/core/checkpoint-requirements.d.ts +13 -1
  53. package/dist/core/checkpoint-requirements.js +4 -0
  54. package/dist/core/checkpoint-store.d.ts +88 -24
  55. package/dist/core/checkpoint-store.js +24 -9
  56. package/dist/core/cross-boundary-taint.d.ts +6 -5
  57. package/dist/core/cross-boundary-taint.js +1 -3
  58. package/dist/core/decision-receipt.d.ts +37 -3
  59. package/dist/core/decision-receipt.js +17 -17
  60. package/dist/core/delegation-not-started.d.ts +6 -0
  61. package/dist/core/delegation-not-started.js +17 -0
  62. package/dist/core/engine-attestation.d.ts +93 -0
  63. package/dist/core/engine-attestation.js +70 -0
  64. package/dist/core/engine-capabilities.d.ts +4 -1
  65. package/dist/core/engine-capabilities.js +1 -1
  66. package/dist/core/engine-notice.d.ts +30 -11
  67. package/dist/core/file-history-store.d.ts +90 -14
  68. package/dist/core/file-history-store.js +23 -15
  69. package/dist/core/gate-fold.d.ts +1 -1
  70. package/dist/core/gate-fold.js +22 -10
  71. package/dist/core/gate-lanes.js +73 -64
  72. package/dist/core/gate-outcome.d.ts +26 -5
  73. package/dist/core/gate-outcome.js +26 -0
  74. package/dist/core/governance-codes.d.ts +5 -1
  75. package/dist/core/governance-codes.js +6 -0
  76. package/dist/core/hooks.d.ts +17 -16
  77. package/dist/core/hooks.js +3 -1
  78. package/dist/core/host-floor.d.ts +128 -0
  79. package/dist/core/host-floor.js +206 -0
  80. package/dist/core/host-target.d.ts +38 -3
  81. package/dist/core/host-target.js +38 -5
  82. package/dist/core/mcp.d.ts +5 -1
  83. package/dist/core/mcp.js +67 -41
  84. package/dist/core/memory-engine/delegation-settlement.js +15 -24
  85. package/dist/core/memory-engine/engine.js +4 -4
  86. package/dist/core/memory-engine/layout.d.ts +60 -8
  87. package/dist/core/memory-engine/layout.js +65 -6
  88. package/dist/core/model-seat.d.ts +10 -3
  89. package/dist/core/mods/classic-events.d.ts +67 -0
  90. package/dist/core/mods/classic-events.js +1 -0
  91. package/dist/core/mods/dollar.d.ts +13 -0
  92. package/dist/core/mods/extension-call.d.ts +31 -0
  93. package/dist/core/mods/extension-call.js +43 -0
  94. package/dist/core/mods/kernel/dispatch.d.ts +20 -3
  95. package/dist/core/mods/kernel/dispatch.js +140 -69
  96. package/dist/core/mods/kernel/events.d.ts +47 -11
  97. package/dist/core/mods/kernel/events.js +66 -42
  98. package/dist/core/mods/kernel/index.d.ts +4 -4
  99. package/dist/core/mods/kernel/index.js +2 -2
  100. package/dist/core/mods/kernel/receive.d.ts +39 -5
  101. package/dist/core/mods/kernel/receive.js +290 -17
  102. package/dist/core/mods/kernel/registration.d.ts +33 -2
  103. package/dist/core/mods/kernel/registration.js +6 -7
  104. package/dist/core/mods/kernel/site-rules.d.ts +44 -16
  105. package/dist/core/mods/kernel/site-rules.js +24 -42
  106. package/dist/core/mods/spec-seats.d.ts +69 -0
  107. package/dist/core/mods/spec-seats.js +114 -0
  108. package/dist/core/mods/stations.d.ts +28 -8
  109. package/dist/core/mods/stations.js +29 -13
  110. package/dist/core/mods/tool-call.d.ts +79 -0
  111. package/dist/core/mods/tool-call.js +152 -0
  112. package/dist/core/namespaced-rule-name.d.ts +32 -38
  113. package/dist/core/namespaced-rule-name.js +29 -36
  114. package/dist/core/parent-spec-seat.d.ts +6 -1
  115. package/dist/core/parent-spec-seat.js +2 -0
  116. package/dist/core/park-selfcheck.js +1 -0
  117. package/dist/core/permission-rule-consent.d.ts +19 -0
  118. package/dist/core/permission-rule-consent.js +116 -26
  119. package/dist/core/permission-rule-model.d.ts +14 -3
  120. package/dist/core/permission-rule-model.js +39 -24
  121. package/dist/core/permission-rule-org.d.ts +6 -2
  122. package/dist/core/permission-rule-org.js +7 -3
  123. package/dist/core/permission-rule-provider.d.ts +5 -2
  124. package/dist/core/permission-rule-provider.js +41 -11
  125. package/dist/core/permission-rule-store.d.ts +3 -2
  126. package/dist/core/permission-rule-store.js +11 -2
  127. package/dist/core/permission-rule-sync.js +3 -2
  128. package/dist/core/permission-rule-syntax.d.ts +5 -4
  129. package/dist/core/permission-rule-syntax.js +2 -2
  130. package/dist/core/permission-rules.d.ts +4 -4
  131. package/dist/core/permission-rules.js +11 -20
  132. package/dist/core/persisted-rule-arms.d.ts +2 -2
  133. package/dist/core/persisted-rule-arms.js +10 -12
  134. package/dist/core/principal-name.d.ts +20 -0
  135. package/dist/core/principal-name.js +22 -0
  136. package/dist/core/prompt-section-seat.js +4 -6
  137. package/dist/core/protocol-http-auth.d.ts +26 -5
  138. package/dist/core/protocol-http-auth.js +137 -4
  139. package/dist/core/retired-keys.d.ts +16 -0
  140. package/dist/core/retired-keys.js +16 -4
  141. package/dist/core/rewrite-rejudge.d.ts +60 -0
  142. package/dist/core/rewrite-rejudge.js +36 -0
  143. package/dist/core/roles.d.ts +28 -1
  144. package/dist/core/roles.js +31 -19
  145. package/dist/core/rule-lane-reads.d.ts +20 -15
  146. package/dist/core/rule-lane-reads.js +45 -17
  147. package/dist/core/rule-owner.d.ts +3 -3
  148. package/dist/core/rule-owner.js +3 -2
  149. package/dist/core/runner/announce-once-ledger.d.ts +14 -0
  150. package/dist/core/runner/announce-once-ledger.js +5 -0
  151. package/dist/core/runner/assemble-result.d.ts +1 -0
  152. package/dist/core/runner/assemble-result.js +1 -1
  153. package/dist/core/runner/call-hook-stations.d.ts +3 -2
  154. package/dist/core/runner/caller-roster.d.ts +16 -4
  155. package/dist/core/runner/caller-roster.js +33 -6
  156. package/dist/core/runner/capability-withheld-seat.d.ts +5 -0
  157. package/dist/core/runner/capability-withheld-seat.js +24 -0
  158. package/dist/core/runner/classifier-ladder.d.ts +7 -9
  159. package/dist/core/runner/classifier-ladder.js +3 -3
  160. package/dist/core/runner/construction-doors.js +3 -0
  161. package/dist/core/runner/contracts.d.ts +28 -25
  162. package/dist/core/runner/cross-boundary-lane.d.ts +17 -13
  163. package/dist/core/runner/cross-boundary-lane.js +40 -27
  164. package/dist/core/runner/denial-limit-arms.d.ts +2 -2
  165. package/dist/core/runner/denial-limit-arms.js +1 -1
  166. package/dist/core/runner/file-history-request.d.ts +18 -0
  167. package/dist/core/runner/file-history-request.js +21 -13
  168. package/dist/core/runner/file-history-restore.d.ts +45 -0
  169. package/dist/core/runner/file-history-restore.js +46 -0
  170. package/dist/core/runner/gate-exit.d.ts +3 -3
  171. package/dist/core/runner/gate-exit.js +4 -3
  172. package/dist/core/runner/image.d.ts +7 -17
  173. package/dist/core/runner/image.js +9 -60
  174. package/dist/core/runner/permission-rule-lanes.d.ts +4 -4
  175. package/dist/core/runner/permission-rule-lanes.js +26 -10
  176. package/dist/core/runner/person-path-rows.d.ts +12 -9
  177. package/dist/core/runner/person-path-rows.js +18 -7
  178. package/dist/core/runner/prepare-ask-lane.d.ts +2 -2
  179. package/dist/core/runner/prepare-ask-lane.js +5 -2
  180. package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -6
  181. package/dist/core/runner/prepare-caps-and-workflow.js +4 -3
  182. package/dist/core/runner/prepare-config-doors.d.ts +29 -38
  183. package/dist/core/runner/prepare-config-doors.js +42 -25
  184. package/dist/core/runner/prepare-defer-classify.d.ts +4 -3
  185. package/dist/core/runner/prepare-defer-classify.js +7 -8
  186. package/dist/core/runner/prepare-file-history.d.ts +48 -8
  187. package/dist/core/runner/prepare-file-history.js +7 -39
  188. package/dist/core/runner/prepare-gate-stations.d.ts +1 -1
  189. package/dist/core/runner/prepare-gate-stations.js +10 -1
  190. package/dist/core/runner/prepare-hands-readface.d.ts +2 -8
  191. package/dist/core/runner/prepare-hands-readface.js +15 -14
  192. package/dist/core/runner/prepare-inherited-gate.d.ts +6 -3
  193. package/dist/core/runner/prepare-inherited-gate.js +5 -3
  194. package/dist/core/runner/prepare-memory-engine-session.js +1 -1
  195. package/dist/core/runner/prepare-park-ask.js +5 -5
  196. package/dist/core/runner/prepare-policy-chain.d.ts +6 -3
  197. package/dist/core/runner/prepare-policy-chain.js +65 -72
  198. package/dist/core/runner/prepare-prompt-assembly.d.ts +5 -7
  199. package/dist/core/runner/prepare-prompt-assembly.js +10 -8
  200. package/dist/core/runner/prepare-prompt-inputs.d.ts +11 -9
  201. package/dist/core/runner/prepare-prompt-inputs.js +3 -5
  202. package/dist/core/runner/prepare-protocol-tools.d.ts +2 -0
  203. package/dist/core/runner/prepare-protocol-tools.js +3 -3
  204. package/dist/core/runner/prepare-safety-scan.d.ts +1 -1
  205. package/dist/core/runner/prepare-safety-scan.js +0 -17
  206. package/dist/core/runner/prepare-suspend-saga.d.ts +2 -0
  207. package/dist/core/runner/prepare-suspend-saga.js +5 -6
  208. package/dist/core/runner/prepare-task.d.ts +1 -1
  209. package/dist/core/runner/prepare-task.js +29 -20
  210. package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +7 -4
  211. package/dist/core/runner/prepare-tool-disclosure-mount.js +20 -16
  212. package/dist/core/runner/prepare-turn-wiring.d.ts +0 -4
  213. package/dist/core/runner/prepare-turn-wiring.js +2 -7
  214. package/dist/core/runner/prepare-wiring-manifest.d.ts +6 -2
  215. package/dist/core/runner/prepare-wiring-manifest.js +3 -3
  216. package/dist/core/runner/resume-admission.js +1 -1
  217. package/dist/core/runner/resume-apply.js +11 -12
  218. package/dist/core/runner/resume-checkpoint-screen.js +3 -0
  219. package/dist/core/runner/resume-claim.d.ts +4 -2
  220. package/dist/core/runner/resume-claim.js +15 -8
  221. package/dist/core/runner/retired-runner-deps.js +1 -0
  222. package/dist/core/runner/rewind-files.d.ts +15 -0
  223. package/dist/core/runner/rewind-files.js +132 -0
  224. package/dist/core/runner/run-attachment-seats.js +2 -1
  225. package/dist/core/runner/run-brain-sinks.d.ts +4 -1
  226. package/dist/core/runner/run-brain-sinks.js +4 -2
  227. package/dist/core/runner/run-harness-handlers.js +12 -4
  228. package/dist/core/runner/run-leg.d.ts +1 -1
  229. package/dist/core/runner/run-leg.js +30 -18
  230. package/dist/core/runner/run-settle-and-teardown.js +2 -1
  231. package/dist/core/runner/run-turn-boundary.js +1 -10
  232. package/dist/core/runner/runtask.d.ts +3 -0
  233. package/dist/core/runner/runtask.js +8 -9
  234. package/dist/core/runner/session-read-file-states.d.ts +15 -0
  235. package/dist/core/runner/session-read-file-states.js +28 -0
  236. package/dist/core/runner/session-rule-policy.js +4 -3
  237. package/dist/core/runner/shell-env-withheld.d.ts +33 -0
  238. package/dist/core/runner/shell-env-withheld.js +51 -0
  239. package/dist/core/runner/skills-seat.js +6 -2
  240. package/dist/core/runner/stream-settle-backstop.js +1 -1
  241. package/dist/core/runner/sub-agent-deny-lists.js +4 -7
  242. package/dist/core/runner/synthetic-tools.d.ts +6 -0
  243. package/dist/core/runner/synthetic-tools.js +4 -1
  244. package/dist/core/runner/tool-disclosure.d.ts +10 -12
  245. package/dist/core/runner/tool-disclosure.js +1 -3
  246. package/dist/core/runner/tool-end-body.d.ts +1 -1
  247. package/dist/core/runner/tool-end-body.js +10 -9
  248. package/dist/core/runner/tool-not-executed.d.ts +5 -0
  249. package/dist/core/runner/tool-not-executed.js +11 -0
  250. package/dist/core/runner/tool-occurrence.d.ts +8 -0
  251. package/dist/core/runner/tool-occurrence.js +7 -0
  252. package/dist/core/runner/turn-attachments.d.ts +33 -15
  253. package/dist/core/runner/turn-attachments.js +62 -37
  254. package/dist/core/runner-deps.d.ts +5 -5
  255. package/dist/core/safety-axis-vocab.d.ts +6 -4
  256. package/dist/core/safety-axis-vocab.js +6 -5
  257. package/dist/core/safety-merge-corpus.js +11 -3
  258. package/dist/core/secret-env.d.ts +26 -3
  259. package/dist/core/secret-env.js +44 -8
  260. package/dist/core/select-model.js +3 -3
  261. package/dist/core/session-policy-store.d.ts +27 -15
  262. package/dist/core/session-policy-store.js +156 -36
  263. package/dist/core/session-store.d.ts +29 -10
  264. package/dist/core/session-store.js +51 -19
  265. package/dist/core/session.d.ts +82 -16
  266. package/dist/core/session.js +53 -0
  267. package/dist/core/shell-read-silence.d.ts +11 -12
  268. package/dist/core/shell-read-silence.js +9 -5
  269. package/dist/core/shell-run-candidates.js +3 -1
  270. package/dist/core/shell-wrapper-projection.js +1 -1
  271. package/dist/core/shell-wrapper-table.d.ts +14 -7
  272. package/dist/core/shell-wrapper-table.js +5 -4
  273. package/dist/core/side-query.js +10 -1
  274. package/dist/core/skill-grant.d.ts +7 -2
  275. package/dist/core/skill-grant.js +5 -0
  276. package/dist/core/skills-directory.js +6 -2
  277. package/dist/core/store-contracts/checkpoint-store-contract.d.ts +11 -1
  278. package/dist/core/store-contracts/checkpoint-store-contract.js +140 -2
  279. package/dist/core/store-contracts/file-history-store-contract.js +31 -1
  280. package/dist/core/store-contracts/peer-directory-contract.d.ts +7 -2
  281. package/dist/core/store-contracts/peer-directory-contract.js +14 -2
  282. package/dist/core/store-contracts/session-repo-contract.js +51 -0
  283. package/dist/core/store-contracts/session-store-contract.d.ts +2 -1
  284. package/dist/core/store-contracts/session-store-contract.js +150 -14
  285. package/dist/core/stub-env.d.ts +2 -0
  286. package/dist/core/stub-env.js +1 -0
  287. package/dist/core/synthetic-read-verdict.js +3 -3
  288. package/dist/core/task-event.d.ts +32 -4
  289. package/dist/core/task-notification.d.ts +16 -12
  290. package/dist/core/task-registry.d.ts +9 -0
  291. package/dist/core/task-registry.js +11 -1
  292. package/dist/core/task-result.d.ts +18 -0
  293. package/dist/core/task-spec.d.ts +18 -13
  294. package/dist/core/tighten-task-spec.js +2 -1
  295. package/dist/core/tool-catalog-entries.d.ts +17 -0
  296. package/dist/core/tool-catalog-entries.js +13 -2
  297. package/dist/core/tool-check-reading.d.ts +11 -0
  298. package/dist/core/tool-check-reading.js +11 -6
  299. package/dist/core/tool-model-gate.d.ts +2 -2
  300. package/dist/core/tool-name-aliases.d.ts +16 -16
  301. package/dist/core/tool-name-aliases.js +13 -19
  302. package/dist/core/tool-name-readings.d.ts +5 -35
  303. package/dist/core/tool-name-readings.js +1 -9
  304. package/dist/core/tool-policy.d.ts +68 -198
  305. package/dist/core/tool-policy.js +149 -198
  306. package/dist/core/tool-result-store.js +3 -0
  307. package/dist/core/tool-roster.d.ts +14 -19
  308. package/dist/core/tool-roster.js +11 -44
  309. package/dist/core/tool-spec-members.js +7 -2
  310. package/dist/core/tool-spec.d.ts +19 -11
  311. package/dist/core/tools.js +49 -9
  312. package/dist/core/trace.d.ts +2 -2
  313. package/dist/core/types.d.ts +1 -1
  314. package/dist/core/user-attachment.d.ts +8 -1
  315. package/dist/core/user-attachment.js +64 -4
  316. package/dist/core/wiring-manifest.d.ts +9 -0
  317. package/dist/core/wiring-manifest.js +1 -0
  318. package/dist/core/workflow-journal-store.js +1 -1
  319. package/dist/engine/compaction/compaction.js +3 -2
  320. package/dist/engine/execution-env/node-execution-env.d.ts +7 -3
  321. package/dist/engine/execution-env/node-execution-env.js +11 -2
  322. package/dist/engine/harness/agent-harness.d.ts +25 -1
  323. package/dist/engine/harness/agent-harness.js +54 -7
  324. package/dist/engine/harness/types.d.ts +29 -2
  325. package/dist/engine/llm/types.d.ts +28 -11
  326. package/dist/engine/loop/agent-loop.d.ts +22 -0
  327. package/dist/engine/loop/agent-loop.js +16 -26
  328. package/dist/engine/loop/types.d.ts +16 -6
  329. package/dist/engine/session/memory-repo.d.ts +9 -2
  330. package/dist/engine/session/memory-repo.js +11 -1
  331. package/dist/engine/session/repo-utils.d.ts +6 -5
  332. package/dist/engine/session/repo-utils.js +14 -6
  333. package/dist/index.d.ts +22 -10
  334. package/dist/index.js +15 -7
  335. package/dist/internal/harness-types.d.ts +1 -1
  336. package/dist/internal/llm.d.ts +1 -1
  337. package/dist/orchestration/run-workflow-tool.d.ts +6 -4
  338. package/dist/orchestration/run-workflow-tool.js +5 -3
  339. package/dist/orchestration/workflow.d.ts +3 -0
  340. package/dist/orchestration/workflow.js +36 -18
  341. package/dist/prompt-assembly/artifact.d.ts +2 -2
  342. package/dist/prompt-assembly/artifact.js +5 -3
  343. package/dist/prompt-assembly/assemble.d.ts +3 -2
  344. package/dist/prompt-assembly/assemble.js +1 -1
  345. package/dist/prompt-assembly/catalog/schema.d.ts +43 -12
  346. package/dist/prompt-assembly/catalog/schema.js +34 -2
  347. package/dist/prompt-assembly/catalog/sections.js +0 -1
  348. package/dist/prompt-assembly/composer.d.ts +3 -1
  349. package/dist/prompt-assembly/composer.js +1 -1
  350. package/dist/prompt-assembly/event-registry.js +1 -0
  351. package/dist/prompt-assembly/overlay.js +3 -3
  352. package/dist/prompt-assembly/renderers.d.ts +1 -1
  353. package/dist/prompt-assembly/renderers.js +0 -3
  354. package/dist/prompt-assembly/role-base.d.ts +15 -0
  355. package/dist/prompt-assembly/role-base.js +9 -0
  356. package/dist/prompt-assembly/select.d.ts +39 -14
  357. package/dist/prompt-assembly/select.js +47 -16
  358. package/dist/prompt-assembly/sugar.d.ts +17 -11
  359. package/dist/prompt-assembly/sugar.js +8 -3
  360. package/dist/prompt-assembly/tool-catalog.d.ts +37 -3
  361. package/dist/prompt-assembly/tool-catalog.js +114 -4
  362. package/dist/prompt-assembly/turn-snapshot.d.ts +4 -10
  363. package/dist/prompt-assembly/turn-snapshot.js +0 -3
  364. package/dist/prompt-assembly/types.d.ts +0 -7
  365. package/dist/scenarios/full-body.d.ts +11 -11
  366. package/dist/scenarios/full-body.js +4 -3
  367. package/dist/shell/lex.js +10 -1
  368. package/dist/stores/file/adoption/adopt.js +4 -3
  369. package/dist/stores/file/adoption/marker.js +3 -2
  370. package/dist/stores/file/checkpoint-store.d.ts +21 -0
  371. package/dist/stores/file/checkpoint-store.js +38 -6
  372. package/dist/stores/file/file-history-store.js +6 -7
  373. package/dist/stores/file/index.js +2 -1
  374. package/dist/stores/file/permission-rule-adopt.js +4 -3
  375. package/dist/stores/file/permission-rule-store.js +11 -5
  376. package/dist/stores/file/session-store.d.ts +29 -6
  377. package/dist/stores/file/session-store.js +42 -50
  378. package/dist/tools/artifact/artifact-tool.js +3 -2
  379. package/dist/tools/fs/bash-program-position.d.ts +19 -2
  380. package/dist/tools/fs/bash-program-position.js +56 -9
  381. package/dist/tools/fs/fs-bash.js +5 -5
  382. package/dist/tools/fs/fs-glob.d.ts +86 -0
  383. package/dist/tools/fs/fs-glob.js +226 -0
  384. package/dist/tools/fs/fs-read.js +14 -14
  385. package/dist/tools/fs/fs-search-tools.js +7 -7
  386. package/dist/tools/fs/pattern-kill-guard.d.ts +22 -0
  387. package/dist/tools/fs/pattern-kill-guard.js +397 -0
  388. package/dist/tools/fs/pdf.d.ts +9 -6
  389. package/dist/tools/fs/pdf.js +3 -3
  390. package/dist/tools/fs/program-read-model.d.ts +57 -7
  391. package/dist/tools/fs/program-read-model.js +11 -1
  392. package/dist/tools/fs/program-read-model.rows.js +78 -21
  393. package/dist/tools/fs/read-deny-home.js +3 -2
  394. package/dist/tools/fs/removal-targets.d.ts +17 -7
  395. package/dist/tools/fs/removal-targets.js +47 -20
  396. package/dist/tools/fs/search.d.ts +10 -0
  397. package/dist/tools/fs/search.js +20 -26
  398. package/dist/tools/fs/shell-read-argv.js +89 -12
  399. package/dist/tools/fs/shell-read-bindings.d.ts +31 -0
  400. package/dist/tools/fs/shell-read-bindings.js +41 -0
  401. package/dist/tools/fs/shell-read-check.js +6 -19
  402. package/dist/tools/fs/shell-read-environment.d.ts +5 -1
  403. package/dist/tools/fs/shell-read-environment.js +3 -2
  404. package/dist/tools/fs/shell-read-establish.d.ts +15 -0
  405. package/dist/tools/fs/shell-read-establish.js +19 -20
  406. package/dist/tools/fs/shell-read-plan.js +24 -16
  407. package/dist/tools/fs/shell-read-start.d.ts +6 -1
  408. package/dist/tools/fs/shell-read-write-targets.d.ts +5 -1
  409. package/dist/tools/fs/shell-read-write-targets.js +2 -3
  410. package/dist/tools/fs/shell-reentry-text.d.ts +9 -0
  411. package/dist/tools/fs/shell-reentry-text.js +40 -2
  412. package/dist/tools/todo.js +63 -63
  413. package/dist/tools/web.d.ts +19 -14
  414. package/dist/tools/web.js +38 -55
  415. package/package.json +1 -1
  416. package/test/export-surface.snapshot.json +143 -5
  417. package/wire-changes/core@7.56.0.json +3891 -0
  418. package/wire-changes/mods-kernel@7.56.0.json +303 -0
@@ -0,0 +1,174 @@
1
+ import { capabilityHeld } from "./model-capability.js";
2
+ import { headerListEntries, lockHeader, takeHeaderSpellings } from "./request-params.js";
3
+ import { MIN_THINKING_TOKENS, RESPONSES_APIS, budgetCapSkipsThinking, declaredEffortLevels, declaredOffSpelling, mintEffortWireValue, reasoningBudgetShare, reasoningRequestCarried, resolveEffort, thinkingOffSpelled, } from "./reasoning.js";
4
+ export function lowestReasoningSeat(model) {
5
+ return thinkingOffSpelled(model) ? "off" : "low";
6
+ }
7
+ const BETA_EFFORT = "effort-2025-11-24";
8
+ const BETA_CONTEXT_MANAGEMENT = "context-management-2025-06-27";
9
+ const BETA_INTERLEAVED_THINKING = "interleaved-thinking-2025-05-14";
10
+ function put(body, key, value) {
11
+ body[key] = value;
12
+ return undefined;
13
+ }
14
+ function withTemplateKwarg(body, enabled) {
15
+ const kwargs = (typeof body.chat_template_kwargs === "object" && body.chat_template_kwargs) || {};
16
+ return put(body, "chat_template_kwargs", { ...kwargs, enable_thinking: enabled });
17
+ }
18
+ function withEffort(body, effort, supportsEffort) {
19
+ if (!supportsEffort || effort === undefined)
20
+ return undefined;
21
+ body.reasoning_effort = effort;
22
+ return effort;
23
+ }
24
+ const COMPLETIONS_DIALECT = {
25
+ openai: {
26
+ off: (body, model) => {
27
+ const spelling = declaredOffSpelling(model);
28
+ return spelling === undefined ? undefined : withEffort(body, spelling, true);
29
+ },
30
+ on: withEffort,
31
+ },
32
+ openrouter: {
33
+ off: (body) => put(body, "reasoning", { enabled: false }),
34
+ on: (body, effort) => {
35
+ put(body, "reasoning", { effort });
36
+ return effort;
37
+ },
38
+ },
39
+ deepseek: {
40
+ off: (body) => put(body, "thinking", { type: "disabled" }),
41
+ on: (body, effort, supportsEffort) => {
42
+ put(body, "thinking", { type: "enabled" });
43
+ return withEffort(body, effort, supportsEffort);
44
+ },
45
+ },
46
+ together: {
47
+ off: (body) => put(body, "reasoning", { enabled: false }),
48
+ on: (body, effort, supportsEffort) => {
49
+ put(body, "reasoning", { enabled: true });
50
+ return withEffort(body, effort, supportsEffort);
51
+ },
52
+ },
53
+ qwen: { off: (body) => put(body, "enable_thinking", false), on: (body) => put(body, "enable_thinking", true) },
54
+ zai: { off: (body) => put(body, "enable_thinking", false), on: (body) => put(body, "enable_thinking", true) },
55
+ "qwen-chat-template": { off: (body) => withTemplateKwarg(body, false), on: (body) => withTemplateKwarg(body, true) },
56
+ };
57
+ function completionsDialectOf(format) {
58
+ return typeof format === "string" && Object.prototype.hasOwnProperty.call(COMPLETIONS_DIALECT, format) ? COMPLETIONS_DIALECT[format] : undefined;
59
+ }
60
+ const bodyOnly = (body, effort) => ({ body, headers: {}, effort, wireFacts: undefined });
61
+ function applyCompletions(input, body) {
62
+ const { model, level } = input;
63
+ const compat = (model.compat ?? {});
64
+ const dialect = completionsDialectOf(compat.thinkingFormat ?? "openai");
65
+ if (capabilityHeld(model, "reasoning") && level === "off")
66
+ return bodyOnly(body, dialect?.off(body, model));
67
+ if (!reasoningRequestCarried(model, level))
68
+ return bodyOnly(body);
69
+ const supportsEffort = compat.supportsReasoningEffort ?? true;
70
+ const wire = mintEffortWireValue(level, model, compat.reasoningEffortLevels).wireValue;
71
+ return bodyOnly(body, dialect?.on(body, wire, supportsEffort));
72
+ }
73
+ function applyResponses(input, body) {
74
+ const { model, level } = input;
75
+ const effort = responsesEffort(model, level);
76
+ if (effort !== undefined)
77
+ body.reasoning = { effort };
78
+ return bodyOnly(body, effort);
79
+ }
80
+ function responsesEffort(model, level) {
81
+ if (capabilityHeld(model, "reasoning") && level === "off")
82
+ return declaredOffSpelling(model);
83
+ const compat = (model.compat ?? {});
84
+ if (compat.supportsReasoningEffort === false)
85
+ return undefined;
86
+ if (!reasoningRequestCarried(model, level))
87
+ return undefined;
88
+ return mintEffortWireValue(level, model, compat.reasoningEffortLevels).wireValue;
89
+ }
90
+ function thinkingBudget(maxTokens, share, fixed, hardCap) {
91
+ const max = hardCap ? maxTokens : Math.max(maxTokens, MIN_THINKING_TOKENS * 2);
92
+ const want = fixed ?? Math.floor(max * share);
93
+ const budget = Math.min(Math.max(MIN_THINKING_TOKENS, want), max - 1);
94
+ return { max, budget };
95
+ }
96
+ function applyMessages(input, body) {
97
+ const { model, level } = input;
98
+ const compat = (model.compat ?? {});
99
+ let wireFacts;
100
+ let thinkingOn = false;
101
+ if (reasoningRequestCarried(model, level)) {
102
+ if (compat.thinkingMode === "adaptive") {
103
+ body.thinking = { type: "adaptive" };
104
+ thinkingOn = true;
105
+ }
106
+ else {
107
+ if (body.max_tokens === undefined || body.max_tokens === null) {
108
+ throw new TypeError("applyReasoningToRequest: the Messages budget form needs a body.max_tokens (it sizes the thinking budget)");
109
+ }
110
+ const maxTokens = body.max_tokens;
111
+ const hardCap = input.budget?.capIsHard ?? true;
112
+ wireFacts = { outputCapTokens: maxTokens, hardOutputCap: hardCap };
113
+ if (budgetCapSkipsThinking(wireFacts.outputCapTokens, wireFacts.hardOutputCap)) {
114
+ delete body.thinking;
115
+ }
116
+ else {
117
+ const share = input.budget?.share ?? reasoningBudgetShare(level);
118
+ const { max, budget } = thinkingBudget(maxTokens, share, input.budget?.tokens, hardCap);
119
+ if (!Number.isFinite(Number(max)) || !Number.isFinite(budget)) {
120
+ const shown = (value) => (typeof value === "string" ? JSON.stringify(value) : String(value));
121
+ throw new TypeError(`applyReasoningToRequest: the Messages budget form cannot size a thinking budget from body.max_tokens ${shown(body.max_tokens)}, ` +
122
+ `budget.share ${shown(share)}, budget.tokens ${shown(input.budget?.tokens)} (cap ${shown(max)}, budget ${shown(budget)}); each must read as a finite number`);
123
+ }
124
+ body.max_tokens = max;
125
+ body.thinking = { type: "enabled", budget_tokens: budget };
126
+ thinkingOn = true;
127
+ }
128
+ }
129
+ if (thinkingOn)
130
+ delete body.temperature;
131
+ }
132
+ else if (capabilityHeld(model, "reasoning") && level === "off" && compat.thinkingMode !== "adaptive") {
133
+ body.thinking = { type: "disabled" };
134
+ }
135
+ const betas = [];
136
+ let effort;
137
+ const declaredEffort = declaredEffortLevels(compat.effortLevels);
138
+ if (declaredEffort !== undefined && reasoningRequestCarried(model, level)) {
139
+ const { effective } = resolveEffort(level, declaredEffort);
140
+ effort = effective === "minimal" ? "low" : effective;
141
+ body.output_config = { effort };
142
+ betas.push(BETA_EFFORT);
143
+ }
144
+ if (compat.contextManagement && thinkingOn) {
145
+ body.context_management = { edits: [{ type: "clear_thinking_20251015", keep: "all" }] };
146
+ betas.push(BETA_CONTEXT_MANAGEMENT);
147
+ }
148
+ if (compat.interleavedThinking)
149
+ betas.push(BETA_INTERLEAVED_THINKING);
150
+ return { body, headers: betas.length > 0 ? { "anthropic-beta": betas.join(",") } : {}, effort, wireFacts };
151
+ }
152
+ export function applyReasoningToRequest(input) {
153
+ const body = { ...input.body };
154
+ if (input.api === "anthropic-messages")
155
+ return applyMessages(input, body);
156
+ if (RESPONSES_APIS.has(input.api))
157
+ return applyResponses(input, body);
158
+ return applyCompletions(input, body);
159
+ }
160
+ export function mergeReasoningHeaders(headers, patch) {
161
+ for (const [name, value] of Object.entries(patch)) {
162
+ const lower = name.toLowerCase();
163
+ if (lower !== "anthropic-beta") {
164
+ lockHeader(headers, lower, value);
165
+ continue;
166
+ }
167
+ const present = takeHeaderSpellings(headers, lower).flatMap((held) => headerListEntries(held));
168
+ for (const beta of headerListEntries(value)) {
169
+ if (!present.includes(beta))
170
+ present.push(beta);
171
+ }
172
+ headers[lower] = present.join(",");
173
+ }
174
+ }
@@ -18,8 +18,8 @@ export type ReasoningIntensity = ThinkingLevel;
18
18
  export declare function isThinkingLevel(v: unknown): v is ThinkingLevel;
19
19
  /**
20
20
  * THE thinking-request ENTRY predicate — does this request enter an applier's emission path at all?
21
- * One conjunction, three arms: the model declares reasoning (TRUTHINESS — the adapters' own
22
- * judgment, see the r5 note in {@link resolveReasoning}), the requested value is a real
21
+ * One conjunction, three arms: the model holds reasoning (`capabilityHeld`, the one capability reading —
22
+ * a declaration of the wrong shape throws there instead of reading by truthiness), the requested value is a real
23
23
  * {@link ThinkingLevel} (an out-of-contract value — a typo'd tier, a caller's own enum — reads as
24
24
  * ABSENCE, never as a declared tier), and it is not the explicit `"off"`.
25
25
  *
@@ -29,8 +29,8 @@ export declare function isThinkingLevel(v: unknown): v is ThinkingLevel;
29
29
  * their own reporting shape (the `graded:false` intent-echo family, each pinned with its rationale
30
30
  * where it lives); this predicate only closes the gate the three appliers used to re-spell.
31
31
  *
32
- * Single-sourced here because every wire applier (openai.ts `applyThinking`, anthropic.ts's thinking
33
- * + effort arms, open-responses.ts `resolveWireEffort`) would otherwise re-spell the same three
32
+ * Single-sourced here because every wire applier (the completions, Messages and Responses arms of
33
+ * `applyReasoningToRequest`, in reasoning-request.ts) would otherwise re-spell the same three
34
34
  * conjuncts while the REPORTING resolver ({@link resolveReasoning}) mirrored one of them, so a
35
35
  * garbage tier puts ZERO parameters on the wire while the resolution claims a clamped-to-minimal
36
36
  * gradient. A predicate the appliers and the reporter both call cannot drift.
@@ -58,7 +58,7 @@ export type ReasoningFormat = "openai" | "openrouter" | "deepseek" | "together"
58
58
  * `reasoning_effort` path (thinking FORM is `thinkingMode`; effort carries the intensity). */
59
59
  | "effort"
60
60
  /** OpenAI Responses API (`openai-responses` / `azure-openai-responses`, design/163): the tier rides
61
- * the NESTED `reasoning: { effort }` request field (open-responses.ts `resolveWireEffort`), clamped
61
+ * the NESTED `reasoning: { effort }` request field (the Responses arm of `applyReasoningToRequest`), clamped
62
62
  * by the same {@link resolveEffort} against `compat.reasoningEffortLevels` — NOT the completions
63
63
  * top-level `reasoning_effort` the `"openai"` tag names. #325 review r3: before this member the
64
64
  * resolver fell through to the completions default and labeled Responses resolutions `"openai"`. */
@@ -127,7 +127,7 @@ export declare function declaredOffSpelling(model: OffCapabilityModel): string |
127
127
  * `reasoning:{enabled:false}` all spell it; the effort-only wires (stock openai completions, the Responses
128
128
  * lane) spell it only through a deployment-declared off spelling ({@link declaredOffSpelling}).
129
129
  *
130
- * A model whose `reasoning` is FALSY spells NOTHING: every applier returns before writing any key for it, so
130
+ * A model that does not hold reasoning (declared false, or undeclared — `capabilityHeld`) spells NOTHING: every applier returns before writing any key for it, so
131
131
  * the request is the gateway's own default — and a default-on gateway thinks regardless (three of four live
132
132
  * endpoints, 2026-09-15). This arm used to answer `true` ("a non-reasoning model never thinks"): the engine
133
133
  * may size a request by what it SENT, never by what it hopes a gateway does when told nothing. What this
@@ -172,8 +172,8 @@ export interface ReasoningWireFacts {
172
172
  export declare function declaredEffortLevels(v: unknown): readonly ThinkingLevel[] | undefined;
173
173
  /**
174
174
  * The effort-lane WIRE-VALUE mint — clamp ({@link resolveEffort}) + the `Model.thinkingLevelMap`
175
- * translation in ONE place, consumed by both completions-family appliers (openai.ts `applyThinking`,
176
- * open-responses.ts `resolveWireEffort`) AND the reporting dispatch ({@link resolveReasoning}'s
175
+ * translation in ONE place, consumed by both effort-lane arms of `applyReasoningToRequest` (completions,
176
+ * Responses) AND the reporting dispatch ({@link resolveReasoning}'s
177
177
  * arms), so the value that reaches the wire and the resolution a trace/result face claims are two
178
178
  * reads of one computation, never parallel re-derivations. Map semantics (the field's contract): a
179
179
  * MISSING key ⇒ provider default (the clamped tier name as-is); a STRING ⇒ that provider-specific
@@ -200,7 +200,7 @@ export interface ResolvedReasoning extends ReasoningResolution {
200
200
  endpoint: string;
201
201
  /**
202
202
  * Present (true) only when the request never CARRIES at all: {@link reasoningRequestCarried} false
203
- * on a non-"off" request — the model declares NO reasoning capability (`Model.reasoning` falsy),
203
+ * on a non-"off" request — the model does not hold reasoning (`capabilityHeld`: declared false or undeclared),
204
204
  * OR the requested value is not a valid {@link ThinkingLevel} (an out-of-contract tier every wire
205
205
  * applier reads as ABSENCE — the same three-conjunct gate all of them share) — or, with
206
206
  * {@link ReasoningWireFacts} supplied, the anthropic budget path's cap-wins skip
@@ -212,7 +212,7 @@ export interface ResolvedReasoning extends ReasoningResolution {
212
212
  * reason at its own tier — the brains deliberately send no disable key for a model declared
213
213
  * non-reasoning, so the engine cannot claim a measured off there; `format` tells a consumer which
214
214
  * family applies (on every other format, absence is the closest the wire has to off — see
215
- * applyThinking's own contract). `format`/`endpoint` report the family that WOULD have carried the
215
+ * the completions arm's own contract). `format`/`endpoint` report the family that WOULD have carried the
216
216
  * tier (the why-shape a consumer diagnoses with, not a claim about the request). Absent on every
217
217
  * reasoning-capable resolution, so existing consumers see byte-identical objects. Loud-bad-values
218
218
  * rule: the one arm where the request evaporates must not be the one arm with no report.
@@ -240,7 +240,7 @@ export interface ResolvedReasoning extends ReasoningResolution {
240
240
  * drops the value — trace/result-face drift.
241
241
  *
242
242
  * - A request that never CARRIES ({@link reasoningRequestCarried} false on a non-"off" value: the model's
243
- * `reasoning` capability flag is FALSY, or the requested value is not a valid tier — no brain emits any
243
+ * `reasoning` capability is not held, or the requested value is not a valid tier — no brain emits any
244
244
  * thinking parameter for either, whatever the format) → `effective:"off"`, `graded:false`, `clamped:true`,
245
245
  * `dropped:true` — the loud-drop arm. Describing the capability dispatch instead would report a
246
246
  * resolution the request never carried, leaving the one arm where the request evaporates as the one
@@ -1,3 +1,4 @@
1
+ import { capabilityHeld } from "./model-capability.js";
1
2
  const RANK = {
2
3
  off: 0,
3
4
  minimal: 1,
@@ -11,7 +12,7 @@ export function isThinkingLevel(v) {
11
12
  return typeof v === "string" && Object.prototype.hasOwnProperty.call(RANK, v);
12
13
  }
13
14
  export function reasoningRequestCarried(model, reasoning) {
14
- return !!model.reasoning && isThinkingLevel(reasoning) && reasoning !== "off";
15
+ return capabilityHeld(model, "reasoning") && isThinkingLevel(reasoning) && reasoning !== "off";
15
16
  }
16
17
  export function rankOf(level) {
17
18
  return RANK[level];
@@ -31,7 +32,7 @@ export function declaredOffSpelling(model) {
31
32
  return typeof mapped === "string" && mapped !== "" ? mapped : undefined;
32
33
  }
33
34
  export function thinkingOffSpelled(model) {
34
- if (!model.reasoning)
35
+ if (!capabilityHeld(model, "reasoning"))
35
36
  return false;
36
37
  const compat = (model.compat ?? {});
37
38
  if (model.api === "anthropic-messages")
@@ -101,7 +102,7 @@ function dispatchReasoning(requested, model, facts) {
101
102
  return { ...mint.resolution, format, endpoint };
102
103
  }
103
104
  export function reasoningEffortLevelsOf(model) {
104
- if (!model.reasoning)
105
+ if (!capabilityHeld(model, "reasoning"))
105
106
  return undefined;
106
107
  const compat = (model.compat ?? {});
107
108
  if (model.api === "anthropic-messages") {
@@ -122,12 +122,15 @@ export declare function applyExtraBody(body: Record<string, unknown>, model: Pic
122
122
  export declare function lockHeader(headers: Record<string, string>, lowerName: string, value: string): void;
123
123
  /**
124
124
  * #343 (review r4) — case-fold READ-AND-CLAIM for an AUGMENTABLE structural header (`anthropic-beta`):
125
- * returns the current value under whatever spelling the user bag carried and deletes that spelling,
126
- * so the caller's canonical lowercase write REPLACES it instead of duplicating beside it (the
125
+ * returns the value under EVERY spelling the bag carried, in key order, and deletes them all, so the
126
+ * caller's canonical lowercase write REPLACES them instead of duplicating beside them (the
127
127
  * read-modify-write used to key the read by the exact lowercase name and miss `Anthropic-Beta`,
128
- * losing the user's betas from the merge AND double-sending the header).
128
+ * losing the user's betas from the merge AND double-sending the header). A spelling is claimed whatever
129
+ * it holds — its value is returned as it is, so a spelling holding `undefined` does not end the claim.
129
130
  */
130
- export declare function takeHeaderCasefold(headers: Record<string, string>, lowerName: string): string | undefined;
131
+ export declare function takeHeaderSpellings(headers: Record<string, string>, lowerName: string): unknown[];
132
+ /** The entries of a comma-list header value (`" a , b,,c"` → `a`, `b`, `c`); a value that is not a string carries none. */
133
+ export declare function headerListEntries(value: unknown): string[];
131
134
  /** A caller's header bag read ONCE, into a plain copy of its own enumerable entries — what a request build hands both
132
135
  * the route law (which credential rides, and its identity) and the merge (what goes on the wire), so a bag whose getters
133
136
  * or keys answer differently on a second read cannot be judged as one bag and sent as another. */
@@ -92,15 +92,18 @@ export function lockHeader(headers, lowerName, value) {
92
92
  }
93
93
  headers[lowerName] = value;
94
94
  }
95
- export function takeHeaderCasefold(headers, lowerName) {
95
+ export function takeHeaderSpellings(headers, lowerName) {
96
+ const values = [];
96
97
  for (const k of Object.keys(headers)) {
97
98
  if (k.toLowerCase() === lowerName) {
98
- const v = headers[k];
99
+ values.push(headers[k]);
99
100
  delete headers[k];
100
- return v;
101
101
  }
102
102
  }
103
- return undefined;
103
+ return values;
104
+ }
105
+ export function headerListEntries(value) {
106
+ return typeof value === "string" ? value.split(",").map((entry) => entry.trim()).filter((entry) => entry !== "") : [];
104
107
  }
105
108
  export function headerBagOnce(bag) {
106
109
  return bag === undefined ? undefined : { ...bag };
@@ -1,5 +1,6 @@
1
1
  import type { BrainRetryErrClass, BrainStatus } from "../core/types.js";
2
2
  import type { ReasoningWireFacts } from "./reasoning.js";
3
+ import type { CapabilityDeclaration, ModelCapability } from "./model-capability.js";
3
4
  /** Run `fn` with a per-task brain-status sink in scope. ALS propagates it through the async brain calls
4
5
  * inside `fn` (the harness's prompt → brain.stream → connect/retry loop), so {@link emitBrainStatus}
5
6
  * reaches THIS task's sink and nothing else. */
@@ -168,3 +169,22 @@ export declare function runWithCredentialOriginRefusals<T>(observe: (r: Credenti
168
169
  * `routeRefusalError`; a judgment that only advises reports nothing). The
169
170
  * observer is the Runner's own seat, whose one delivery is the guarded `deliverEngineNotice` — nothing is swallowed here. */
170
171
  export declare function reportCredentialOriginRefusal(report: CredentialOriginRefusalReport): void;
172
+ /** A request that withheld a capability from the model it was sent to: the model, the capability, the model's declaration
173
+ * that withheld it (`capabilityOf`), and how many blocks it replaced. */
174
+ export interface CapabilityWithheldReport {
175
+ modelId: string;
176
+ capability: ModelCapability;
177
+ cause: Exclude<CapabilityDeclaration, "declared_on">;
178
+ count: number;
179
+ }
180
+ /**
181
+ * Run `fn` with a per-run withheld-capability sink in scope — the SIXTH brain→runner ALS channel, with the fourth's shape
182
+ * and for its reasons: the WHOLE leg (the end-of-task compaction runs after the leg's prompt, and a child leg running
183
+ * inside its parent's tool call must report to its own leg, not to the scope it inherited), not shielded around the leg's
184
+ * internal calls, not revoked on settlement, no-op outside the scope.
185
+ */
186
+ export declare function runWithCapabilityWithheld<T>(observe: (r: CapabilityWithheldReport) => void, fn: () => Promise<T>): Promise<T>;
187
+ /** Report a withheld capability to the active per-run sink, if any (called by the message assemblers' one emit,
188
+ * `reportImagesWithheld`). The observer is the Runner's own seat, whose one delivery is the guarded `deliverEngineNotice`
189
+ * — nothing is swallowed here: a seat that fails otherwise fails the request build, never the person's notice in silence. */
190
+ export declare function reportCapabilityWithheld(report: CapabilityWithheldReport): void;
@@ -75,3 +75,10 @@ export function runWithCredentialOriginRefusals(observe, fn) {
75
75
  export function reportCredentialOriginRefusal(report) {
76
76
  credentialOriginRefusalSinkStore.getStore()?.observe(report);
77
77
  }
78
+ const capabilityWithheldSinkStore = new AsyncLocalStorage();
79
+ export function runWithCapabilityWithheld(observe, fn) {
80
+ return capabilityWithheldSinkStore.run({ observe }, fn);
81
+ }
82
+ export function reportCapabilityWithheld(report) {
83
+ capabilityWithheldSinkStore.getStore()?.observe(report);
84
+ }
@@ -1,4 +1,5 @@
1
1
  import type { AgentTool } from "../internal/harness-types.js";
2
+ import { type HostFloor } from "./host-floor.js";
2
3
  import type { A2aServerSpec, ToolEffect } from "./types.js";
3
4
  /** The hard per-skill description bound (ruled 2026-08-03: ~2KiB). */
4
5
  export declare const A2A_SKILL_DESCRIPTION_MAX_CHARS = 2048;
@@ -96,4 +97,4 @@ export declare class A2aRpcError extends Error {
96
97
  * `allSettled` keeps it fail-open: one unreachable peer is a skipped peer with a warning, never a task
97
98
  * that cannot start.
98
99
  */
99
- export declare function materializeA2aTools(specs: readonly A2aServerSpec[], principal?: string, signal?: AbortSignal): Promise<MaterializedA2a>;
100
+ export declare function materializeA2aTools(specs: readonly A2aServerSpec[], principal?: string, signal?: AbortSignal, hostFloor?: HostFloor): Promise<MaterializedA2a>;
package/dist/core/a2a.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { Type } from "typebox";
3
3
  import { A2A_TASK_STATES } from "./a2a-task-state.js";
4
- import { assertEndpointBound, redirectPolicy, resolveProtocolHttpHeaders, underDeclaredHeaders } from "./protocol-http-auth.js";
4
+ import { assertEndpointBound, carriesDeclaredHeaders, resolveProtocolHttpHeaders, underDeclaredHeaders } from "./protocol-http-auth.js";
5
+ import { fetchFollowing, hopRefusal, HOST_FLOOR_REFUSED_CODE } from "./host-floor.js";
5
6
  import { describeHttpTransportFailure } from "./mcp-failure.js";
6
7
  import { findNamespacePrefixCollision, mintNamespacePrefix, mintNamespacedToolName } from "./protocol-naming.js";
7
8
  import { A2A_NAMESPACE } from "./protocol-table.js";
@@ -77,6 +78,7 @@ function safeId(v) {
77
78
  return undefined;
78
79
  return inlineUntrusted(s, A2A_ID_MAX_CHARS);
79
80
  }
81
+ const A2A_MAX_REDIRECTS = 20;
80
82
  function withRequestDeadline(outer, timeoutMs) {
81
83
  const controller = new AbortController();
82
84
  let timedOut = false;
@@ -144,21 +146,25 @@ async function readBoundedText(res, what) {
144
146
  async function requestJson(t, what, init) {
145
147
  const doFetch = resolveFetch();
146
148
  const deadline = withRequestDeadline(init.signal, init.timeoutMs);
149
+ const peerLabel = inlineUntrusted(t.peer, A2A_ID_MAX_CHARS);
147
150
  try {
148
- const res = await doFetch(init.url, {
151
+ const followed = await fetchFollowing(doFetch, new URL(init.url), {
149
152
  method: init.method,
150
- signal: deadline.signal,
151
- redirect: redirectPolicy(t.headers),
152
153
  headers: underDeclaredHeaders({ accept: "application/json", "a2a-version": A2A_PROTOCOL_VERSION, ...(init.body !== undefined ? { "content-type": "application/json" } : {}) }, t.headers),
153
154
  ...(init.body !== undefined ? { body: init.body } : {}),
154
- });
155
- const text = await readBoundedText(res, `${what} from A2A peer "${inlineUntrusted(t.peer, A2A_ID_MAX_CHARS)}"`);
155
+ signal: deadline.signal,
156
+ }, { refusal: (url) => hopRefusal(url, t.floor, false), follows: () => !carriesDeclaredHeaders(t.headers), maxRedirects: A2A_MAX_REDIRECTS });
157
+ if (followed.kind === "refused")
158
+ throw Object.assign(new Error(`a2a: ${what} on peer "${peerLabel}" is not sent — ${followed.reason}`), { code: HOST_FLOOR_REFUSED_CODE });
159
+ if (followed.kind === "too_many")
160
+ throw new Error(`a2a: ${what} on peer "${peerLabel}" was redirected more than ${A2A_MAX_REDIRECTS} times`);
161
+ const res = followed.res;
162
+ const text = await readBoundedText(res, `${what} from A2A peer "${peerLabel}"`);
156
163
  return { status: res.status, text };
157
164
  }
158
165
  catch (err) {
159
166
  if (init.signal?.aborted === true)
160
167
  throw err;
161
- const peerLabel = inlineUntrusted(t.peer, A2A_ID_MAX_CHARS);
162
168
  if (deadline.timedOut()) {
163
169
  throw new Error(`a2a: ${what} on peer "${peerLabel}" got no answer within ${init.timeoutMs}ms. The client stopped waiting — the peer may still be acting on the request, so treat the outcome as UNKNOWN and verify before retrying.`, { cause: err });
164
170
  }
@@ -553,16 +559,16 @@ function declaredPeerOf(declared, index) {
553
559
  const judged = judgeEntryToolAxes(snapshot, "a2a");
554
560
  return judged.ok ? { spec: judged.entry } : { spec: snapshot, refusal: judged.error };
555
561
  }
556
- async function materializePeer(peer, principal, lifecycle, signal) {
562
+ async function materializePeer(peer, principal, lifecycle, signal, floor) {
557
563
  if ("refusal" in peer)
558
564
  throw peer.refusal;
559
565
  const { spec } = peer;
560
566
  const declaredAxes = spec.toolAxes;
561
567
  const headers = resolveProtocolHttpHeaders(A2A_NAMESPACE.id, spec, principal);
562
- const discovery = { peer: spec.name, endpoint: spec.url, headers };
568
+ const discovery = { peer: spec.name, endpoint: spec.url, headers, floor };
563
569
  const card = readCard(spec.name, await discoverCardBody(spec, discovery, signal), spec.url);
564
570
  assertEndpointBound(A2A_NAMESPACE.id, spec.name, card.endpoint, spec.cardUrl === undefined ? [spec.url] : [spec.url, spec.cardUrl], headers);
565
- const transport = { peer: spec.name, endpoint: card.endpoint, headers };
571
+ const transport = { peer: spec.name, endpoint: card.endpoint, headers, floor };
566
572
  const tools = [];
567
573
  const skillAxes = [];
568
574
  for (const skill of card.skills) {
@@ -592,7 +598,7 @@ function asPeerWarning(spec, err) {
592
598
  warning.code = "a2a.peer_unavailable";
593
599
  return warning;
594
600
  }
595
- export async function materializeA2aTools(specs, principal, signal) {
601
+ export async function materializeA2aTools(specs, principal, signal, hostFloor) {
596
602
  const peers = specs.map((spec, index) => declaredPeerOf(spec, index));
597
603
  if (peers.length > 0) {
598
604
  const collision = findNamespacePrefixCollision(A2A_NAMESPACE, peers.map((p) => p.spec.name));
@@ -610,7 +616,7 @@ export async function materializeA2aTools(specs, principal, signal) {
610
616
  const toolAxes = [];
611
617
  const warnings = [];
612
618
  const statuses = [];
613
- const settled = await Promise.allSettled(peers.map((peer) => materializePeer(peer, principal, lifecycle, signal)));
619
+ const settled = await Promise.allSettled(peers.map((peer) => materializePeer(peer, principal, lifecycle, signal, hostFloor)));
614
620
  for (let i = 0; i < peers.length; i++) {
615
621
  const spec = peers[i].spec;
616
622
  const outcome = settled[i];
@@ -645,7 +651,7 @@ export async function materializeA2aTools(specs, principal, signal) {
645
651
  }
646
652
  const previous = statuses.find((s) => s.name === spec.name)?.toolNames ?? [];
647
653
  try {
648
- const fresh = await materializePeer(target, principal, lifecycle, signal);
654
+ const fresh = await materializePeer(target, principal, lifecycle, signal, hostFloor);
649
655
  const names = fresh.tools.map((t) => t.name);
650
656
  results.push({
651
657
  peer: spec.name,
@@ -157,4 +157,14 @@ export interface SkillSpec {
157
157
  * byte-identical result; a placeholder with no directory stays verbatim.
158
158
  */
159
159
  baseDir?: string;
160
+ /**
161
+ * The hooks this skill carries — registrations on the mods bus (the `TaskSpec.mods` form: user tier, a name unique in the
162
+ * run), whose handlers take part only while the skill is ACTIVE on the leg that loads it: from its activation (the `Skill`
163
+ * tool's success, or prepare for a skill the person invoked by name; a resumed run reopens the skills its park recorded
164
+ * active) to the end of that run. A host compiles a frontmatter `hooks:` table into one such registration; the engine
165
+ * reads no hook grammar. Each hangs `classic.*` events only (any other event refuses the prepare, `config.mods_invalid`).
166
+ * They are admitted with the leg's other registrations at its prepare (so a skill never activated still counts as a hook
167
+ * the leg may run) and stay the leg's own: a delegated child neither dispatches them nor is screened by them.
168
+ */
169
+ mods?: readonly import("./mods/classic-events.js").EngineModRegistration[];
160
170
  }
@@ -1,3 +1,4 @@
1
+ import type { EditRewritten } from "./rewrite-rejudge.js";
1
2
  import { type RuleToolNameVerdict } from "./tool-name-aliases.js";
2
3
  import type { ToolCallRequest } from "./tool-policy.js";
3
4
  import { type AllowRuleMember, type AllowRuleShadow } from "./allow-rule-shadow.js";
@@ -46,14 +47,15 @@ export type AllowEntryInert = {
46
47
  readonly entry: string;
47
48
  readonly reason: AllowEntryInertReason;
48
49
  } & AllowEntryInertDetail;
49
- /** One entry the grammar reads (kind closed): a whole non-shell tool; a protocol namespace; the whole shell tool; and one
50
- * kind per rule grammar (`ruleToolGrammarOf`) — a shell command rule, a path rule, a name rule, a host rule — each the row
51
- * the persisted grammar parses, its `behavior` the list's direction. */
50
+ /** One entry the grammar reads (kind closed): a whole non-shell tool; a covering spelling — a set of tool names
51
+ * ({@link isCoveringRuleName}: a protocol peer, a glob over a protocol name's tool segment, and on a deny list a `*` anywhere in
52
+ * the name, `*` alone every tool); the whole shell tool; and one kind per rule grammar (`ruleToolGrammarOf`) — a shell command
53
+ * rule, a path rule, a name rule, a host rule — each the row the persisted grammar parses, its `behavior` the list's direction. */
52
54
  export type CompiledAllowEntry = {
53
55
  readonly kind: "tool";
54
56
  readonly name: string;
55
57
  } | {
56
- readonly kind: "namespace";
58
+ readonly kind: "covering";
57
59
  readonly pattern: string;
58
60
  } | {
59
61
  readonly kind: "shell";
@@ -108,15 +110,13 @@ export type RuleEntryReading = {
108
110
  * grammar alone is read — what a resume's pre-claim screen can read before the leg has a roster.
109
111
  */
110
112
  export declare function readRuleEntry(raw: unknown, behavior: "allow" | "deny", roster?: ReadonlySet<string>): RuleEntryReading;
111
- /** The tool name a compiled entry speaks for — its tool, its namespace spelling, or its rule's tool (what a name audit reads). */
113
+ /** The tool name a compiled entry speaks for — its tool, its covering spelling, or its rule's tool (what a name audit reads). */
112
114
  export declare function compiledEntryName(compiled: CompiledAllowEntry): string;
113
115
  /**
114
- * Compile one list WHOLE through {@link readRuleEntry}: the entries it reads and the ones it reads as nothing (each with its
115
- * reason and, for a name the roster refuses, the judgment's word and the spelling to write). An allow list holding `*` voids
116
- * the list (every other entry on it reads as nothing too: the list grants nothing — the safe direction) — `*` as the lenient
117
- * rule parser names it ({@link namesWholeRoster}), so an entry the stricter entry grammar refuses (`* (*)`) still voids. A
118
- * `*` on a deny list reads as nothing by itself and the rest of that list still refuses: a deny list never loses an entry to
119
- * a wildcard beside it. `roster` as in {@link readRuleEntry}.
116
+ * Compile one list through {@link readRuleEntry}, entry by entry: the entries it reads and the ones it reads as nothing (each
117
+ * with its reason and, for a name the roster refuses, the judgment's word and the spelling to write). No entry changes how
118
+ * another is read: a `*` on an allow list grants nothing by itself (`wildcard_all`) and the entries beside it keep their
119
+ * reading; on a deny list it refuses every tool. `roster` as in {@link readRuleEntry}.
120
120
  */
121
121
  export declare function compileAllowList(entries: readonly string[], behavior: "allow" | "deny", roster?: ReadonlySet<string>): {
122
122
  rows: Array<{
@@ -275,6 +275,10 @@ export declare function screenAllowedToolsValue(value: unknown, seat: AllowedToo
275
275
  /** The disclosure record for one member, minted from the entries it matched: each sanitized (deployment or model-authored
276
276
  * text on a human trust boundary) and capped, the rest counted. */
277
277
  export declare function allowRuleShadowOf(member: AllowRuleMember, entries: readonly string[]): AllowRuleShadow;
278
+ /** A disclosure list with one more member's record folded in: ONE record per member — a member already disclosed gains the
279
+ * other record's entries after its own (every speaking, in reading order: two shown names that read alike are two speakers),
280
+ * the cap kept and the rest counted; any other member is appended. Records are minted values already ({@link allowRuleShadowOf}). */
281
+ export declare function withAllowRuleShadow(list: readonly AllowRuleShadow[], shadow: AllowRuleShadow): AllowRuleShadow[];
278
282
  /** Read a disclosure value off a decision WITHOUT trusting it (a policy's own value, an ancestor's): every record a known
279
283
  * member with a list of strings, or nothing — a display member must never throw where a card is minted. */
280
284
  export declare function readAllowRuleShadows(value: unknown): readonly AllowRuleShadow[] | undefined;
@@ -325,8 +329,9 @@ export declare function allowRuleShadowSentence(shadows: readonly AllowRuleShado
325
329
  authoredBy?: "deployment";
326
330
  probeReason?: string;
327
331
  }): string;
328
- /** The card's two disclosure members off a surviving ask, minted at every station that builds an approval request: the
329
- * sanitized records, and the message with the sentence rendered onto it. */
332
+ /** The card's disclosure members off a surviving ask, minted at every station that builds an approval request: the
333
+ * sanitized records, the message with the sentence rendered onto it, and the outlet of a person's rewritten edit (the
334
+ * approved-edit pass's own member, whose form is the bytes the card presents). */
330
335
  export declare function cardDisclosureOf(decision: {
331
336
  message?: string;
332
337
  allowRuleShadowed?: unknown;
@@ -334,9 +339,11 @@ export declare function cardDisclosureOf(decision: {
334
339
  mandate?: PersistedRuleMandate;
335
340
  authoredBy?: "deployment";
336
341
  probeReason?: string;
342
+ editRewritten?: EditRewritten;
337
343
  }, fallbackMessage: string): {
338
344
  message: string;
339
345
  allowRuleShadowed?: readonly AllowRuleShadow[];
346
+ editRewritten?: EditRewritten;
340
347
  };
341
348
  /** The notice for list entries that grant (or refuse) nothing — one code for every list. */
342
349
  export declare const ALLOWED_TOOL_NOT_GRANTED_CODE = "permission.allowed_tool_not_granted";