@sema-agent/core 7.51.1 → 7.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (372) hide show
  1. package/CHANGELOG.md +550 -2
  2. package/dist/agents/agent-transcript-tool.d.ts +1 -1
  3. package/dist/agents/cascade.js +4 -0
  4. package/dist/agents/cumulative-stats.d.ts +3 -0
  5. package/dist/agents/cumulative-stats.js +3 -0
  6. package/dist/agents/list-agents-tool.d.ts +1 -1
  7. package/dist/agents/read-inbox-tool.d.ts +1 -1
  8. package/dist/agents/repair-loop.js +4 -0
  9. package/dist/agents/send-message-tool.d.ts +11 -16
  10. package/dist/agents/send-message-tool.js +11 -13
  11. package/dist/agents/subagent.d.ts +5 -0
  12. package/dist/agents/subagent.js +7 -4
  13. package/dist/agents/tool-filter.d.ts +40 -13
  14. package/dist/agents/tool-filter.js +28 -14
  15. package/dist/bench/metrics.d.ts +1 -0
  16. package/dist/brain/anthropic.js +16 -12
  17. package/dist/brain/model-presets.d.ts +4 -5
  18. package/dist/brain/model-presets.js +4 -4
  19. package/dist/brain/open-responses.js +16 -12
  20. package/dist/brain/openai.js +16 -12
  21. package/dist/brain/request-params.d.ts +12 -33
  22. package/dist/brain/request-params.js +5 -2
  23. package/dist/brain/request-route.d.ts +9 -8
  24. package/dist/brain/request-route.js +1 -0
  25. package/dist/brain/route-adjudicator.d.ts +117 -47
  26. package/dist/brain/route-adjudicator.js +171 -42
  27. package/dist/brain/route-conformance.js +2 -2
  28. package/dist/brain/status-sink.d.ts +18 -0
  29. package/dist/brain/status-sink.js +7 -0
  30. package/dist/core/allow-entry.d.ts +42 -8
  31. package/dist/core/allow-entry.js +24 -17
  32. package/dist/core/auto-compaction.d.ts +23 -20
  33. package/dist/core/auto-compaction.js +37 -16
  34. package/dist/core/auto-promote.d.ts +2 -1
  35. package/dist/core/auto-promote.js +2 -2
  36. package/dist/core/caller-tool-name.d.ts +9 -0
  37. package/dist/core/caller-tool-name.js +13 -0
  38. package/dist/core/checkpoint-requirements.d.ts +7 -1
  39. package/dist/core/checkpoint-requirements.js +2 -0
  40. package/dist/core/checkpoint-store.d.ts +36 -12
  41. package/dist/core/checkpoint-store.js +1 -1
  42. package/dist/core/child-clamp-seats.d.ts +6 -0
  43. package/dist/core/child-clamp-seats.js +2 -1
  44. package/dist/core/credential-vocabulary.d.ts +33 -8
  45. package/dist/core/credential-vocabulary.js +32 -7
  46. package/dist/core/decision-receipt.d.ts +2 -2
  47. package/dist/core/delegation-frames.d.ts +9 -2
  48. package/dist/core/delegation-name.d.ts +18 -0
  49. package/dist/core/delegation-name.js +47 -0
  50. package/dist/core/engine-capabilities.d.ts +8 -1
  51. package/dist/core/engine-capabilities.js +1 -1
  52. package/dist/core/engine-notice.d.ts +36 -19
  53. package/dist/core/frontmatter-fence.d.ts +10 -0
  54. package/dist/core/frontmatter-fence.js +6 -0
  55. package/dist/core/gate-fold.js +5 -23
  56. package/dist/core/gate-lanes.js +356 -270
  57. package/dist/core/governance-codes.d.ts +9 -4
  58. package/dist/core/governance-codes.js +9 -3
  59. package/dist/core/hooks.d.ts +276 -734
  60. package/dist/core/hooks.js +97 -192
  61. package/dist/{tools/fs → core}/image-admission.d.ts +21 -3
  62. package/dist/{tools/fs → core}/image-admission.js +24 -6
  63. package/dist/core/locked-config.d.ts +26 -5
  64. package/dist/core/locked-config.js +31 -6
  65. package/dist/core/mcp-connection-pool.d.ts +4 -1
  66. package/dist/core/mcp-connection-pool.js +7 -2
  67. package/dist/core/mcp-probe.d.ts +12 -9
  68. package/dist/core/mcp-probe.js +2 -2
  69. package/dist/core/mcp-server-spec.d.ts +53 -7
  70. package/dist/core/mcp-server-spec.js +84 -1
  71. package/dist/core/mcp.d.ts +11 -7
  72. package/dist/core/mcp.js +27 -9
  73. package/dist/core/memory-engine/data-plane.js +5 -1
  74. package/dist/core/memory-engine/distiller.js +16 -2
  75. package/dist/core/memory-engine/engine.d.ts +8 -11
  76. package/dist/core/memory-engine/engine.js +9 -5
  77. package/dist/core/memory-engine/frontmatter.d.ts +6 -0
  78. package/dist/core/memory-engine/frontmatter.js +19 -16
  79. package/dist/core/memory.d.ts +2 -2
  80. package/dist/core/mode-policy.d.ts +4 -0
  81. package/dist/core/mode-policy.js +7 -5
  82. package/dist/core/model-seat.d.ts +4 -1
  83. package/dist/core/mods/dollar.d.ts +109 -0
  84. package/dist/core/mods/dollar.js +154 -0
  85. package/dist/core/mods/host.d.ts +23 -0
  86. package/dist/core/mods/host.js +21 -0
  87. package/dist/core/mods/kernel/budget.d.ts +43 -0
  88. package/dist/core/mods/kernel/budget.js +83 -0
  89. package/dist/core/mods/kernel/dispatch.d.ts +100 -0
  90. package/dist/core/mods/kernel/dispatch.js +701 -0
  91. package/dist/core/mods/kernel/events.d.ts +242 -0
  92. package/dist/core/mods/kernel/events.js +210 -0
  93. package/dist/core/mods/kernel/index.d.ts +6 -0
  94. package/dist/core/mods/kernel/index.js +5 -0
  95. package/dist/core/mods/kernel/receive.d.ts +65 -0
  96. package/dist/core/mods/kernel/receive.js +123 -0
  97. package/dist/core/mods/kernel/registration.d.ts +131 -0
  98. package/dist/core/mods/kernel/registration.js +102 -0
  99. package/dist/core/mods/kernel/site-rules.d.ts +84 -0
  100. package/dist/core/mods/kernel/site-rules.js +104 -0
  101. package/dist/core/mods/stations.d.ts +350 -0
  102. package/dist/core/mods/stations.js +444 -0
  103. package/dist/core/own-property-receipt.js +11 -23
  104. package/dist/core/parent-spec-seat.d.ts +18 -7
  105. package/dist/core/parent-spec-seat.js +6 -2
  106. package/dist/core/path-identity.js +2 -1
  107. package/dist/core/permission-rule-syntax.d.ts +15 -0
  108. package/dist/core/permission-rule-syntax.js +24 -16
  109. package/dist/core/permission-rules.d.ts +7 -1
  110. package/dist/core/permission-rules.js +26 -15
  111. package/dist/core/prompt-section-seat.d.ts +15 -27
  112. package/dist/core/prompt-section-seat.js +73 -40
  113. package/dist/core/protocol-http-auth.d.ts +3 -1
  114. package/dist/core/protocol-http-auth.js +2 -0
  115. package/dist/core/reminder-mint.d.ts +2 -2
  116. package/dist/core/remote-env.d.ts +24 -12
  117. package/dist/core/remote-env.js +1 -0
  118. package/dist/core/resume-startup-cause.d.ts +16 -1
  119. package/dist/core/resume-startup-cause.js +4 -1
  120. package/dist/core/retired-keys.d.ts +4 -0
  121. package/dist/core/retired-keys.js +3 -0
  122. package/dist/core/runner/announce-once-ledger.d.ts +31 -1
  123. package/dist/core/runner/announce-once-ledger.js +22 -0
  124. package/dist/core/runner/assemble-result.d.ts +9 -0
  125. package/dist/core/runner/assemble-result.js +3 -1
  126. package/dist/core/runner/call-hook-stations.d.ts +23 -27
  127. package/dist/core/runner/call-hook-stations.js +58 -42
  128. package/dist/core/runner/caller-stop-gate.d.ts +25 -0
  129. package/dist/core/runner/caller-stop-gate.js +7 -0
  130. package/dist/core/runner/compaction-seams.d.ts +8 -22
  131. package/dist/core/runner/compaction-seams.js +28 -53
  132. package/dist/core/runner/construction-doors.js +11 -1
  133. package/dist/core/runner/contracts.d.ts +85 -83
  134. package/dist/core/runner/credential-origin-seat.d.ts +2 -0
  135. package/dist/core/runner/credential-origin-seat.js +19 -0
  136. package/dist/core/runner/extra-body-dropped-seat.d.ts +2 -6
  137. package/dist/core/runner/gate-exit.d.ts +47 -36
  138. package/dist/core/runner/gate-exit.js +8 -2
  139. package/dist/core/runner/image.js +1 -2
  140. package/dist/core/runner/inline-image.js +1 -1
  141. package/dist/core/runner/notice-seat-input.d.ts +11 -0
  142. package/dist/core/runner/notice-seat-input.js +1 -0
  143. package/dist/core/runner/person-path-rows.js +1 -0
  144. package/dist/core/runner/prepare-acquire-reconcile.js +5 -1
  145. package/dist/core/runner/prepare-ask-lane.d.ts +5 -7
  146. package/dist/core/runner/prepare-ask-lane.js +6 -15
  147. package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -2
  148. package/dist/core/runner/prepare-caps-and-workflow.js +25 -8
  149. package/dist/core/runner/prepare-config-doors.d.ts +5 -0
  150. package/dist/core/runner/prepare-config-doors.js +9 -0
  151. package/dist/core/runner/prepare-defer-classify.js +3 -4
  152. package/dist/core/runner/prepare-gate-stations.d.ts +8 -11
  153. package/dist/core/runner/prepare-gate-stations.js +11 -10
  154. package/dist/core/runner/prepare-inherited-gate.d.ts +8 -12
  155. package/dist/core/runner/prepare-inherited-gate.js +8 -21
  156. package/dist/core/runner/prepare-memory-engine-session.js +1 -1
  157. package/dist/core/runner/prepare-park-ask.js +10 -14
  158. package/dist/core/runner/prepare-policy-chain.d.ts +18 -16
  159. package/dist/core/runner/prepare-policy-chain.js +98 -101
  160. package/dist/core/runner/prepare-project-context.js +7 -10
  161. package/dist/core/runner/prepare-prompt-assembly.d.ts +45 -40
  162. package/dist/core/runner/prepare-prompt-assembly.js +134 -101
  163. package/dist/core/runner/prepare-prompt-inputs.d.ts +18 -19
  164. package/dist/core/runner/prepare-prompt-inputs.js +5 -7
  165. package/dist/core/runner/prepare-protocol-tools.d.ts +6 -4
  166. package/dist/core/runner/prepare-protocol-tools.js +2 -2
  167. package/dist/core/runner/prepare-safety-scan.js +6 -10
  168. package/dist/core/runner/prepare-suspend-saga.d.ts +6 -0
  169. package/dist/core/runner/prepare-suspend-saga.js +7 -5
  170. package/dist/core/runner/prepare-task.js +33 -15
  171. package/dist/core/runner/prepare-turn-wiring.d.ts +13 -15
  172. package/dist/core/runner/prepare-turn-wiring.js +29 -27
  173. package/dist/core/runner/prepare-wiring-manifest.d.ts +5 -6
  174. package/dist/core/runner/prepare-wiring-manifest.js +7 -7
  175. package/dist/core/runner/resume-apply.d.ts +5 -2
  176. package/dist/core/runner/resume-apply.js +24 -42
  177. package/dist/core/runner/resume-checkpoint-screen.d.ts +1 -0
  178. package/dist/core/runner/resume-checkpoint-screen.js +9 -1
  179. package/dist/core/runner/resume-preflight.js +38 -16
  180. package/dist/core/runner/retired-runner-deps.js +3 -1
  181. package/dist/core/runner/run-brain-sinks.d.ts +3 -2
  182. package/dist/core/runner/run-brain-sinks.js +5 -1
  183. package/dist/core/runner/run-compaction-machinery.d.ts +7 -1
  184. package/dist/core/runner/run-compaction-machinery.js +7 -33
  185. package/dist/core/runner/run-harness-handlers.js +4 -2
  186. package/dist/core/runner/run-identity-wiring.d.ts +3 -1
  187. package/dist/core/runner/run-identity-wiring.js +3 -2
  188. package/dist/core/runner/run-leg.js +62 -84
  189. package/dist/core/runner/run-notification-lane.js +1 -0
  190. package/dist/core/runner/run-recovery-lanes.d.ts +3 -0
  191. package/dist/core/runner/run-recovery-lanes.js +11 -10
  192. package/dist/core/runner/run-settle-and-teardown.js +9 -28
  193. package/dist/core/runner/run-stop-and-final-verify.js +18 -25
  194. package/dist/core/runner/run-terminal-adoption.d.ts +3 -0
  195. package/dist/core/runner/run-terminal-adoption.js +33 -22
  196. package/dist/core/runner/run-tool-mount-facts.js +5 -3
  197. package/dist/core/runner/run-turn-boundary.js +23 -34
  198. package/dist/core/runner/runtask.d.ts +6 -7
  199. package/dist/core/runner/runtask.js +14 -72
  200. package/dist/core/runner/session-rule-policy.d.ts +6 -4
  201. package/dist/core/runner/session-rule-policy.js +17 -10
  202. package/dist/core/runner/side-call-account.d.ts +68 -0
  203. package/dist/core/runner/side-call-account.js +61 -0
  204. package/dist/core/runner/stream-halt-verbs.js +12 -17
  205. package/dist/core/runner/stream-lifecycle-verbs.js +8 -5
  206. package/dist/core/runner/stream-steer-verb.d.ts +1 -1
  207. package/dist/core/runner/stream-steer-verb.js +20 -38
  208. package/dist/core/runner/sub-agent-deny-lists.d.ts +121 -22
  209. package/dist/core/runner/sub-agent-deny-lists.js +228 -71
  210. package/dist/core/runner/tool-end-body.d.ts +5 -6
  211. package/dist/core/runner/tool-end-body.js +6 -4
  212. package/dist/core/runner/tool-not-executed.d.ts +15 -0
  213. package/dist/core/runner/tool-not-executed.js +30 -0
  214. package/dist/core/runner/tool-occurrence.d.ts +8 -7
  215. package/dist/core/runner/tool-occurrence.js +5 -5
  216. package/dist/core/runner/tool-result-media-seat.d.ts +1 -1
  217. package/dist/core/runner-deps.d.ts +20 -28
  218. package/dist/core/safety-merge-corpus.js +18 -2
  219. package/dist/core/secret-env.d.ts +93 -20
  220. package/dist/core/secret-env.js +192 -38
  221. package/dist/core/session-policy-store.d.ts +93 -17
  222. package/dist/core/session-policy-store.js +178 -25
  223. package/dist/core/session-reconcile.d.ts +4 -0
  224. package/dist/core/session-reconcile.js +2 -1
  225. package/dist/core/shell-read-silence.js +3 -32
  226. package/dist/core/side-query.d.ts +5 -3
  227. package/dist/core/skill-grant.d.ts +3 -2
  228. package/dist/core/skill-grant.js +17 -9
  229. package/dist/core/skills-directory.d.ts +31 -11
  230. package/dist/core/skills-directory.js +655 -104
  231. package/dist/core/task-event.d.ts +13 -3
  232. package/dist/core/task-result.d.ts +8 -0
  233. package/dist/core/task-spec.d.ts +20 -19
  234. package/dist/core/task-stream.d.ts +14 -4
  235. package/dist/core/tighten-task-spec.d.ts +4 -3
  236. package/dist/core/tighten-task-spec.js +2 -4
  237. package/dist/core/tool-check-reading.d.ts +74 -0
  238. package/dist/core/tool-check-reading.js +80 -0
  239. package/dist/core/tool-policy.d.ts +59 -18
  240. package/dist/core/tool-policy.js +77 -12
  241. package/dist/core/tool-registry.d.ts +20 -0
  242. package/dist/core/tool-registry.js +4 -0
  243. package/dist/core/tool-spec.d.ts +10 -6
  244. package/dist/core/tools.js +2 -0
  245. package/dist/core/trace.d.ts +51 -32
  246. package/dist/core/types.d.ts +2 -1
  247. package/dist/core/types.js +1 -0
  248. package/dist/core/unc-spelling.d.ts +10 -0
  249. package/dist/core/unc-spelling.js +3 -0
  250. package/dist/core/untrusted-egress.d.ts +8 -0
  251. package/dist/core/untrusted-egress.js +4 -1
  252. package/dist/core/user-attachment.d.ts +12 -2
  253. package/dist/core/user-attachment.js +17 -2
  254. package/dist/core/wiring-manifest.d.ts +14 -13
  255. package/dist/core/wiring-manifest.js +2 -2
  256. package/dist/engine/compaction/utils.js +1 -2
  257. package/dist/engine/execution-env/node-execution-env.d.ts +4 -3
  258. package/dist/engine/execution-env/symlink-chain.js +1 -1
  259. package/dist/engine/harness/agent-harness.d.ts +1 -1
  260. package/dist/engine/harness/agent-harness.js +3 -3
  261. package/dist/engine/harness/types.d.ts +17 -16
  262. package/dist/engine/harness/types.js +7 -1
  263. package/dist/engine/llm/types.d.ts +12 -7
  264. package/dist/engine/loop/agent-loop.js +1 -1
  265. package/dist/engine/loop/types.d.ts +1 -1
  266. package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
  267. package/dist/engine/session/import-validate.js +3 -10
  268. package/dist/engine/session/session.d.ts +4 -4
  269. package/dist/engine/session/session.js +4 -4
  270. package/dist/index.d.ts +24 -17
  271. package/dist/index.js +15 -12
  272. package/dist/internal/harness.d.ts +1 -1
  273. package/dist/internal/harness.js +1 -1
  274. package/dist/orchestration/run-spec.d.ts +4 -6
  275. package/dist/orchestration/run-spec.js +39 -63
  276. package/dist/orchestration/run-workflow-tool.js +1 -2
  277. package/dist/orchestration/workflow.d.ts +11 -3
  278. package/dist/orchestration/workflow.js +11 -2
  279. package/dist/prompt-assembly/artifact-store.d.ts +37 -56
  280. package/dist/prompt-assembly/artifact-store.js +31 -49
  281. package/dist/prompt-assembly/artifact.d.ts +89 -76
  282. package/dist/prompt-assembly/artifact.js +167 -146
  283. package/dist/prompt-assembly/assemble.d.ts +34 -29
  284. package/dist/prompt-assembly/assemble.js +33 -220
  285. package/dist/prompt-assembly/bands.d.ts +20 -0
  286. package/dist/prompt-assembly/bands.js +18 -0
  287. package/dist/prompt-assembly/catalog/constitution.d.ts +23 -0
  288. package/dist/prompt-assembly/catalog/constitution.js +69 -0
  289. package/dist/prompt-assembly/catalog/core-behavior.d.ts +9 -0
  290. package/dist/prompt-assembly/catalog/core-behavior.js +85 -0
  291. package/dist/prompt-assembly/catalog/index.d.ts +11 -0
  292. package/dist/prompt-assembly/catalog/index.js +59 -0
  293. package/dist/prompt-assembly/catalog/modes.d.ts +15 -0
  294. package/dist/prompt-assembly/catalog/modes.js +137 -0
  295. package/dist/prompt-assembly/catalog/role.d.ts +10 -0
  296. package/dist/prompt-assembly/catalog/role.js +157 -0
  297. package/dist/prompt-assembly/catalog/schema.d.ts +124 -0
  298. package/dist/prompt-assembly/catalog/schema.js +25 -0
  299. package/dist/prompt-assembly/catalog/sections.d.ts +9 -0
  300. package/dist/prompt-assembly/catalog/sections.js +98 -0
  301. package/dist/prompt-assembly/catalog/team.d.ts +4 -0
  302. package/dist/prompt-assembly/catalog/team.js +258 -0
  303. package/dist/prompt-assembly/composer.d.ts +24 -28
  304. package/dist/prompt-assembly/composer.js +124 -46
  305. package/dist/prompt-assembly/epoch.d.ts +89 -79
  306. package/dist/prompt-assembly/epoch.js +115 -142
  307. package/dist/prompt-assembly/explain.d.ts +58 -34
  308. package/dist/prompt-assembly/explain.js +21 -24
  309. package/dist/prompt-assembly/overlay.d.ts +127 -0
  310. package/dist/prompt-assembly/overlay.js +301 -0
  311. package/dist/prompt-assembly/renderers.d.ts +21 -0
  312. package/dist/prompt-assembly/renderers.js +39 -0
  313. package/dist/prompt-assembly/section-usage.d.ts +3 -3
  314. package/dist/prompt-assembly/section-usage.js +1 -1
  315. package/dist/prompt-assembly/select.d.ts +56 -0
  316. package/dist/prompt-assembly/select.js +69 -0
  317. package/dist/prompt-assembly/sugar.d.ts +31 -0
  318. package/dist/prompt-assembly/sugar.js +20 -0
  319. package/dist/prompt-assembly/turn-snapshot.d.ts +3 -2
  320. package/dist/prompt-assembly/types.d.ts +45 -148
  321. package/dist/prompts/coordinator.d.ts +2 -21
  322. package/dist/prompts/coordinator.js +3 -255
  323. package/dist/prompts/cowork.d.ts +27 -16
  324. package/dist/prompts/cowork.js +2 -23
  325. package/dist/prompts/default.d.ts +38 -500
  326. package/dist/prompts/default.js +20 -285
  327. package/dist/prompts/supervisor.d.ts +6 -71
  328. package/dist/prompts/supervisor.js +6 -117
  329. package/dist/stores/file/session-policy-store.d.ts +3 -3
  330. package/dist/tools/fs/bash-readonly-classifier.d.ts +6 -5
  331. package/dist/tools/fs/dir-entries.d.ts +4 -2
  332. package/dist/tools/fs/dir-entries.js +16 -4
  333. package/dist/tools/fs/fs-bash.d.ts +1 -1
  334. package/dist/tools/fs/fs-bash.js +22 -11
  335. package/dist/tools/fs/fs-pdf.js +17 -13
  336. package/dist/tools/fs/fs-read.js +4 -3
  337. package/dist/tools/fs/fs-shared.d.ts +1 -10
  338. package/dist/tools/fs/fs-shared.js +3 -4
  339. package/dist/tools/fs/fs-write.js +2 -1
  340. package/dist/tools/fs/notebook.js +1 -1
  341. package/dist/tools/fs/pdf.d.ts +20 -10
  342. package/dist/tools/fs/pdf.js +19 -10
  343. package/dist/tools/fs/program-read-model.d.ts +68 -8
  344. package/dist/tools/fs/program-read-model.js +112 -33
  345. package/dist/tools/fs/program-read-model.rows.js +30 -10
  346. package/dist/tools/fs/read-deny-home.d.ts +25 -9
  347. package/dist/tools/fs/read-deny-home.js +28 -27
  348. package/dist/tools/fs/read-deny.d.ts +41 -11
  349. package/dist/tools/fs/read-deny.js +51 -5
  350. package/dist/tools/fs/safety.d.ts +4 -26
  351. package/dist/tools/fs/safety.js +10 -32
  352. package/dist/tools/fs/search.js +15 -10
  353. package/dist/tools/fs/shell-read-argv.d.ts +3 -2
  354. package/dist/tools/fs/shell-read-argv.js +118 -38
  355. package/dist/tools/fs/shell-read-establish.d.ts +5 -5
  356. package/dist/tools/fs/shell-read-establish.js +11 -61
  357. package/dist/tools/fs/shell-read-identity.js +6 -3
  358. package/dist/tools/fs/shell-read-judge.d.ts +13 -15
  359. package/dist/tools/fs/shell-read-judge.js +18 -4
  360. package/dist/tools/fs/shell-read-plan.d.ts +2 -2
  361. package/dist/tools/web.js +1 -1
  362. package/package.json +13 -1
  363. package/test/export-surface.snapshot.json +256 -99
  364. package/wire-changes/core@7.51.1.json +5 -5
  365. package/wire-changes/core@7.51.2.json +293 -0
  366. package/wire-changes/core@7.52.0.json +5859 -0
  367. package/dist/core/hook-seats.d.ts +0 -66
  368. package/dist/core/hook-seats.js +0 -37
  369. package/dist/prompt-assembly/packs/sema-default.d.ts +0 -2
  370. package/dist/prompt-assembly/packs/sema-default.js +0 -147
  371. package/dist/prompts/simple-sections.d.ts +0 -58
  372. package/dist/prompts/simple-sections.js +0 -43
@@ -1,11 +1,9 @@
1
- import { decisionText, describeThrown, receiveHookResult, isEngineRefusal, unaskedSeatAnswer } from "./tool-policy.js";
2
- import { asThrownError } from "./thrown-value.js";
3
- import { createSettlementLedger, engineFailClosedExit, hookDenyExit } from "./runner/gate-exit.js";
4
- import { traceHookCrash } from "./gate-crash-trace.js";
1
+ import { abortedSeatDeny, decisionText, describeThrown, isEngineRefusal, ownArgs, refuseOutOfContractDecision, unaskedSeatAnswer } from "./tool-policy.js";
2
+ import { createSettlementLedger, engineFailClosedExit, hookDenyExit, unownedArgsExit } from "./runner/gate-exit.js";
3
+ import { classicEventBase, dispatchClassic, ENGINE_CORE_ANSWER, engineCore, failedHandlerClause, judgedInputOf, observePermissionDenied, recordScreeningChain } from "./mods/stations.js";
5
4
  import { runGateFold } from "./gate-fold.js";
6
5
  import { runGateLanes } from "./gate-lanes.js";
7
6
  export { normalizeOrgGateVerdict, normalizePersistedRuleHit } from "./rule-lane-reads.js";
8
- export { cloneObserverInput } from "./runner/gate-exit.js";
9
7
  import { brandPolicyAskClass } from "./ask-class.js";
10
8
  import { isAskOrigin, screenAskClassMembers } from "./ask-origin.js";
11
9
  import { isAutoModeFallbackCause } from "./auto-mode.js";
@@ -13,92 +11,6 @@ import { inlineUntrusted } from "./untrusted-text.js";
13
11
  export { formatHookFeedback } from "./reminder-mint.js";
14
12
  import { createSafeNotifier } from "./safe-notify.js";
15
13
  import { wireOf } from "./tool-name-readings.js";
16
- export const DEFAULT_HOOK_TIMEOUT_MS = 600_000;
17
- export const MAX_HOOK_TIMEOUT_MS = 2_147_483_647;
18
- const POST_ABORT_GRACE_MS = 1_000;
19
- export function postAbortGraceMs(remainingMs) {
20
- return Math.max(0, Math.min(POST_ABORT_GRACE_MS, remainingMs));
21
- }
22
- const badHookTimeoutReported = new WeakSet();
23
- export function resolveHookTimeoutMs(supplied, report, owner) {
24
- if (supplied === undefined)
25
- return DEFAULT_HOOK_TIMEOUT_MS;
26
- if (Number.isFinite(supplied) && supplied >= 0 && supplied <= MAX_HOOK_TIMEOUT_MS)
27
- return supplied;
28
- if (report !== undefined && !(owner !== undefined && badHookTimeoutReported.has(owner))) {
29
- if (owner !== undefined)
30
- badHookTimeoutReported.add(owner);
31
- try {
32
- report(new Error(`Hooks.timeoutMs must be a non-negative finite number no greater than ${MAX_HOOK_TIMEOUT_MS} (got ${String(supplied)}) — ` +
33
- `every hook seat falls back to the ${DEFAULT_HOOK_TIMEOUT_MS}ms default`));
34
- }
35
- catch {
36
- }
37
- }
38
- return DEFAULT_HOOK_TIMEOUT_MS;
39
- }
40
- export async function runHookSeat(seat, bound, call) {
41
- void seat;
42
- const timeoutMs = resolveHookTimeoutMs(bound.timeoutMs, bound.onBadTimeout, bound.owner);
43
- const taskSignal = bound.signal;
44
- const controller = new AbortController();
45
- const pending = Promise.resolve(call(controller.signal));
46
- const startedAt = performance.now();
47
- return await new Promise((resolve, reject) => {
48
- let settled = false;
49
- let listening = false;
50
- let timer;
51
- const clearTimer = () => {
52
- if (timer !== undefined)
53
- clearTimeout(timer);
54
- timer = undefined;
55
- };
56
- const finish = (act) => {
57
- if (settled)
58
- return;
59
- settled = true;
60
- clearTimer();
61
- if (listening)
62
- taskSignal?.removeEventListener("abort", onAbort);
63
- act();
64
- };
65
- const expire = (cause) => finish(() => {
66
- void pending.then(undefined, () => {
67
- });
68
- resolve({ expired: true, cause });
69
- queueMicrotask(() => {
70
- try {
71
- controller.abort();
72
- }
73
- catch {
74
- }
75
- });
76
- });
77
- const collapseToGrace = () => {
78
- if (settled)
79
- return;
80
- clearTimer();
81
- timer = setTimeout(() => expire("aborted"), postAbortGraceMs(timeoutMs - (performance.now() - startedAt)));
82
- };
83
- const onAbort = () => (bound.abortEnds === true ? expire("aborted") : collapseToGrace());
84
- timer = setTimeout(() => expire("timeout"), timeoutMs);
85
- if (taskSignal !== undefined) {
86
- if (taskSignal.aborted) {
87
- onAbort();
88
- }
89
- else {
90
- taskSignal.addEventListener("abort", onAbort, { once: true });
91
- listening = true;
92
- }
93
- }
94
- pending.then((value) => finish(() => resolve({ expired: false, value })), (err) => finish(() => reject(asThrownError(err))));
95
- });
96
- }
97
- export function hookSeatExpiredError(seat, timeoutMs, cause, consequence) {
98
- return new Error(cause === "timeout"
99
- ? `the deployment's ${seat} hook did not answer within its ${timeoutMs}ms bound (Hooks.timeoutMs) — ${consequence}`
100
- : `the deployment's ${seat} hook had not answered when the task was cancelled — ${consequence}`);
101
- }
102
14
  const reflectApply = Reflect.apply;
103
15
  const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
104
16
  const getPrototypeOf = Object.getPrototypeOf;
@@ -174,54 +86,92 @@ export function mintHookInvocationIdentity(facts) {
174
86
  ...(facts.parentToolCallId !== undefined ? { parentToolCallId: facts.parentToolCallId } : {}),
175
87
  }));
176
88
  }
177
- function preToolUseCrashReason(subject, err) {
178
- const cause = inlineUntrusted(describeThrown(err), 200);
179
- return (`a PreToolUse hook crashed while screening ${subject}; the call was NOT executed (fail-closed). ` +
180
- `This is a failure of the deployment's hook, NOT of the tool itself — an identical retry reaches the ` +
181
- `same hook and fails the same way. Hook error: ${cause || "(no message)"}`);
89
+ function screenPreToolUseResult(r) {
90
+ if (r === undefined || r === null || r === false)
91
+ return r;
92
+ return refuseOutOfContractDecision(r, { reasonIsNonInput: true });
182
93
  }
183
- function preToolUseUnansweredReason(subject, timeoutMs, cause) {
184
- return cause === "timeout"
185
- ? `a PreToolUse hook did not answer within its ${timeoutMs}ms bound while screening ${subject}; the call was ` +
186
- `NOT executed (fail-closed). This is a failure of the deployment's hook, NOT of the tool itself — the ` +
187
- `screening face never returned a verdict, so nothing was decided about this call either way.`
188
- : `the task was cancelled while a PreToolUse hook was still screening ${subject}; the call was NOT executed ` +
189
- `(fail-closed). No verdict was reached — this is the run ending, not the tool failing.`;
94
+ function preToolUseAnswerViolation(answer) {
95
+ const r = screenPreToolUseResult(answer);
96
+ if (r === undefined || r === null || r === false || !isEngineRefusal(r))
97
+ return undefined;
98
+ return typeof r.message === "string" ? r.message : "the PreToolUse answer was refused by the engine";
190
99
  }
191
- function screenPreToolUseResult(r) {
192
- if (r === undefined)
100
+ function preToolUseRefusedReason(subject, failed) {
101
+ if (failed === undefined) {
102
+ return `the task was cancelled while a PreToolUse hook was still screening ${subject}; the call was NOT executed ` + `(fail-closed). No verdict was reached — this is the run ending, not the tool failing.`;
103
+ }
104
+ const tail = failed.cause === "threw"
105
+ ? ` This is a failure of the deployment's hook, NOT of the tool itself — an identical retry reaches the same hook and fails the same way.`
106
+ : failed.cause === "timeout"
107
+ ? ` This is a failure of the deployment's hook, NOT of the tool itself — the screening face never returned a verdict, so nothing was decided about this call either way.`
108
+ : "";
109
+ return `a PreToolUse hook ${failedHandlerClause(failed)} while screening ${subject}; the call was NOT executed (fail-closed).${tail}`;
110
+ }
111
+ export function createPreToolUseScreening(input) {
112
+ const bus = input.modBus;
113
+ if (bus === undefined || !bus.hasHandlers("classic.PreToolUse"))
193
114
  return undefined;
194
- return receiveHookResult(r);
115
+ const { toolCallId, toolName } = input.event;
116
+ const screenedName = wireOf("gate.preToolUse", input.event);
117
+ const eventOf = (args) => {
118
+ const cwd = input.trackedCwd?.();
119
+ return {
120
+ ...classicEventBase(input.identity, input.observedPermissionMode?.()),
121
+ tool: screenedName,
122
+ tool_use_id: toolCallId,
123
+ input: judgedInputOf(args),
124
+ ...(typeof cwd === "string" ? { cwd } : {}),
125
+ ...(input.hookEnv !== undefined ? { env: input.hookEnv } : {}),
126
+ };
127
+ };
128
+ return {
129
+ screen: async (args, subject) => {
130
+ let outcome;
131
+ try {
132
+ outcome = await dispatchClassic(bus, "classic.PreToolUse", eventOf(args), { ...(input.abortSignal !== undefined ? { signal: input.abortSignal } : {}), checkAnswer: preToolUseAnswerViolation });
133
+ }
134
+ catch (err) {
135
+ return { kind: "refused", reason: preToolUseRefusedReason(subject, { kind: "failed", registration: "engine", cause: "threw", reason: `could not raise the screening: ${describeThrown(err)}`, skipped: [] }) };
136
+ }
137
+ if (outcome === undefined || outcome.kind === "aborted")
138
+ return { kind: "refused", reason: preToolUseRefusedReason(subject, undefined) };
139
+ if (outcome.kind === "failed")
140
+ return { kind: "refused", reason: preToolUseRefusedReason(subject, outcome) };
141
+ const r = screenPreToolUseResult(outcome.answer);
142
+ return { kind: "answered", answer: r === null || r === false ? undefined : r, ...(outcome.answeredBy !== undefined ? { answeredBy: outcome.answeredBy } : {}) };
143
+ },
144
+ deniedReason: (answer) => decisionText(answer) ?? `tool "${toolName}" blocked by a PreToolUse hook`,
145
+ };
195
146
  }
196
- export function createPreToolUseConstraintPolicy(preToolUse, env, onCrash, timeoutMs) {
197
- return brandPolicyAskClass({
147
+ export function createPreToolUseConstraintPolicy(chain, env) {
148
+ const judges = (p) => !p.observe;
149
+ const minted = brandPolicyAskClass({
198
150
  check: async (req, signal) => {
151
+ if (!chain.hasHandlers("classic.PreToolUse", judges))
152
+ return { action: "allow" };
199
153
  const unasked = unaskedSeatAnswer(req, signal, { aborted: `the inherited PreToolUse screening of "${req.toolName}" was not consulted: the run or turn was already interrupted`, unreachable: `the inherited PreToolUse screening of "${req.toolName}" was not consulted: nobody can be asked about this call` }, "hook");
200
154
  if (unasked !== undefined)
201
155
  return unasked;
202
- let r;
203
- const boundMs = resolveHookTimeoutMs(timeoutMs, onCrash);
156
+ const subject = `this call to "${req.toolName}"`;
157
+ let outcome;
204
158
  try {
205
- const seat = await runHookSeat("preToolUse", { timeoutMs: boundMs }, (sig) => preToolUse(req.toolName, req.args, { toolCallId: req.toolCallId, toolName: req.toolName, signal: sig, ...(env !== undefined ? { env } : {}) }));
206
- if (seat.expired) {
207
- try {
208
- onCrash?.(hookSeatExpiredError("preToolUse", boundMs, seat.cause, `the inherited screening of "${req.toolName}" was refused fail-closed`));
209
- }
210
- catch {
211
- }
212
- return { action: "deny", message: preToolUseUnansweredReason(`this call to "${req.toolName}"`, boundMs, seat.cause), decisionReason: "hook" };
213
- }
214
- r = screenPreToolUseResult(seat.value);
159
+ outcome = await chain.dispatch("classic.PreToolUse", { tool: req.toolName, tool_use_id: req.toolCallId, input: judgedInputOf(req.args), ...(env !== undefined ? { env } : {}) }, {
160
+ bottom: engineCore,
161
+ participant: judges,
162
+ ...(signal !== undefined ? { signal } : {}),
163
+ checkAnswer: (a) => (a === ENGINE_CORE_ANSWER ? undefined : preToolUseAnswerViolation(a)),
164
+ });
215
165
  }
216
166
  catch (err) {
217
- try {
218
- onCrash?.(err);
219
- }
220
- catch {
221
- }
222
- return { action: "deny", message: preToolUseCrashReason(`this call to "${req.toolName}"`, err), decisionReason: "hook" };
167
+ return { action: "deny", message: preToolUseRefusedReason(subject, { kind: "failed", registration: "engine", cause: "threw", reason: `could not raise the screening: ${describeThrown(err)}`, skipped: [] }), decisionReason: "hook" };
223
168
  }
224
- if (r === undefined)
169
+ if (outcome.kind === "aborted")
170
+ return abortedSeatDeny(req, `the inherited PreToolUse screening of "${req.toolName}" ended when the run or turn was interrupted`, "hook");
171
+ if (outcome.kind === "failed")
172
+ return { action: "deny", message: preToolUseRefusedReason(subject, outcome), decisionReason: "hook" };
173
+ const r = screenPreToolUseResult(outcome.answer);
174
+ if (r === undefined || r === null || r === false)
225
175
  return { action: "allow" };
226
176
  if (r.action === "deny") {
227
177
  return { action: "deny", message: decisionText(r) ?? `tool "${req.toolName}" blocked by a PreToolUse hook`, decisionReason: "hook" };
@@ -239,6 +189,8 @@ export function createPreToolUseConstraintPolicy(preToolUse, env, onCrash, timeo
239
189
  return r.updatedInput !== undefined ? { action: "allow", updatedInput: r.updatedInput, ...stated } : { action: "allow", ...stated };
240
190
  },
241
191
  }, "hook");
192
+ recordScreeningChain(minted, chain);
193
+ return minted;
242
194
  }
243
195
  export function askCarryRowMembers(carry) {
244
196
  if (carry === undefined)
@@ -253,54 +205,21 @@ export function askCarryRowMembers(carry) {
253
205
  ...(classed !== undefined ? classed : {}),
254
206
  };
255
207
  }
256
- export function createPreToolUseScreening(preToolUse, input, hookSeatMs, notifier) {
257
- if (preToolUse === undefined)
258
- return undefined;
259
- const { toolCallId, toolName } = input.event;
260
- const screenedName = wireOf("gate.preToolUse", input.event);
261
- const hookCtx = (seatSignal) => ({
262
- toolCallId,
263
- toolName: screenedName,
264
- ...(seatSignal !== undefined ? { signal: seatSignal } : {}),
265
- ...(() => {
266
- const c = input.trackedCwd?.();
267
- return typeof c === "string" ? { cwd: c } : {};
268
- })(),
269
- ...(input.hookEnv !== undefined ? { env: input.hookEnv } : {}),
270
- ...(input.identity !== undefined ? { identity: input.identity } : {}),
271
- });
272
- const bound = { timeoutMs: hookSeatMs, ...(input.abortSignal !== undefined ? { signal: input.abortSignal } : {}), abortEnds: true };
273
- return {
274
- screen: (args) => runHookSeat("preToolUse", bound, (sig) => preToolUse(screenedName, args, hookCtx(sig))),
275
- screened: screenPreToolUseResult,
276
- crashReason: preToolUseCrashReason,
277
- unansweredReason: async (subject, cause) => {
278
- if (cause === "timeout")
279
- traceHookCrash(input, hookSeatExpiredError("preToolUse", hookSeatMs, cause, `${subject} was NOT executed (fail-closed) and the screening face was signalled to stop`), notifier);
280
- return preToolUseUnansweredReason(subject, hookSeatMs, cause);
281
- },
282
- deniedReason: (answer) => decisionText(answer) ?? `tool "${toolName}" blocked by a PreToolUse hook`,
283
- refusedReason: (answer) => String(answer.message ?? `the PreToolUse hook's result for "${toolName}" was refused by the engine`),
284
- };
285
- }
286
208
  export async function runToolGate(input) {
287
- const { event, preToolUse, adjudicate, resolveAsk, suspendAsk } = input;
209
+ const { event, adjudicate, resolveAsk, suspendAsk } = input;
288
210
  const { toolCallId, toolName } = event;
289
211
  const callSignal = input.callSignal;
290
212
  const modelInput = event.input;
213
+ const owned = ownArgs(modelInput);
214
+ const args = owned.ok ? owned.value : modelInput;
291
215
  const notifier = createSafeNotifier(input.onNotifyError !== undefined ? { onError: input.onNotifyError } : undefined);
292
- const hookSeatMs = resolveHookTimeoutMs(input.hookTimeoutMs, (err) => traceHookCrash(input, err, notifier));
293
- const observerBound = { timeoutMs: hookSeatMs, ...(input.abortSignal !== undefined ? { signal: input.abortSignal } : {}) };
294
- const notifyPermissionDeniedSeat = async (payload) => {
295
- if (input.permissionDenied === undefined)
296
- return;
297
- await notifier.notifyAsync(async () => {
298
- const seat = await runHookSeat("permissionDenied", observerBound, (sig) => input.permissionDenied?.({ ...payload, signal: sig }));
299
- if (seat.expired)
300
- throw hookSeatExpiredError("permissionDenied", hookSeatMs, seat.cause, "the deny observation was abandoned; the deny itself is unchanged");
301
- }, "toolGate.permissionDenied");
216
+ const notifyPermissionDeniedSeat = (payload) => {
217
+ const mode = input.observedPermissionMode?.();
218
+ const seen = mode !== undefined ? { ...payload, permissionMode: mode } : payload;
219
+ const onHostObserverFailure = (err) => void notifier.notify(() => { throw err; }, "toolGate.permissionDenied");
220
+ return observePermissionDenied({ legBus: input.modBus, hostObserver: input.permissionDenied, payload: seen, signal: input.abortSignal, onHostObserverFailure });
302
221
  };
303
- const screening = createPreToolUseScreening(preToolUse, input, hookSeatMs, notifier);
222
+ const screening = createPreToolUseScreening(input);
304
223
  const pass = {
305
224
  input,
306
225
  event,
@@ -315,8 +234,8 @@ export async function runToolGate(input) {
315
234
  notifyPermissionDenied: notifyPermissionDeniedSeat,
316
235
  screening,
317
236
  afterFold: runGateLanes,
318
- currentInput: modelInput,
319
- req: { toolName, args: modelInput, toolCallId, ...(() => { const f = input.toolFaceOf?.(toolName); return f !== undefined ? { face: f } : {}; })() },
237
+ currentInput: args,
238
+ req: Object.freeze({ toolName, args, toolCallId, ...(() => { const f = input.toolFaceOf?.(toolName); return f !== undefined ? { face: f } : {}; })() }),
320
239
  preToolContext: [],
321
240
  hookAsk: undefined,
322
241
  parkFailed: undefined,
@@ -326,29 +245,15 @@ export async function runToolGate(input) {
326
245
  tightenedBy: undefined,
327
246
  policyRewrite: undefined,
328
247
  };
248
+ if (!owned.ok)
249
+ return await unownedArgsExit(pass, owned.reason);
329
250
  if (screening !== undefined) {
330
- let r;
331
- let unanswered;
332
- try {
333
- const seat = await screening.screen(pass.currentInput);
334
- if (seat.expired)
335
- unanswered = seat.cause;
336
- else
337
- r = screening.screened(seat.value);
338
- }
339
- catch (err) {
340
- const reason = screening.crashReason(`this call to "${toolName}"`, err);
341
- traceHookCrash(input, err, notifier);
342
- return await engineFailClosedExit(pass, reason);
343
- }
344
- if (unanswered !== undefined) {
345
- const reason = await screening.unansweredReason(`this call to "${toolName}"`, unanswered);
346
- return await engineFailClosedExit(pass, reason);
251
+ const screened = await screening.screen(pass.currentInput, `this call to "${toolName}"`);
252
+ if (screened.kind === "refused") {
253
+ return await engineFailClosedExit(pass, screened.reason);
347
254
  }
255
+ const r = screened.answer;
348
256
  if (r) {
349
- if (isEngineRefusal(r)) {
350
- return await engineFailClosedExit(pass, screening.refusedReason(r));
351
- }
352
257
  if (r.additionalContext) {
353
258
  pass.preToolContext.push(r.additionalContext);
354
259
  }
@@ -362,7 +267,7 @@ export async function runToolGate(input) {
362
267
  pass.hookAsk = r;
363
268
  }
364
269
  if (r.action === "allow")
365
- pass.hookAllowed = true;
270
+ pass.hookAllowedBy = screened.answeredBy !== undefined ? [screened.answeredBy] : [];
366
271
  }
367
272
  }
368
273
  return await runGateFold(pass);
@@ -24,9 +24,27 @@
24
24
  * before the frame and the transcript read them. A block whose bytes the admission refuses becomes a text
25
25
  * block that names the tool, the refusal and the size — never the bytes, and never silently nothing.
26
26
  */
27
- import type { DocumentContent, ImageContent } from "../../internal/llm.js";
28
- import { type ImageDimensions, type ImageDownsampler } from "../../core/mcp.js";
29
- import { type MediaBlock } from "../../core/media-byte-cap.js";
27
+ import type { DocumentContent, ImageContent } from "../internal/llm.js";
28
+ import { type ImageDimensions, type ImageDownsampler } from "./image-downsample.js";
29
+ import { type MediaBlock } from "./media-byte-cap.js";
30
+ /** Byte cap on a Read-image WITHOUT a downsampler: an image file is returned AS a visual
31
+ * `ImageContent` block (base64) rather than refused. Bounded so a huge image cannot blow the request.
32
+ * This stat-time cap only bounds the READ; the accept/refuse decision is the base64 gate below (the
33
+ * provider limit is on base64 LENGTH, so the effective no-sharp accept bound is raw ≤ 3.75MB). */
34
+ export declare const MAX_IMAGE_READ_BYTES: number;
35
+ /** Byte cap on a Read-image WITH a downsampler: sharp can shrink a big photo to CC's 2000×2000/3.75MB
36
+ * target, so the smaller hard refusal does not apply (CC readImageWithTokenBudget reads the file
37
+ * unbounded; we keep an OOM sanity bound — deliberate delta, camera photos fit comfortably). */
38
+ export declare const MAX_IMAGE_DOWNSAMPLE_INPUT_BYTES: number;
39
+ /** Max raw size sent whole as a document block (CC `PDF_TARGET_RAW_SIZE`). */
40
+ export declare const PDF_TARGET_RAW_SIZE: number;
41
+ /** Verify the raw bytes actually ARE the image format the extension claims (magic-number sniff). Extension alone
42
+ * is forgeable: a `.png` holding text / an empty file / a truncated blob would otherwise become a malformed
43
+ * `ImageContent` that makes the NEXT provider request fail (400). Pure — no I/O. */
44
+ export declare function imageMagicMatches(bytes: Uint8Array, mimeType: string): boolean;
45
+ /** True when the bytes start with the `%PDF-` magic. Magic outranks extension both ways: a mis-named
46
+ * `.pdf` without it is refused, and a non-`.pdf` file carrying it is read AS a PDF. */
47
+ export declare function pdfMagicMatches(bytes: Uint8Array): boolean;
30
48
  /** The image types the content API accepts — the only ones a signature check can verify. */
31
49
  export declare const ADMITTED_IMAGE_MIME_TYPES: readonly ["image/png", "image/jpeg", "image/gif", "image/webp"];
32
50
  /** The raw-byte read cap for an image, with or without a downsampler. */
@@ -1,9 +1,27 @@
1
- import { MCP_IMAGE_MAX_BASE64 } from "../../core/mcp.js";
2
- import { claimedMediaType } from "../../core/media-byte-cap.js";
3
- import { readMember } from "../../core/thrown-value.js";
4
- import { imageMagicMatches } from "./safety.js";
5
- import { MAX_IMAGE_READ_BYTES, MAX_IMAGE_DOWNSAMPLE_INPUT_BYTES } from "./fs-shared.js";
6
- import { PDF_TARGET_RAW_SIZE, pdfMagicMatches } from "./pdf.js";
1
+ import { MCP_IMAGE_MAX_BASE64 } from "./image-downsample.js";
2
+ import { claimedMediaType } from "./media-byte-cap.js";
3
+ import { readMember } from "./thrown-value.js";
4
+ export const MAX_IMAGE_READ_BYTES = 5 * 1024 * 1024;
5
+ export const MAX_IMAGE_DOWNSAMPLE_INPUT_BYTES = 64 * 1024 * 1024;
6
+ export const PDF_TARGET_RAW_SIZE = 20 * 1024 * 1024;
7
+ export function imageMagicMatches(bytes, mimeType) {
8
+ const b = bytes;
9
+ switch (mimeType) {
10
+ case "image/png":
11
+ return b.length >= 8 && b[0] === 0x89 && b[1] === 0x50 && b[2] === 0x4e && b[3] === 0x47 && b[4] === 0x0d && b[5] === 0x0a && b[6] === 0x1a && b[7] === 0x0a;
12
+ case "image/jpeg":
13
+ return b.length >= 3 && b[0] === 0xff && b[1] === 0xd8 && b[2] === 0xff;
14
+ case "image/gif":
15
+ return b.length >= 6 && b[0] === 0x47 && b[1] === 0x49 && b[2] === 0x46 && b[3] === 0x38 && (b[4] === 0x37 || b[4] === 0x39) && b[5] === 0x61;
16
+ case "image/webp":
17
+ return b.length >= 12 && b[0] === 0x52 && b[1] === 0x49 && b[2] === 0x46 && b[3] === 0x46 && b[8] === 0x57 && b[9] === 0x45 && b[10] === 0x42 && b[11] === 0x50;
18
+ default:
19
+ return false;
20
+ }
21
+ }
22
+ export function pdfMagicMatches(bytes) {
23
+ return bytes.length >= 5 && bytes[0] === 0x25 && bytes[1] === 0x50 && bytes[2] === 0x44 && bytes[3] === 0x46 && bytes[4] === 0x2d;
24
+ }
7
25
  export const ADMITTED_IMAGE_MIME_TYPES = Object.freeze(["image/png", "image/jpeg", "image/gif", "image/webp"]);
8
26
  export function imageReadCap(downsampler) {
9
27
  return downsampler ? MAX_IMAGE_DOWNSAMPLE_INPUT_BYTES : MAX_IMAGE_READ_BYTES;
@@ -39,8 +39,8 @@ export interface LockedPreflight {
39
39
  /** The validated lock set (empty when the deployment declares none). */
40
40
  lockedKeys: ReadonlySet<LockedKey>;
41
41
  /** Effective MCP server list for this task: a validated, frozen SNAPSHOT of `spec.mcp` when the
42
- * key is unlocked (see {@link snapshotAndValidateMcpEntries} — the content-class declaration is read once
43
- * and judged here, so no mint site downstream can be handed a different value than the door
42
+ * key is unlocked (see {@link snapshotAndValidateMcpEntries} — the content-class and `toolAxes` declarations
43
+ * are read once and judged here, so no mint site downstream can be handed a different value than the door
44
44
  * approved); with `mcp` locked a spec-supplied value has already been refused, so this is always
45
45
  * `undefined` (core has no deployment-level MCP seat — a locked deployment mounts no
46
46
  * task-supplied servers). */
@@ -84,15 +84,36 @@ export declare function resolveLockedKeys(config: LockedConfig | undefined): Rea
84
84
  * Boundary, stated: the copy is one level deep — nested option objects (transport, headers, env,
85
85
  * toolAxes) stay shared with the caller's entry exactly as before, because the axis this owns is the
86
86
  * content class; readers of the nested shapes normalize their own values (the transport DISCRIMINATOR
87
- * is derived, never echoed raw). Own ENUMERABLE properties only: an entry whose fields live on a
88
- * prototype was never the plain configuration record this type describes, and its absent class reads
89
- * fail-closed like any other absence.
87
+ * is derived, never echoed raw). `toolAxes` is the one nested shape both entrances replace with its
88
+ * reader's plain copy ({@link judgeEntryToolAxes}), and the one member this snapshot reads BY NAME rather
89
+ * than by spread, once: a declaration an entry carries as a non-enumerable or inherited property would
90
+ * otherwise vanish before any reader sees it, and an absent caller axis is a tightening lost, not a
91
+ * fail-closed absence. Every other member is taken as own ENUMERABLE properties only: an entry whose
92
+ * fields live on a prototype was never the plain configuration record this type describes, and its
93
+ * absent class reads fail-closed like any other absence.
90
94
  *
91
95
  * Exported because the SECOND boundary needs the identical guarantee: `materializeMcpTools` is public
92
96
  * and a library caller reaches it without passing any door, so it snapshots its own input through
93
97
  * this same function (idempotent over an already-frozen entry). One spelling, both entrances.
94
98
  */
95
99
  export declare function snapshotMcpEntries(entries: readonly McpServerSpec[]): McpServerSpec[];
100
+ /**
101
+ * The `toolAxes` question for ONE snapshot entry — asked by the preparation door (a refusal ends the prepare) and by the materialization
102
+ * entrance (a refusal fails that server's dial), so there is one reading, one copy and one sentence whichever time it is asked.
103
+ * `ok: true` carries the entry with the reader's PLAIN COPY of the axes in place of the caller's object: what was judged is the very value
104
+ * the connect and every refresh read, not a live object that could answer differently later. The copy is frozen with the entry — a tool
105
+ * that shallow-copies a server (`mountedMcp()`) to customise its axes must not rewrite what the parent reads. `ok: false` carries the
106
+ * coded refusal (`config.invalid_argument`) naming the server, the tool and the member, never a value.
107
+ */
108
+ export declare function judgeEntryToolAxes(copy: McpServerSpec): {
109
+ ok: true;
110
+ entry: McpServerSpec;
111
+ } | {
112
+ ok: false;
113
+ error: Error & {
114
+ code: string;
115
+ };
116
+ };
96
117
  /**
97
118
  * The single preflight resolver: validate the lock declaration, refuse a spec that tries to occupy
98
119
  * a locked slot (`config.locked_key`, two-state — the whole prepare is rejected, nothing is
@@ -1,3 +1,4 @@
1
+ import { readMcpToolAxes } from "./mcp-server-spec.js";
1
2
  import { isToolContentOrigin, TOOL_CONTENT_ORIGINS } from "./memory-engine/content-origin.js";
2
3
  import { inlineUntrusted } from "./untrusted-text.js";
3
4
  import { assertNoRetiredToolPolicyKeys } from "./retired-keys.js";
@@ -27,7 +28,10 @@ export function resolveLockedKeys(config) {
27
28
  return keys;
28
29
  }
29
30
  export function snapshotMcpEntries(entries) {
30
- return entries.map((entry) => Object.freeze({ ...entry }));
31
+ return entries.map((entry) => {
32
+ const { toolAxes, ...rest } = entry;
33
+ return Object.freeze((toolAxes === undefined ? rest : { ...rest, toolAxes }));
34
+ });
31
35
  }
32
36
  function describeDeclared(value) {
33
37
  try {
@@ -42,20 +46,41 @@ function describeDeclared(value) {
42
46
  }
43
47
  }
44
48
  }
49
+ const serverNameOf = (copy) => inlineUntrusted(typeof copy.name === "string" ? JSON.stringify(copy.name) : describeDeclared(copy.name), 80);
50
+ export function judgeEntryToolAxes(copy) {
51
+ const { toolAxes: declaredAxes, ...rest } = copy;
52
+ const axes = readMcpToolAxes(declaredAxes);
53
+ if (!axes.ok) {
54
+ return {
55
+ ok: false,
56
+ error: codedError("config.invalid_argument", `MCP server ${serverNameOf(copy)} declares toolAxes the engine cannot read: ${inlineUntrusted(axes.problem, 240)}. A per-tool safety-axis declaration is the ` +
57
+ `caller's trust root for the approval gate, so it is refused rather than partly applied — dropping one key or defaulting one word ` +
58
+ `would leave a declaration that reads as in force while it is not.`),
59
+ };
60
+ }
61
+ if (axes.toolAxes !== undefined) {
62
+ for (const perTool of Object.values(axes.toolAxes))
63
+ Object.freeze(perTool);
64
+ Object.freeze(axes.toolAxes);
65
+ }
66
+ return { ok: true, entry: Object.freeze(axes.toolAxes === undefined ? rest : { ...rest, toolAxes: axes.toolAxes }) };
67
+ }
45
68
  function snapshotAndValidateMcpEntries(entries) {
46
- const copies = snapshotMcpEntries(entries);
47
- for (const copy of copies) {
69
+ return snapshotMcpEntries(entries).map((copy) => {
48
70
  const declared = copy.contentOrigin;
49
71
  if (declared !== undefined && !isToolContentOrigin(declared)) {
50
- throw codedError("config.mcp_content_class", `MCP server ${inlineUntrusted(typeof copy.name === "string" ? JSON.stringify(copy.name) : describeDeclared(copy.name), 80)} declares contentOrigin ` +
72
+ throw codedError("config.mcp_content_class", `MCP server ${serverNameOf(copy)} declares contentOrigin ` +
51
73
  `${inlineUntrusted(describeDeclared(declared), 80)}, which is not one of ` +
52
74
  `${TOOL_CONTENT_ORIGINS.map((v) => `"${v}"`).join(" | ")}. The declaration decides whether this server's tools ` +
53
75
  `mark the session's memory externally exposed — a value this engine cannot read is refused at the door rather ` +
54
76
  `than folded to a class, because folding it would let a deployment believe a declaration is in force while every ` +
55
77
  `call keeps writing a one-way durable mark.`);
56
78
  }
57
- }
58
- return copies;
79
+ const judged = judgeEntryToolAxes(copy);
80
+ if (!judged.ok)
81
+ throw judged.error;
82
+ return judged.entry;
83
+ });
59
84
  }
60
85
  export function preflightLockedConfig(spec, deps) {
61
86
  const lockedKeys = resolveLockedKeys(deps.lockedConfig);
@@ -56,8 +56,11 @@ export declare class McpConnectionPool {
56
56
  * transport object that answers differently to two readers cannot split the dial from its key); every other transport member is read here.
57
57
  * The declaration's mount identity (`fingerprint`) is part of the key when declared: the revocation probe is asked with it, so two mounts the
58
58
  * host tells apart never share one connection (an undeclared fingerprint leaves the key as it always was).
59
+ * So is the startup bound the dial runs under (`startupMs`, the dial's one reading of {@link mcpStartupTimeoutMs}, threaded like `kind`):
60
+ * a connection is dialled under the declaration of the mount that dials it, so a mount never waits on, or shares, a dial bounded by
61
+ * another mount's clock. No bound in force (none declared, no environment seat) leaves the key as it always was.
59
62
  */
60
- static keyOf(spec: McpServerSpec, principal: string | undefined, kind: string | undefined): string;
63
+ static keyOf(spec: McpServerSpec, principal: string | undefined, kind: string | undefined, startupMs: number | undefined): string;
61
64
  /**
62
65
  * Lease the connection for `key`, dialling it with `dial` when none is live. `fresh` replaces the pool's current connection with a new
63
66
  * dial (a re-dial): the connection it replaces lives on until its other holders release it. Resolves `undefined` once the pool is
@@ -4,10 +4,15 @@ export class McpConnectionPool {
4
4
  dialing = new Map();
5
5
  generation = new Map();
6
6
  shut = false;
7
- static keyOf(spec, principal, kind) {
7
+ static keyOf(spec, principal, kind, startupMs) {
8
8
  const rest = Object.fromEntries(Object.keys(spec.transport).filter((k) => k !== "kind").map((k) => [k, Reflect.get(spec.transport, k)]));
9
9
  const fingerprint = spec.fingerprint;
10
- return canonicalize(fingerprint === undefined ? [spec.name, kind ?? null, rest, principal ?? null] : [spec.name, kind ?? null, rest, principal ?? null, fingerprint]);
10
+ const identity = [spec.name, kind ?? null, rest, principal ?? null];
11
+ if (fingerprint !== undefined)
12
+ identity.push(fingerprint);
13
+ if (startupMs !== undefined)
14
+ identity.push({ startupTimeoutMs: startupMs });
15
+ return canonicalize(identity);
11
16
  }
12
17
  async acquire(key, dial, opts) {
13
18
  if (this.shut)
@@ -38,15 +38,17 @@ export interface McpProbeOptions {
38
38
  * on a real leg — so a server that applies per-user rules answers the probe as it would answer the
39
39
  * task. */
40
40
  principal?: string;
41
- /** Per-server ceiling on the VERDICT, in whole milliseconds within `[1, MCP_ENV_MS_MAX]` (the ceiling
42
- * every env-supplied MCP bound keeps, because a larger delay is silently rewritten to 1 ms). When it
43
- * elapses, THAT server's row reads `failed` with `errorCode: "timeout"` and the walk moves on; nothing
44
- * throws. It does NOT end the dial — nothing here can — so the transport stays open until the dial
45
- * lands on its own; see the residue note on {@link probeMcpServers}.
41
+ /** An OVERALL ceiling on the VERDICT for each server, in whole milliseconds within `[1, MCP_ENV_MS_MAX]` (the
42
+ * ceiling every env-supplied MCP bound keeps, because a larger delay is silently rewritten to 1 ms). The
43
+ * caller's own choice, and it lives BESIDE the per-phase startup bounds the dial runs under — whichever
44
+ * arrives first decides. When it elapses, THAT server's row reads `failed` with `errorCode: "timeout"` and
45
+ * the walk moves on; nothing throws. It does NOT end the dial — nothing here can — so the transport stays
46
+ * open until the dial lands on its own; see the residue note on {@link probeMcpServers}.
46
47
  *
47
- * Default: the engine's own startup-phase bound ({@link mcpStartupTimeoutMs}, env `MCP_TIMEOUT`) when a
48
- * deployment set one; absent there, this module runs no clock and the answer for that server is
49
- * whatever the dial's own request budgets produce — which bound the REQUESTS, not the dial. */
48
+ * Default: none. The probe has no clock of its own: it dials through the entrance a task does, so each
49
+ * startup phase (the handshake, then the initial listing) carries that server's own bound from the one
50
+ * reader ({@link import("./mcp.js").mcpStartupTimeoutMs}: its `startupTimeoutMs`, else env `MCP_TIMEOUT`, else
51
+ * the SDK's 60 000 ms) — exactly what a task allows it. */
50
52
  timeoutMs?: number;
51
53
  /** Abort the whole probe. The call rejects with the signal's own reason (a bare `abort()` gives an
52
54
  * `AbortError`) AFTER every server it had opened is closed — see the residue contract on
@@ -102,7 +104,8 @@ export interface McpProbeOptions {
102
104
  * return, and NOT that the call itself is bounded. What bounds it, stated part by part rather than
103
105
  * summarised into a number that would be wrong:
104
106
  * · a dial has two REQUEST-BUDGET phases, each carrying the startup-phase bound ({@link
105
- * mcpStartupTimeoutMs}, env `MCP_TIMEOUT`, else the SDK's 60 000 ms default): the handshake, one
107
+ * import("./mcp.js").mcpStartupTimeoutMs}: the server's own `startupTimeoutMs`, else env `MCP_TIMEOUT`, else the SDK's
108
+ * 60 000 ms default): the handshake, one
106
109
  * request; and the initial tool listing, a PAGINATED WALK whose whole budget is that same number
107
110
  * (however many pages it takes — and no request at all when the peer advertises no tools). Two
108
111
  * budgets, so twice that, not once;