@sema-agent/server 7.132.0 → 7.134.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 (473) hide show
  1. package/MIGRATION.md +353 -0
  2. package/README.md +8 -9
  3. package/README.zh-CN.md +7 -6
  4. package/USAGE.md +301 -64
  5. package/deploy/sema-up/README.md +35 -1
  6. package/deploy/sema-up/chart/Chart.yaml +1 -1
  7. package/deploy/sema-up/chart/templates/NOTES.txt +15 -0
  8. package/deploy/sema-up/chart/templates/_helpers.tpl +129 -0
  9. package/deploy/sema-up/chart/templates/sealed-key.yaml +24 -0
  10. package/deploy/sema-up/chart/templates/server-v4pro.yaml +19 -2
  11. package/deploy/sema-up/chart/templates/server.yaml +19 -2
  12. package/deploy/sema-up/chart/values-full-single.yaml +5 -1
  13. package/deploy/sema-up/chart/values.yaml +34 -0
  14. package/deploy/sema-up/stack/compose.yaml +3 -0
  15. package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -2
  16. package/dist/adoption/plan.d.ts +3 -2
  17. package/dist/adoption/plan.js +7 -5
  18. package/dist/adoption/runner.js +3 -10
  19. package/dist/adoption/sql.d.ts +3 -2
  20. package/dist/adoption/sql.js +3 -5
  21. package/dist/adoption/wire.d.ts +4 -1
  22. package/dist/adoption/wire.js +1 -0
  23. package/dist/approval-ask-audit-store.d.ts +32 -14
  24. package/dist/approval-ask-audit-store.js +272 -74
  25. package/dist/approval-ask-machine.d.ts +15 -0
  26. package/dist/approval-ask-machine.js +6 -0
  27. package/dist/approval-ask-retention.d.ts +136 -0
  28. package/dist/approval-ask-retention.js +102 -0
  29. package/dist/approval-card.d.ts +83 -23
  30. package/dist/approval-card.js +45 -15
  31. package/dist/approval-content-kind.d.ts +5 -2
  32. package/dist/approval-content-kind.js +16 -3
  33. package/dist/approval-deny-reasons.d.ts +1 -1
  34. package/dist/approval-gate-currency.d.ts +72 -0
  35. package/dist/approval-gate-currency.js +94 -0
  36. package/dist/approval.d.ts +15 -0
  37. package/dist/approval.js +55 -17
  38. package/dist/audit.d.ts +27 -10
  39. package/dist/audit.js +12 -16
  40. package/dist/bake-runner/main.js +3 -2
  41. package/dist/boot/coordinators.d.ts +6 -1
  42. package/dist/boot/coordinators.js +6 -3
  43. package/dist/boot/deferred-sandbox-path-env.js +1 -1
  44. package/dist/boot/execution-env.js +9 -7
  45. package/dist/boot/execution-lane.js +11 -0
  46. package/dist/boot/leader.d.ts +2 -0
  47. package/dist/boot/leader.js +4 -1
  48. package/dist/boot/memory-boundary.js +2 -2
  49. package/dist/boot/memory-consolidation.d.ts +5 -4
  50. package/dist/boot/memory-consolidation.js +7 -6
  51. package/dist/boot/org-delivery.d.ts +28 -0
  52. package/dist/boot/org-delivery.js +20 -0
  53. package/dist/boot/read-deny-anchor-audit.js +2 -2
  54. package/dist/boot/reapers.d.ts +3 -0
  55. package/dist/boot/reapers.js +21 -1
  56. package/dist/boot/resolve-spec.d.ts +3 -0
  57. package/dist/boot/resolve-spec.js +60 -81
  58. package/dist/boot/runner-deps.d.ts +18 -5
  59. package/dist/boot/runner-deps.js +10 -0
  60. package/dist/boot/session-faces.d.ts +1 -0
  61. package/dist/boot/session-faces.js +4 -2
  62. package/dist/boot/stage-02-web-admin-pull.js +4 -1
  63. package/dist/boot/stage-06-runners.d.ts +6 -3
  64. package/dist/boot/stage-06-runners.js +20 -4
  65. package/dist/boot/stage-07-capability-layer.d.ts +4 -1
  66. package/dist/boot/stage-07-capability-layer.js +24 -3
  67. package/dist/boot/stage-08-reapers.d.ts +4 -1
  68. package/dist/boot/stage-08-reapers.js +2 -2
  69. package/dist/boot/stage-09-leader.d.ts +5 -1
  70. package/dist/boot/stage-09-leader.js +2 -2
  71. package/dist/boot/stage-10-http-server.d.ts +5 -1
  72. package/dist/boot/stage-10-http-server.js +6 -6
  73. package/dist/boot/stores.d.ts +8 -0
  74. package/dist/boot/stores.js +10 -14
  75. package/dist/boot/web-admin.d.ts +10 -0
  76. package/dist/boot/web-admin.js +162 -65
  77. package/dist/boot/workflow-orchestration.d.ts +2 -0
  78. package/dist/boot/workflow-orchestration.js +2 -1
  79. package/dist/brain.js +8 -3
  80. package/dist/breaker-key.d.ts +6 -0
  81. package/dist/breaker-key.js +29 -0
  82. package/dist/budget.js +5 -1
  83. package/dist/caller-text-echo.d.ts +11 -6
  84. package/dist/caller-text-echo.js +10 -12
  85. package/dist/canonical-json.d.ts +2 -41
  86. package/dist/canonical-json.js +2 -13
  87. package/dist/capabilities/center-plugins.d.ts +7 -0
  88. package/dist/capabilities/center-plugins.js +1 -1
  89. package/dist/capabilities/composite-members.d.ts +1 -1
  90. package/dist/capabilities/composite-members.js +1 -1
  91. package/dist/capabilities/execution-lane.js +2 -2
  92. package/dist/capabilities/hands-lane.d.ts +21 -0
  93. package/dist/capabilities/hands-lane.js +10 -0
  94. package/dist/capabilities/mcp-probe.d.ts +36 -4
  95. package/dist/capabilities/mcp-probe.js +29 -6
  96. package/dist/capabilities/scenarios.d.ts +63 -7
  97. package/dist/capabilities/scenarios.js +39 -7
  98. package/dist/capability-facts.d.ts +36 -4
  99. package/dist/capability-facts.js +30 -4
  100. package/dist/center-config-tier.d.ts +69 -0
  101. package/dist/center-config-tier.js +42 -0
  102. package/dist/checkpoint-ctx-seal-m28.d.ts +42 -0
  103. package/dist/checkpoint-ctx-seal-m28.js +19 -0
  104. package/dist/checkpoint-identity.d.ts +16 -0
  105. package/dist/checkpoint-identity.js +19 -0
  106. package/dist/config-catalog.d.ts +17 -10
  107. package/dist/config-catalog.js +43 -28
  108. package/dist/config-d-migration.d.ts +3 -1
  109. package/dist/config-d-migration.js +2 -2
  110. package/dist/config-dir-trust.d.ts +114 -0
  111. package/dist/config-dir-trust.js +388 -0
  112. package/dist/config-invariants.d.ts +18 -5
  113. package/dist/config-invariants.js +35 -3
  114. package/dist/config-provider.d.ts +6 -1
  115. package/dist/config-provider.js +6 -2
  116. package/dist/config-types.d.ts +71 -14
  117. package/dist/config-types.js +8 -0
  118. package/dist/config.d.ts +13 -0
  119. package/dist/config.js +121 -59
  120. package/dist/delegated-session-owner.d.ts +185 -0
  121. package/dist/delegated-session-owner.js +119 -0
  122. package/dist/device-protocol.d.ts +5 -3
  123. package/dist/device-protocol.js +1 -1
  124. package/dist/device-ws-hub.js +21 -2
  125. package/dist/device-ws-protocol.d.ts +70 -6
  126. package/dist/device-ws-protocol.js +50 -23
  127. package/dist/elicitation.js +3 -2
  128. package/dist/entry-problems.d.ts +34 -0
  129. package/dist/entry-problems.js +14 -0
  130. package/dist/execution-lane-caps.d.ts +49 -10
  131. package/dist/execution-lane-caps.js +43 -4
  132. package/dist/field-conflict.d.ts +44 -0
  133. package/dist/field-conflict.js +21 -0
  134. package/dist/file-history-disclosure.d.ts +34 -5
  135. package/dist/file-history-disclosure.js +2 -2
  136. package/dist/fleet/fleet-bus.d.ts +84 -6
  137. package/dist/fleet/fleet-bus.js +42 -9
  138. package/dist/hooks/classic-stations.d.ts +10 -5
  139. package/dist/hooks/classic-stations.js +4 -4
  140. package/dist/hooks/command-spawn.d.ts +57 -0
  141. package/dist/hooks/command-spawn.js +139 -0
  142. package/dist/hooks/hook-llm.js +2 -2
  143. package/dist/hooks/hook-runner.d.ts +127 -25
  144. package/dist/hooks/hook-runner.js +668 -287
  145. package/dist/hooks/hook-source.d.ts +44 -0
  146. package/dist/hooks/hook-source.js +40 -0
  147. package/dist/http/active-run-conflict.d.ts +5 -13
  148. package/dist/http/active-run-conflict.js +17 -27
  149. package/dist/http/admission.js +111 -60
  150. package/dist/http/approval-sweeps.js +58 -19
  151. package/dist/http/caller-trust.d.ts +77 -0
  152. package/dist/http/caller-trust.js +143 -0
  153. package/dist/http/checkpoint-ctx.d.ts +173 -18
  154. package/dist/http/checkpoint-ctx.js +171 -12
  155. package/dist/http/claimed-run.d.ts +4 -3
  156. package/dist/http/device-placement.d.ts +2 -4
  157. package/dist/http/device-placement.js +2 -1
  158. package/dist/http/dispatch.js +13 -7
  159. package/dist/http/durable-run-leg.d.ts +4 -32
  160. package/dist/http/durable-run-leg.js +37 -12
  161. package/dist/http/idempotency.d.ts +2 -2
  162. package/dist/http/idempotency.js +2 -2
  163. package/dist/http/owner-access.d.ts +56 -0
  164. package/dist/http/owner-access.js +42 -0
  165. package/dist/http/principal-gate.d.ts +78 -27
  166. package/dist/http/principal-gate.js +64 -14
  167. package/dist/http/readiness.d.ts +11 -5
  168. package/dist/http/readiness.js +10 -3
  169. package/dist/http/refusal-body.d.ts +12 -0
  170. package/dist/http/refusal-body.js +11 -0
  171. package/dist/http/request-guards.d.ts +16 -32
  172. package/dist/http/request-guards.js +31 -30
  173. package/dist/http/resume-ctx-read.d.ts +50 -6
  174. package/dist/http/resume-ctx-read.js +33 -7
  175. package/dist/http/resume-legs.d.ts +5 -5
  176. package/dist/http/resume-legs.js +163 -91
  177. package/dist/http/retired-service-deps.d.ts +43 -0
  178. package/dist/http/retired-service-deps.js +18 -0
  179. package/dist/http/route-ctx.d.ts +44 -37
  180. package/dist/http/route-ctx.js +4 -0
  181. package/dist/http/route-table.js +2 -0
  182. package/dist/http/routes/a2a-serve.js +3 -4
  183. package/dist/http/routes/admin-config-refresh.js +1 -1
  184. package/dist/http/routes/admin-drain.js +1 -1
  185. package/dist/http/routes/admin-memory-optout.js +5 -1
  186. package/dist/http/routes/adoption.js +2 -9
  187. package/dist/http/routes/agents-roster.js +2 -3
  188. package/dist/http/routes/approvals-assistant.js +91 -56
  189. package/dist/http/routes/background.js +3 -2
  190. package/dist/http/routes/capabilities.js +20 -4
  191. package/dist/http/routes/config-catalog.d.ts +3 -3
  192. package/dist/http/routes/config-catalog.js +1 -1
  193. package/dist/http/routes/devices.js +3 -17
  194. package/dist/http/routes/diagnostics.d.ts +3 -3
  195. package/dist/http/routes/diagnostics.js +6 -2
  196. package/dist/http/routes/fleet.js +4 -4
  197. package/dist/http/routes/images.js +6 -7
  198. package/dist/http/routes/leader.js +1 -8
  199. package/dist/http/routes/mcp-reconnect.d.ts +1 -1
  200. package/dist/http/routes/mcp-reconnect.js +3 -2
  201. package/dist/http/routes/memory-bundle.js +1 -1
  202. package/dist/http/routes/memory-compliance.js +1 -1
  203. package/dist/http/routes/memory-consolidation.js +1 -1
  204. package/dist/http/routes/memory-origin.d.ts +1 -1
  205. package/dist/http/routes/memory-origin.js +1 -1
  206. package/dist/http/routes/memory-policy.d.ts +1 -1
  207. package/dist/http/routes/memory-policy.js +3 -2
  208. package/dist/http/routes/notify-wake.js +8 -21
  209. package/dist/http/routes/observability.js +2 -2
  210. package/dist/http/routes/principal-inbox.d.ts +39 -0
  211. package/dist/http/routes/principal-inbox.js +76 -0
  212. package/dist/http/routes/retention-ops.js +2 -9
  213. package/dist/http/routes/rules.js +9 -22
  214. package/dist/http/routes/runs.d.ts +5 -0
  215. package/dist/http/routes/runs.js +63 -115
  216. package/dist/http/routes/session-sync.d.ts +3 -2
  217. package/dist/http/routes/session-sync.js +53 -48
  218. package/dist/http/routes/sessions-list.d.ts +1 -1
  219. package/dist/http/routes/sessions-list.js +3 -4
  220. package/dist/http/routes/sessions.js +33 -43
  221. package/dist/http/routes/side-query.js +6 -4
  222. package/dist/http/routes/tasks.js +71 -30
  223. package/dist/http/routes/trace-usage.js +7 -9
  224. package/dist/http/routes/workflows.d.ts +351 -0
  225. package/dist/http/routes/workflows.js +153 -119
  226. package/dist/http/run-declared-families.d.ts +16 -0
  227. package/dist/http/run-declared-families.js +12 -0
  228. package/dist/http/send.d.ts +24 -3
  229. package/dist/http/send.js +14 -2
  230. package/dist/http/server.d.ts +23 -18
  231. package/dist/http/server.js +20 -15
  232. package/dist/http/stored-body-replay.js +17 -4
  233. package/dist/http/submit-ctx.d.ts +4 -3
  234. package/dist/http/submit-ctx.js +23 -6
  235. package/dist/http/submit-replay.d.ts +4 -3
  236. package/dist/http/submit-replay.js +5 -4
  237. package/dist/http/wire-types.d.ts +17 -10
  238. package/dist/index.d.ts +3 -1
  239. package/dist/index.js +1 -1
  240. package/dist/lane-home-probe.d.ts +78 -9
  241. package/dist/lane-home-probe.js +78 -12
  242. package/dist/leader/endpoint.d.ts +4 -1
  243. package/dist/leader/endpoint.js +11 -10
  244. package/dist/leader/wire.d.ts +4 -0
  245. package/dist/leader/wire.js +8 -7
  246. package/dist/limit-refusal.d.ts +17 -5
  247. package/dist/limit-refusal.js +4 -1
  248. package/dist/main.js +1 -1
  249. package/dist/mcp-assertion-header.d.ts +31 -10
  250. package/dist/mcp-assertion-header.js +10 -3
  251. package/dist/memory-origin-fence.js +2 -2
  252. package/dist/memory-project-layer.d.ts +37 -0
  253. package/dist/memory-project-layer.js +46 -0
  254. package/dist/memory-scope.d.ts +23 -16
  255. package/dist/memory-scope.js +24 -8
  256. package/dist/memory-sync-client.d.ts +27 -13
  257. package/dist/memory-sync-client.js +107 -18
  258. package/dist/model-compat.d.ts +1 -1
  259. package/dist/model-entry-refusal.d.ts +9 -1
  260. package/dist/model-entry-refusal.js +6 -1
  261. package/dist/model-plane-face.d.ts +51 -0
  262. package/dist/model-plane-face.js +24 -0
  263. package/dist/model-provider.d.ts +5 -0
  264. package/dist/model-provider.js +4 -2
  265. package/dist/model-route-endpoint.d.ts +8 -11
  266. package/dist/model-route-endpoint.js +4 -7
  267. package/dist/model-route-env.d.ts +22 -0
  268. package/dist/model-route-env.js +2 -0
  269. package/dist/model-route-gap.d.ts +60 -30
  270. package/dist/model-route-gap.js +21 -15
  271. package/dist/observability/corrupt-read-seat.d.ts +7 -0
  272. package/dist/observability/corrupt-read-seat.js +9 -0
  273. package/dist/observability/err-text.d.ts +6 -0
  274. package/dist/observability/err-text.js +18 -4
  275. package/dist/observability/fail-open.d.ts +35 -9
  276. package/dist/observability/fail-open.js +35 -9
  277. package/dist/observability/metrics.js +1 -0
  278. package/dist/observability/prompt-manifest.d.ts +22 -25
  279. package/dist/observability/prompt-manifest.js +54 -50
  280. package/dist/observability/tool-trace.js +9 -10
  281. package/dist/operator-ask.d.ts +10 -0
  282. package/dist/operator-ask.js +3 -0
  283. package/dist/orchestration/workflow-agent-session-index.d.ts +12 -12
  284. package/dist/orchestration/workflow-agent-session-index.js +9 -13
  285. package/dist/orchestration/workflow-completion-inbox.d.ts +42 -15
  286. package/dist/orchestration/workflow-completion-inbox.js +13 -0
  287. package/dist/orchestration/workflow-notify-journal.d.ts +13 -32
  288. package/dist/orchestration/workflow-notify-journal.js +27 -34
  289. package/dist/orchestration/workflow-park-decision.d.ts +89 -0
  290. package/dist/orchestration/workflow-park-decision.js +119 -0
  291. package/dist/org-delivery-gate.d.ts +81 -0
  292. package/dist/org-delivery-gate.js +59 -0
  293. package/dist/panel-tool-names.d.ts +23 -0
  294. package/dist/panel-tool-names.js +8 -0
  295. package/dist/parked-decide.d.ts +43 -11
  296. package/dist/parked-decide.js +100 -51
  297. package/dist/parked-revive-surface.d.ts +9 -2
  298. package/dist/parked-revive-surface.js +11 -8
  299. package/dist/permission-rule-list.d.ts +1 -1
  300. package/dist/permission-rule-list.js +2 -2
  301. package/dist/permission-rule-vocab.d.ts +1 -23
  302. package/dist/permission-rule-vocab.js +0 -13
  303. package/dist/plugins/approval-ask-store-file.d.ts +16 -1
  304. package/dist/plugins/approval-ask-store-file.js +21 -0
  305. package/dist/plugins/approval-ask-store-memory.d.ts +18 -1
  306. package/dist/plugins/approval-ask-store-memory.js +34 -2
  307. package/dist/plugins/approval-ask-store-sql.d.ts +25 -0
  308. package/dist/plugins/approval-ask-store-sql.js +37 -1
  309. package/dist/plugins/approval-payload-fingerprint.d.ts +14 -6
  310. package/dist/plugins/approval-payload-fingerprint.js +1 -1
  311. package/dist/plugins/blob-backend.d.ts +38 -25
  312. package/dist/plugins/blob-backend.js +29 -19
  313. package/dist/plugins/breaker-state-sql.d.ts +2 -2
  314. package/dist/plugins/breaker-state-sql.js +4 -4
  315. package/dist/plugins/caching-session-store.d.ts +4 -1
  316. package/dist/plugins/caching-session-store.js +7 -3
  317. package/dist/plugins/checkpoint-store-sql.d.ts +36 -1
  318. package/dist/plugins/checkpoint-store-sql.js +65 -3
  319. package/dist/plugins/file-history-store-sql.d.ts +5 -2
  320. package/dist/plugins/file-history-store-sql.js +3 -1
  321. package/dist/plugins/file-run-store.d.ts +5 -13
  322. package/dist/plugins/file-run-store.js +9 -0
  323. package/dist/plugins/fork-routing-session-store.d.ts +9 -1
  324. package/dist/plugins/fork-routing-session-store.js +12 -1
  325. package/dist/plugins/host-platform.d.ts +2 -0
  326. package/dist/plugins/host-platform.js +2 -1
  327. package/dist/plugins/local-checkpoint-store.d.ts +15 -2
  328. package/dist/plugins/local-checkpoint-store.js +32 -1
  329. package/dist/plugins/local-session-store.d.ts +13 -10
  330. package/dist/plugins/local-session-store.js +23 -14
  331. package/dist/plugins/local-session-window.d.ts +45 -0
  332. package/dist/plugins/local-session-window.js +38 -0
  333. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +3 -2
  334. package/dist/plugins/mailbox-store-sql.d.ts +30 -48
  335. package/dist/plugins/mailbox-store-sql.js +77 -52
  336. package/dist/plugins/memory-embedder-fingerprint.js +2 -1
  337. package/dist/plugins/memory-run-store.d.ts +5 -13
  338. package/dist/plugins/memory-run-store.js +8 -0
  339. package/dist/plugins/one-time-migrations.d.ts +121 -5
  340. package/dist/plugins/one-time-migrations.js +332 -8
  341. package/dist/plugins/org-delivery-quota-store.d.ts +123 -0
  342. package/dist/plugins/org-delivery-quota-store.js +228 -0
  343. package/dist/plugins/permission-rule-store-file.js +10 -6
  344. package/dist/plugins/permission-rule-store-sql.js +8 -8
  345. package/dist/plugins/pg-pool.js +39 -7
  346. package/dist/plugins/pg-session-storage.d.ts +18 -5
  347. package/dist/plugins/pg-session-storage.js +68 -23
  348. package/dist/plugins/remote-env-adb.d.ts +6 -12
  349. package/dist/plugins/remote-env-adb.js +12 -2
  350. package/dist/plugins/remote-env-device.d.ts +14 -7
  351. package/dist/plugins/remote-env-device.js +23 -15
  352. package/dist/plugins/remote-env-k8s.d.ts +8 -12
  353. package/dist/plugins/remote-env-k8s.js +23 -5
  354. package/dist/plugins/remote-env-local-docker.d.ts +10 -15
  355. package/dist/plugins/remote-env-local-docker.js +12 -9
  356. package/dist/plugins/remote-env-ssh.d.ts +10 -16
  357. package/dist/plugins/remote-env-ssh.js +17 -11
  358. package/dist/plugins/run-store-sql.d.ts +16 -14
  359. package/dist/plugins/run-store-sql.js +22 -2
  360. package/dist/plugins/schema-indexes.js +2 -0
  361. package/dist/plugins/send-user-file.js +2 -2
  362. package/dist/plugins/session-epoch-anchor.d.ts +32 -6
  363. package/dist/plugins/session-epoch-anchor.js +2 -3
  364. package/dist/plugins/session-ownership.d.ts +11 -0
  365. package/dist/plugins/session-ownership.js +11 -0
  366. package/dist/plugins/session-placement.d.ts +12 -14
  367. package/dist/plugins/session-placement.js +2 -15
  368. package/dist/plugins/session-store.d.ts +18 -8
  369. package/dist/plugins/session-store.js +15 -4
  370. package/dist/plugins/sql-driver.d.ts +74 -11
  371. package/dist/plugins/sql-driver.js +210 -12
  372. package/dist/plugins/sql-errors.d.ts +23 -0
  373. package/dist/plugins/sql-errors.js +21 -0
  374. package/dist/plugins/store-backend.d.ts +36 -1
  375. package/dist/plugins/store-backend.js +40 -14
  376. package/dist/plugins/store-contracts.d.ts +42 -0
  377. package/dist/plugins/store-contracts.js +1 -0
  378. package/dist/plugins/tidb-pool.d.ts +6 -1
  379. package/dist/plugins/tidb-pool.js +44 -10
  380. package/dist/plugins/tidb-session-storage.d.ts +3 -2
  381. package/dist/plugins/tidb-session-storage.js +2 -2
  382. package/dist/plugins/tidb-session-store.d.ts +25 -5
  383. package/dist/plugins/tidb-session-store.js +67 -21
  384. package/dist/plugins/workflow-journal-store-sql.d.ts +73 -19
  385. package/dist/plugins/workflow-journal-store-sql.js +19 -6
  386. package/dist/plugins/workflow-run-store-sql.d.ts +30 -8
  387. package/dist/plugins/workflow-run-store-sql.js +50 -9
  388. package/dist/posture-source.d.ts +18 -10
  389. package/dist/posture-source.js +4 -1
  390. package/dist/project-identity.d.ts +45 -6
  391. package/dist/project-identity.js +162 -8
  392. package/dist/project-layer-key.d.ts +28 -0
  393. package/dist/project-layer-key.js +29 -0
  394. package/dist/question.js +3 -2
  395. package/dist/read-deny-entry.d.ts +25 -0
  396. package/dist/read-deny-entry.js +12 -0
  397. package/dist/read-face-posture.d.ts +37 -11
  398. package/dist/read-face-posture.js +32 -3
  399. package/dist/request-key-closure.d.ts +7 -0
  400. package/dist/request-key-closure.js +9 -1
  401. package/dist/request-tool-axes.d.ts +12 -0
  402. package/dist/request-tool-axes.js +20 -0
  403. package/dist/request-value-closure.d.ts +5 -0
  404. package/dist/request-value-closure.js +11 -3
  405. package/dist/rule-entry-list.d.ts +26 -2
  406. package/dist/rule-entry-list.js +72 -12
  407. package/dist/rules-consent.js +3 -4
  408. package/dist/run-acceptance.d.ts +19 -3
  409. package/dist/run-acceptance.js +13 -1
  410. package/dist/run-local.js +37 -6
  411. package/dist/runs.d.ts +12 -10
  412. package/dist/runs.js +25 -6
  413. package/dist/runtime-caps-resolver.d.ts +16 -6
  414. package/dist/runtime-caps-resolver.js +18 -5
  415. package/dist/sandbox-pkg-source.d.ts +19 -1
  416. package/dist/sandbox-pkg-source.js +29 -7
  417. package/dist/sealed-key.d.ts +32 -0
  418. package/dist/sealed-key.js +55 -1
  419. package/dist/security.d.ts +95 -15
  420. package/dist/security.js +52 -9
  421. package/dist/session-error-wire.d.ts +31 -7
  422. package/dist/session-error-wire.js +9 -2
  423. package/dist/session-sync-kernel.d.ts +37 -10
  424. package/dist/session-sync-kernel.js +10 -0
  425. package/dist/session-titled-frame.d.ts +33 -0
  426. package/dist/session-titled-frame.js +4 -0
  427. package/dist/session-titler.d.ts +9 -1
  428. package/dist/session-titler.js +15 -4
  429. package/dist/spec-fields.js +21 -2
  430. package/dist/sql-engine-posture.d.ts +3 -1
  431. package/dist/task-a2a.js +4 -3
  432. package/dist/task-cwd.d.ts +1 -1
  433. package/dist/task-mcp.d.ts +5 -5
  434. package/dist/task-mcp.js +27 -74
  435. package/dist/task-settings.d.ts +93 -88
  436. package/dist/task-settings.js +71 -63
  437. package/dist/text-bidi.d.ts +0 -4
  438. package/dist/text-bidi.js +1 -3
  439. package/dist/tighten-only-seats.d.ts +150 -0
  440. package/dist/tighten-only-seats.js +196 -0
  441. package/dist/tool-approval.d.ts +451 -136
  442. package/dist/tool-approval.js +733 -256
  443. package/dist/tool-rule-names.d.ts +6 -0
  444. package/dist/trace/core-keyset-guard.d.ts +108 -25
  445. package/dist/trace/exit-seat.d.ts +40 -0
  446. package/dist/trace/exit-seat.js +130 -0
  447. package/dist/trace/ledger-events.d.ts +6 -3
  448. package/dist/trace/project.d.ts +98 -13
  449. package/dist/trace/project.js +57 -32
  450. package/dist/trace/projection-table.d.ts +100 -0
  451. package/dist/trace/projection-table.js +130 -0
  452. package/dist/trace/redact.d.ts +57 -0
  453. package/dist/trace/redact.js +962 -168
  454. package/dist/trace/self-minted-wire.d.ts +349 -1
  455. package/dist/trace/self-minted-wire.js +118 -1
  456. package/dist/trace/wire-projection-faces.d.ts +304 -2
  457. package/dist/trace/wire-projection-faces.js +160 -13
  458. package/dist/url-refusal.js +2 -0
  459. package/dist/web-admin-client/apply-effective.d.ts +12 -0
  460. package/dist/web-admin-client/apply-effective.js +56 -5
  461. package/dist/web-admin-client/facade.d.ts +1 -1
  462. package/dist/web-admin-client/facade.js +1 -1
  463. package/dist/web-admin-client/read-face.js +5 -9
  464. package/dist/web-admin-client/skills-mcp.d.ts +1 -1
  465. package/dist/web-admin-client/skills-mcp.js +6 -8
  466. package/dist/web-admin-client/types.d.ts +1 -1
  467. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -9
  468. package/package.json +8 -4
  469. package/scripts/drain-check-local.mjs +34 -2
  470. package/scripts/drain-check.mysql.sql +20 -2
  471. package/scripts/drain-check.pg.sql +20 -2
  472. package/dist/mcp-tool-faces.d.ts +0 -69
  473. package/dist/mcp-tool-faces.js +0 -106
@@ -1,16 +1,15 @@
1
1
  import { isUuidV7, legacyUnownedAmnestyOpen } from "../../security.js";
2
2
  import { sendJson, sendError } from "../send.js";
3
- import { sendUnauthorized } from "../principal-gate.js";
3
+ import { fleetViewOf, sendUnauthorized } from "../principal-gate.js";
4
4
  import { filterFingerprint } from "../cursor-fingerprint.js";
5
5
  import { sessionTempoOfRunStatus } from "../../plugins/store-contracts.js";
6
6
  import { assertNever } from "../route-ctx.js";
7
7
  import * as facts from "../../capability-facts.js";
8
8
  export async function handleSessionsList(req, res, match, ctx) {
9
9
  const { deps } = ctx;
10
- const { isFleetWide, sessionOwnerScope } = ctx.helpers;
11
10
  switch (match.decl.id) {
12
11
  case "sessions-list": {
13
- const { fleetWide, gateOwner } = sessionOwnerScope(req);
12
+ const { fleetWide, gateOwner } = fleetViewOf(req, deps, "read");
14
13
  if (!fleetWide && gateOwner === null) {
15
14
  sendUnauthorized(res, "identity");
16
15
  return;
@@ -26,7 +25,7 @@ export async function handleSessionsList(req, res, match, ctx) {
26
25
  return;
27
26
  }
28
27
  case "sendfile-links": {
29
- const { fleetWide, gateOwner } = sessionOwnerScope(req);
28
+ const { fleetWide, gateOwner } = fleetViewOf(req, deps, "read");
30
29
  if (!fleetWide && gateOwner === null) {
31
30
  sendUnauthorized(res, "identity");
32
31
  return;
@@ -1,6 +1,6 @@
1
1
  import { SessionError, materializeA2aTools, materializeMcpTools, sanitizePathComponent } from "@sema-agent/core";
2
2
  import { a2aForScenario, mcpForScenario } from "../../web-admin-client/facade.js";
3
- import { HttpError, isUuidShape, legacyUnownedSessionOk } from "../../security.js";
3
+ import { HttpError, isUuidShape, legacyUnownedSessionOk, sessionOwnerCellOf } from "../../security.js";
4
4
  import { windowMessages, truncateMessageBlobs, redactSessionViewForRead } from "../../audit.js";
5
5
  import { redactSecrets } from "../../trace/redact.js";
6
6
  import { recordFailOpen } from "../../observability/fail-open.js";
@@ -9,18 +9,19 @@ import { sentMemoryComplianceFailure } from "../memory-compliance-failure-reply.
9
9
  import { MAX_SETTINGS_OUTPUT_STYLE_CHARS, MAX_SETTINGS_ENV_VARS, MAX_SETTINGS_ENV_KEY_CHARS, MAX_SETTINGS_ENV_VALUE_CHARS } from "../../task-settings.js";
10
10
  import { readWritableSessionPermissionRules } from "../../session-policy-wire.js";
11
11
  import { sendJson, sendError, sendSessionError, sendSessionPolicyError, sseHeaders, httpErrorBody } from "../send.js";
12
- import { gatedPrincipal, explicitOperatorOk, sessionOwnerReadable, sendPrincipalRefusal, sendUnauthorized } from "../principal-gate.js";
12
+ import { fleetViewOf, gatedPrincipal, explicitOperatorOk, sessionCallerOf, sessionOwnerReadable, sendPrincipalRefusal, sendUnauthorized } from "../principal-gate.js";
13
+ import { runRowReadableOnSessionFace } from "../owner-access.js";
13
14
  import { assertNever, SESSION_NOT_FOUND_MESSAGE } from "../route-ctx.js";
14
15
  import * as facts from "../../capability-facts.js";
15
16
  import { rosterAgentId } from "./agents-roster.js";
16
17
  import { projectSessionListRow } from "./sessions-list.js";
17
18
  import { readSessionRowPatch } from "../../session-row.js";
19
+ import { buildBoundedToolNames } from "../../panel-tool-names.js";
18
20
  const MCP_STATUS_TTL_MS = 5_000;
19
21
  const A2A_STATUS_TTL_MS = 5_000;
20
22
  const A2A_MATERIALIZE_TIMEOUT_MS = 10_000;
21
23
  const MEMORY_STATUS_TTL_MS = 5_000;
22
24
  const LAST_LEG_LEDGER_TIMEOUT_MS = 2_000;
23
- const A2A_PANEL_MAX_TOOL_NAMES = 200;
24
25
  export function createSessionsLocal() {
25
26
  return {
26
27
  sseConnections: 0,
@@ -30,11 +31,11 @@ export function createSessionsLocal() {
30
31
  memoryStatusCache: new Map(),
31
32
  };
32
33
  }
33
- async function lastLegMcpFor(deps, sessionId, principal) {
34
+ async function lastLegMcpFor(deps, sessionId, caller) {
34
35
  let timer;
35
36
  try {
36
37
  return await Promise.race([
37
- readLastLegMcp(deps, sessionId, principal),
38
+ readLastLegMcp(deps, sessionId, caller),
38
39
  new Promise((r) => { timer = setTimeout(() => { recordFailOpen("server.mcp-panel.last-leg-unreadable", `ledger read exceeded ${LAST_LEG_LEDGER_TIMEOUT_MS}ms`); r(undefined); }, LAST_LEG_LEDGER_TIMEOUT_MS); }),
39
40
  ]);
40
41
  }
@@ -47,14 +48,14 @@ async function lastLegMcpFor(deps, sessionId, principal) {
47
48
  clearTimeout(timer);
48
49
  }
49
50
  }
50
- async function readLastLegMcp(deps, sessionId, principal) {
51
+ async function readLastLegMcp(deps, sessionId, caller) {
51
52
  const runStore = deps.runStore;
52
53
  if (!runStore || sessionId === null)
53
54
  return undefined;
54
55
  const latest = await runStore.latestRunForSession(sessionId);
55
56
  if (latest === undefined)
56
57
  return undefined;
57
- if (!sessionOwnerReadable(principal, latest.owner, deps) && !explicitOperatorOk(principal, deps.config.operatorPrincipals))
58
+ if (!runRowReadableOnSessionFace(deps, caller, latest.owner, "owner_or_operator"))
58
59
  return undefined;
59
60
  const events = await runStore.getEvents(latest.taskId, 0);
60
61
  for (let i = events.length - 1; i >= 0; i--) {
@@ -70,7 +71,7 @@ async function readLastLegMcp(deps, sessionId, principal) {
70
71
  }
71
72
  export async function handleSessions(req, res, match, ctx) {
72
73
  const { deps } = ctx;
73
- const { readJson, safeDecode, sessionOwnerOk, sessionOwnerScopeForWrite } = ctx.helpers;
74
+ const { readJson, safeDecode, sessionOwnerOk } = ctx.helpers;
74
75
  const readOwnedSessionView = async (sessionAudit, sessionId, readOpts) => {
75
76
  const ownerOf = deps.sessionStorage?.ownerOf?.bind(deps.sessionStorage);
76
77
  if (ownerOf !== undefined) {
@@ -79,7 +80,7 @@ export async function handleSessions(req, res, match, ctx) {
79
80
  sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
80
81
  return undefined;
81
82
  }
82
- if (!sessionOwnerOk(req, res, owner))
83
+ if (!sessionOwnerOk(req, res, await sessionOwnerCellOf(deps.sessionStorage, sessionId, owner)))
83
84
  return undefined;
84
85
  }
85
86
  let audit;
@@ -95,7 +96,7 @@ export async function handleSessions(req, res, match, ctx) {
95
96
  sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
96
97
  return undefined;
97
98
  }
98
- if (!sessionOwnerOk(req, res, audit.owner))
99
+ if (!sessionOwnerOk(req, res, await sessionOwnerCellOf(deps.sessionStorage, sessionId, audit.owner)))
99
100
  return undefined;
100
101
  return audit;
101
102
  };
@@ -138,12 +139,13 @@ export async function handleSessions(req, res, match, ctx) {
138
139
  }
139
140
  {
140
141
  if (match.decl.id === "session-mcp") {
141
- const principal = gatedPrincipal(req, deps.config);
142
+ const caller = sessionCallerOf(req, deps);
143
+ const principal = caller.principal;
142
144
  if (deps.config.requirePrincipal && !principal) {
143
145
  sendPrincipalRefusal(res, req, deps.config);
144
146
  return;
145
147
  }
146
- const lastLegMcp = await lastLegMcpFor(deps, safeDecode(match.params.sessionId), principal);
148
+ const lastLegMcp = await lastLegMcpFor(deps, safeDecode(match.params.sessionId), caller);
147
149
  const ledgerHalf = lastLegMcp === undefined ? {} : { lastLegMcp };
148
150
  let scenarioName;
149
151
  try {
@@ -233,13 +235,7 @@ export async function handleSessions(req, res, match, ctx) {
233
235
  ...(s.agentName ? { agentName: s.agentName } : {}),
234
236
  ...(s.agentDescription ? { agentDescription: s.agentDescription } : {}),
235
237
  ...(s.endpoint ? { endpoint: redactSecrets(String(s.endpoint)).slice(0, 2048) } : {}),
236
- ...(s.toolNames
237
- ? {
238
- toolCount: s.toolNames.length,
239
- toolNames: s.toolNames.slice(0, A2A_PANEL_MAX_TOOL_NAMES),
240
- ...(s.toolNames.length > A2A_PANEL_MAX_TOOL_NAMES ? { toolNamesTruncated: true } : {}),
241
- }
242
- : {}),
238
+ ...(s.toolNames ? { toolCount: s.toolNames.length, ...buildBoundedToolNames(s.toolNames) } : {}),
243
239
  ...(s.error ? { error: redactSecrets(String(s.error)).slice(0, 200) } : {}),
244
240
  })),
245
241
  };
@@ -277,7 +273,7 @@ export async function handleSessions(req, res, match, ctx) {
277
273
  return;
278
274
  }
279
275
  owner = head.owner;
280
- if (!sessionOwnerOk(req, res, owner ?? null))
276
+ if (!sessionOwnerOk(req, res, await sessionOwnerCellOf(deps.sessionStorage, headSession, owner ?? null)))
281
277
  return;
282
278
  leafId = head.leafId;
283
279
  }
@@ -287,7 +283,7 @@ export async function handleSessions(req, res, match, ctx) {
287
283
  sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
288
284
  return;
289
285
  }
290
- if (!sessionOwnerOk(req, res, owner ?? null))
286
+ if (!sessionOwnerOk(req, res, await sessionOwnerCellOf(deps.sessionStorage, headSession, owner ?? null)))
291
287
  return;
292
288
  leafId = await getLeafId(headSession);
293
289
  }
@@ -344,13 +340,13 @@ export async function handleSessions(req, res, match, ctx) {
344
340
  return;
345
341
  }
346
342
  sse.sseOwnerLookups++;
347
- const ownerP = ownerOf(evSession);
348
- void ownerP.catch(() => undefined).then(() => { sse.sseOwnerLookups--; });
343
+ const cellP = ownerOf(evSession).then((o) => (o === undefined ? undefined : sessionOwnerCellOf(evFact.sessionStorage, evSession, o)));
344
+ void cellP.catch(() => undefined).then(() => { sse.sseOwnerLookups--; });
349
345
  let stallTimer;
350
- let owner;
346
+ let cell;
351
347
  try {
352
- owner = await Promise.race([
353
- ownerP,
348
+ cell = await Promise.race([
349
+ cellP,
354
350
  new Promise((r) => { stallTimer = setTimeout(() => r("__stall__"), stallBound); stallTimer.unref?.(); }),
355
351
  ]);
356
352
  }
@@ -360,21 +356,22 @@ export async function handleSessions(req, res, match, ctx) {
360
356
  }
361
357
  if (closed)
362
358
  return;
363
- if (owner === "__stall__") {
359
+ if (cell === "__stall__") {
364
360
  cleanup();
365
361
  res.setHeader("retry-after", "5");
366
362
  sendError(res, 503, "state.sse_owner_lookup_stalled", "session-events owner lookup stalled — retry");
367
363
  return;
368
364
  }
369
- if (owner === undefined) {
365
+ if (cell === undefined) {
370
366
  cleanup();
371
367
  sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
372
368
  return;
373
369
  }
374
- if (!sessionOwnerOk(req, res, owner ?? null)) {
370
+ if (!sessionOwnerOk(req, res, cell)) {
375
371
  cleanup();
376
372
  return;
377
373
  }
374
+ const owner = cell.owner;
378
375
  const q = new URLSearchParams(match.search);
379
376
  const lastLeafId = q.get("lastLeafId");
380
377
  let first = true;
@@ -678,7 +675,7 @@ export async function handleSessions(req, res, match, ctx) {
678
675
  sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
679
676
  return;
680
677
  }
681
- if (!sessionOwnerOk(req, res, face.owner))
678
+ if (!sessionOwnerOk(req, res, await sessionOwnerCellOf(store, sessionId, face.owner)))
682
679
  return;
683
680
  const read = readSessionRowPatch(await readJson(req));
684
681
  if ("problem" in read) {
@@ -702,7 +699,7 @@ export async function handleSessions(req, res, match, ctx) {
702
699
  }
703
700
  const fork = forkFact.sessionStorage.fork.bind(forkFact.sessionStorage);
704
701
  const ownerOf = forkFact.sessionStorage.ownerOf.bind(forkFact.sessionStorage);
705
- const scope = sessionOwnerScopeForWrite(req);
702
+ const scope = fleetViewOf(req, deps, "write");
706
703
  if (!scope.fleetWide && scope.gateOwner === null) {
707
704
  sendUnauthorized(res, "identity");
708
705
  return;
@@ -717,7 +714,7 @@ export async function handleSessions(req, res, match, ctx) {
717
714
  sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
718
715
  return;
719
716
  }
720
- if (!scope.fleetWide && owner !== scope.gateOwner && !legacyUnownedSessionOk(deps.config.requirePrincipal, scope.gateOwner, owner)) {
717
+ if (!scope.fleetWide && owner !== scope.gateOwner && !legacyUnownedSessionOk(deps.config.requirePrincipal, sessionCallerOf(req, deps), await sessionOwnerCellOf(forkFact.sessionStorage, sourceId, owner))) {
721
718
  sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
722
719
  return;
723
720
  }
@@ -740,7 +737,7 @@ export async function handleSessions(req, res, match, ctx) {
740
737
  }
741
738
  const purge = deleteFact.purge;
742
739
  const ownerOf = deleteFact.sessionStorage.ownerOf.bind(deleteFact.sessionStorage);
743
- const scope = sessionOwnerScopeForWrite(req);
740
+ const scope = fleetViewOf(req, deps, "write");
744
741
  if (!scope.fleetWide && scope.gateOwner === null) {
745
742
  sendUnauthorized(res, "identity");
746
743
  return;
@@ -755,7 +752,7 @@ export async function handleSessions(req, res, match, ctx) {
755
752
  sendJson(res, 200, { deleted: false });
756
753
  return;
757
754
  }
758
- if (!scope.fleetWide && owner !== scope.gateOwner && !legacyUnownedSessionOk(deps.config.requirePrincipal, scope.gateOwner, owner)) {
755
+ if (!scope.fleetWide && owner !== scope.gateOwner && !legacyUnownedSessionOk(deps.config.requirePrincipal, sessionCallerOf(req, deps), await sessionOwnerCellOf(deleteFact.sessionStorage, sessionId, owner))) {
759
756
  sendJson(res, 200, { deleted: false });
760
757
  return;
761
758
  }
@@ -805,7 +802,7 @@ export async function handleSessions(req, res, match, ctx) {
805
802
  sendError(res, 409, "conflict.session_ownerless", "this session has no recorded owner, so its rules can be neither read nor changed through this route; rules already stored for it keep applying to the runs of the principal they were stored under. Ways out: on the local backend, during the upgrade window, the first task submitted with a principal on a session written by an earlier version claims it for that principal (this route then serves its owner); or delete the session (DELETE /v1/sessions/:id), which removes its rules with it");
806
803
  return;
807
804
  }
808
- const operator = explicitOperatorOk(principal, deps.config.operatorPrincipals);
805
+ const operator = explicitOperatorOk(principal, deps.config);
809
806
  if (!operator && owner !== (principal ?? null)) {
810
807
  sendError(res, 404, "not_found.session", SESSION_NOT_FOUND_MESSAGE);
811
808
  return;
@@ -822,14 +819,7 @@ export async function handleSessions(req, res, match, ctx) {
822
819
  }
823
820
  return;
824
821
  }
825
- let body;
826
- try {
827
- body = (await readJson(req));
828
- }
829
- catch {
830
- sendError(res, 400, "request.invalid_json", "invalid JSON body");
831
- return;
832
- }
822
+ const body = (await readJson(req));
833
823
  const read = readWritableSessionPermissionRules(body.rules);
834
824
  if (read.refusal !== undefined) {
835
825
  sendSessionPolicyError(res, read.refusal);
@@ -1,7 +1,8 @@
1
1
  import { MODEL_ROLES, expandTiers, isThinkingLevel } from "@sema-agent/core";
2
2
  import { HttpError } from "../../security.js";
3
+ import { echoCallerText } from "../../caller-text-echo.js";
3
4
  import { isAtMentionable, matchCatalogModel, refusedCatalogEntry, selectableCatalog } from "../../model-select.js";
4
- import { modelUnavailableMessage } from "../../model-entry-refusal.js";
5
+ import { echoModelRef, modelUnavailableMessage } from "../../model-entry-refusal.js";
5
6
  import { redactSecrets } from "../../trace/redact.js";
6
7
  import { admitProviderEcho, redactErrorMessage } from "../../observability/run-terminal.js";
7
8
  import { sendJson, sendError, sendHttpError, msg } from "../send.js";
@@ -12,6 +13,7 @@ export function isCorePreflightValidationError(message) {
12
13
  return CORE_PREFLIGHT_VALIDATION_PREFIXES.some((prefix) => message.startsWith(prefix));
13
14
  }
14
15
  export const CORE_PREFLIGHT_VALIDATION_ANCHORS = CORE_PREFLIGHT_VALIDATION_PREFIXES;
16
+ const MODEL_ROLE_ECHO_CHARS = 80;
15
17
  function isModelRole(value) {
16
18
  return typeof value === "string" && MODEL_ROLES.includes(value);
17
19
  }
@@ -62,7 +64,7 @@ export async function handleSideQuery(req, res, match, ctx) {
62
64
  return;
63
65
  }
64
66
  if (body.modelRole !== undefined && !isModelRole(body.modelRole)) {
65
- const shown = (typeof body.modelRole === "string" ? JSON.stringify(body.modelRole.slice(0, 80)) : `of type ${body.modelRole === null ? "null" : Array.isArray(body.modelRole) ? "array" : typeof body.modelRole}`);
67
+ const shown = (typeof body.modelRole === "string" ? JSON.stringify(echoCallerText(body.modelRole, { maxChars: MODEL_ROLE_ECHO_CHARS })) : `of type ${body.modelRole === null ? "null" : Array.isArray(body.modelRole) ? "array" : typeof body.modelRole}`);
66
68
  sendError(res, 400, "request.field_invalid", `invalid modelRole ${shown} — must be a string, one of ${MODEL_ROLES.join(" / ")} (the engine's role vocabulary); a value outside it is refused before any model call`);
67
69
  return;
68
70
  }
@@ -70,12 +72,12 @@ export async function handleSideQuery(req, res, match, ctx) {
70
72
  const catalog = selectableCatalog(deps.config.models ?? {}, deps.config.tiers, deps.config.modelRefusals);
71
73
  const unavailable = matchCatalogModel(body.model, catalog, deps.config.modelRefusals) === undefined ? refusedCatalogEntry(body.model, deps.config.modelRefusals) : undefined;
72
74
  if (unavailable !== undefined) {
73
- const message = modelUnavailableMessage("model", body.model.slice(0, 120), unavailable.name, unavailable.refusal);
75
+ const message = modelUnavailableMessage("model", body.model, unavailable.name, unavailable.refusal);
74
76
  sendError(res, 400, "request.model_unavailable", message);
75
77
  return;
76
78
  }
77
79
  if (!isAtMentionable(body.model, catalog, deps.config.atMention, deps.config.modelRefusals)) {
78
- sendError(res, 400, "request.model_not_allowed", `model is not @-mentionable on this deployment: "${body.model.slice(0, 120)}" — which models can be @-mentioned is configured by the operator (models.atMention)`);
80
+ sendError(res, 400, "request.model_not_allowed", `model is not @-mentionable on this deployment: "${echoModelRef(body.model)}" — which models can be @-mentioned is configured by the operator (models.atMention)`);
79
81
  return;
80
82
  }
81
83
  }
@@ -18,10 +18,10 @@ import { contextUsageEventData, turnEndEventData, toolStartEventData, toolEndEve
18
18
  import { cascadeConfig, runMeta } from "../run-meta.js";
19
19
  import { idemCallerOf, inflightKeyOf, submissionIdemOf } from "../idempotency.js";
20
20
  import { replayOfExistingRun } from "../submit-replay.js";
21
- import { sendJson, sendError, sseHeaders } from "../send.js";
21
+ import { httpErrorCode, sendJson, sendError, sseHeaders } from "../send.js";
22
22
  import { collectSsePreamble } from "../sse-log.js";
23
23
  import { buildApprovalPreamble, buildApprovalPreambleSseFrames } from "../../approval-card.js";
24
- import { createApprovalCardEmitter, resolveApprovalLeg, resolveStreamApprovalGate } from "../../tool-approval.js";
24
+ import { approvalPreambleReplays, createApprovalCardEmitter, declaredApprovalFrameFamilies, resolveApprovalLeg, resolveStreamApprovalGate } from "../../tool-approval.js";
25
25
  import { buildActiveRunConflict, isActiveRunConflictBody, toDoneFrameResult } from "../active-run-conflict.js";
26
26
  import { commitPlacement, devicePlacementErrorBody } from "../device-placement.js";
27
27
  import { commitSessionInheritEnv } from "../session-inherit-env.js";
@@ -34,6 +34,9 @@ import { persistSubmitCtx } from "../submit-ctx.js";
34
34
  import { serviceVersion } from "../../service-version.js";
35
35
  import { withModelReachScope } from "../../model-reach-scope.js";
36
36
  import { createInstructionSelectionLeg } from "../../instruction-selection.js";
37
+ import { fieldConflictFacts } from "../../field-conflict.js";
38
+ import { refusalBody } from "../refusal-body.js";
39
+ import { heldWorkflowParkDecisions } from "../../parked-decide.js";
37
40
  const DISCONNECT_PARK_GRACE_MS = 10_000;
38
41
  function sseData(res, payload) {
39
42
  const anchor = payload.eventId;
@@ -60,8 +63,8 @@ function sendSubmitResult(res, resp) {
60
63
  : raw;
61
64
  sendJson(res, 200, body);
62
65
  }
63
- function writeMetaFrame(res, taskId, sessionId) {
64
- res.write(`event: meta\ndata: ${JSON.stringify({ type: "meta", taskId, ...(sessionId ? { sessionId } : {}) })}\n\n`);
66
+ function writeMetaFrame(res, taskId, sessionId, warnings) {
67
+ res.write(`event: meta\ndata: ${JSON.stringify({ type: "meta", taskId, ...(sessionId ? { sessionId } : {}), ...(warnings !== undefined ? { warnings } : {}) })}\n\n`);
65
68
  }
66
69
  function refusalDoneResult(body) {
67
70
  if (isActiveRunConflictBody(body))
@@ -147,14 +150,26 @@ export async function handleTasks(req, res, match, ctx) {
147
150
  const prepared = await prepareSpec(req, res, keyedBody, undefined, { liveStream });
148
151
  if (!prepared)
149
152
  return;
153
+ const declaredFamilies = declaredApprovalFrameFamilies(prepared.body.settings);
154
+ const approvalLegInput = (streamApprovalOn) => {
155
+ const legWalltimeMs = typeof prepared.spec.limits?.maxWalltimeMs === "number" ? prepared.spec.limits.maxWalltimeMs : undefined;
156
+ return {
157
+ streamApprovalOn,
158
+ windowMs: deps.config.streamApproval?.windowMs,
159
+ windowMarginMs: deps.config.streamAskWindowMarginMs,
160
+ ...(legWalltimeMs !== undefined ? { legWalltimeMs } : {}),
161
+ declaredFamilies,
162
+ };
163
+ };
164
+ const assembleApprovalLeg = (streamApprovalOn) => resolveApprovalLeg({ ...approvalLegInput(streamApprovalOn), nowMonotonicMs: performance.now() });
150
165
  const principal = prepared.auth?.principal;
151
- const wiringOperatorFace = explicitOperatorOk(gatedPrincipal(req, deps.config), deps.config.operatorPrincipals);
166
+ const wiringOperatorFace = explicitOperatorOk(gatedPrincipal(req, deps.config), deps.config);
152
167
  let wiringReceipt;
153
168
  const instructionLeg = createInstructionSelectionLeg();
154
169
  const withRunReceipt = (out) => wiringReceipt !== undefined ? { ...out, wiringManifest: wiringReceipt } : out;
155
170
  if (liveStream) {
156
171
  if (prepared.verify || prepared.cascade) {
157
- sendError(res, 400, "request.field_conflict", "verify / cascade are not supported on /v1/tasks/stream (both are multi-attempt, not a single stream) — use /v1/tasks or /v1/runs");
172
+ sendError(res, 400, "request.field_conflict", "verify / cascade are not supported on /v1/tasks/stream (both are multi-attempt, not a single stream) — use /v1/tasks or /v1/runs", fieldConflictFacts("cascade_verify", prepared.verify ? (prepared.cascade ? ["verify", "cascade"] : ["verify"]) : ["cascade"]));
158
173
  return;
159
174
  }
160
175
  const earlyDurableTid = facts.durableRuns(deps).available && prepared.spec.sessionId ? uuidv7() : undefined;
@@ -169,7 +184,7 @@ export async function handleTasks(req, res, match, ctx) {
169
184
  reqState.streamDetached = detachOnDisconnect;
170
185
  sseHeaders(res, earlyDurableTid ? { "x-task-id": earlyDurableTid } : undefined);
171
186
  if (earlyDurableTid)
172
- writeMetaFrame(res, earlyDurableTid, prepared.spec.sessionId);
187
+ writeMetaFrame(res, earlyDurableTid, prepared.spec.sessionId, prepared.warnings);
173
188
  const ac = createRunAbort();
174
189
  let closed = false;
175
190
  let detachLogged = false;
@@ -212,17 +227,29 @@ export async function handleTasks(req, res, match, ctx) {
212
227
  toolApprovalEnabled: Boolean(deps.toolApproval),
213
228
  streamApprovalEnabled: deps.config.streamApproval?.enabled === true,
214
229
  backend: deps.backend,
215
- parkFacility: deps.checkpointStore !== undefined,
230
+ checkpointStore: deps.checkpointStore,
216
231
  });
217
- const replaySessionId = replayGate.active ? prepared.spec.sessionId : undefined;
232
+ const replaySessionId = approvalPreambleReplays(approvalLegInput(replayGate.active)) ? prepared.spec.sessionId : undefined;
233
+ const presentedOnConnection = new Set();
234
+ const presentedCompleted = new Set();
235
+ const admitPresentedComplete = (askId) => {
236
+ if (!presentedOnConnection.has(askId))
237
+ return true;
238
+ if (presentedCompleted.has(askId))
239
+ return false;
240
+ presentedCompleted.add(askId);
241
+ return true;
242
+ };
218
243
  if (replaySessionId) {
219
244
  const replayOwner = gatedPrincipal(req, deps.config) ?? null;
220
245
  const askStore = replayGate.active ? replayGate.askStore : undefined;
246
+ let presentedAskIds = [];
221
247
  const preambleFrames = await collectSsePreamble(async (signal) => {
222
248
  if (!askStore)
223
249
  return [];
224
250
  const rows = await askStore.listPendingBySession(replaySessionId, replayOwner, signal);
225
251
  const { frames, skipped, dropped } = buildApprovalPreamble(rows, Date.now(), deps.config.streamApproval.replayMax);
252
+ presentedAskIds = frames.map((f) => f.askId);
226
253
  if (skipped > 0)
227
254
  deps.logger?.warn?.("approval_preamble_row_skipped", { sessionId: replaySessionId, skipped, face: "tasks.stream" });
228
255
  if (dropped > 0)
@@ -232,6 +259,16 @@ export async function handleTasks(req, res, match, ctx) {
232
259
  if (!res.writableEnded && !res.destroyed) {
233
260
  for (const f of preambleFrames)
234
261
  res.write(`event: ${f.event}\ndata: ${JSON.stringify(f.data)}\n\n`);
262
+ if (deps.toolApproval && preambleFrames.length > 0) {
263
+ for (const askId of presentedAskIds)
264
+ presentedOnConnection.add(askId);
265
+ const unwatch = deps.toolApproval.watchPresentedCards(presentedAskIds, (frame) => {
266
+ if (res.writableEnded || res.destroyed || !admitPresentedComplete(frame.askId))
267
+ return;
268
+ res.write(`event: ${frame.type}\ndata: ${JSON.stringify(frame)}\n\n`);
269
+ });
270
+ res.once("close", unwatch);
271
+ }
235
272
  }
236
273
  }
237
274
  const hb = setInterval(() => {
@@ -378,7 +415,9 @@ export async function handleTasks(req, res, match, ctx) {
378
415
  const tailContentMode = prepared.spec.forwardSubagentEvents === true ? "on" : "progress_only";
379
416
  const childReasoning = createReasoningSegments();
380
417
  const topReasoning = createReasoningSegments();
418
+ const heldDecisions = prepared.spec.sessionId !== undefined ? await heldWorkflowParkDecisions(deps, prepared.spec.sessionId) : {};
381
419
  const fwdInternals = {
420
+ ...heldDecisions,
382
421
  onForwardEvent: (e) => {
383
422
  fleetPub?.onForwardEvent(e);
384
423
  ledgerSink?.onForwardEvent(e);
@@ -457,6 +496,7 @@ export async function handleTasks(req, res, match, ctx) {
457
496
  liveStreamRef = liveStream;
458
497
  if (durableTaskId)
459
498
  steerableRuns.set(durableTaskId, liveStream);
499
+ prepared.acceptance.attachStream({ reachable: () => !closed && !res.writableEnded && !res.destroyed, write: (frame) => sseData(res, { ...frame }) });
460
500
  for await (const ev of liveStream) {
461
501
  if (closed)
462
502
  break;
@@ -635,18 +675,11 @@ export async function handleTasks(req, res, match, ctx) {
635
675
  toolApprovalEnabled: Boolean(deps.toolApproval),
636
676
  streamApprovalEnabled: deps.config.streamApproval?.enabled === true,
637
677
  backend: deps.backend,
638
- parkFacility: deps.checkpointStore !== undefined,
678
+ checkpointStore: deps.checkpointStore,
639
679
  }).active;
640
- const legWalltimeMs = typeof prepared.spec.limits?.maxWalltimeMs === "number" ? prepared.spec.limits.maxWalltimeMs : undefined;
641
- const approvalLeg = resolveApprovalLeg({
642
- streamApprovalOn,
643
- windowMs: deps.config.streamApproval?.windowMs,
644
- windowMarginMs: deps.config.streamAskWindowMarginMs,
645
- ...(legWalltimeMs !== undefined ? { legWalltimeMs } : {}),
646
- nowMonotonicMs: performance.now(),
647
- });
680
+ const approvalLeg = assembleApprovalLeg(streamApprovalOn);
648
681
  const legDeadlineMonotonic = approvalLeg.legDeadlineMonotonic;
649
- const windowZero = approvalLeg.windowZero;
682
+ const unattended = approvalLeg.unattended;
650
683
  const emitCard = createApprovalCardEmitter({
651
684
  ...(ledgerSink
652
685
  ? {
@@ -659,6 +692,8 @@ export async function handleTasks(req, res, match, ctx) {
659
692
  writeLive: (frame) => {
660
693
  if (res.writableEnded || res.destroyed)
661
694
  throw new Error("live stream ended");
695
+ if (frame.type === "approval_complete" && !admitPresentedComplete(frame.askId))
696
+ return;
662
697
  emitAsk(frame);
663
698
  },
664
699
  });
@@ -666,11 +701,10 @@ export async function handleTasks(req, res, match, ctx) {
666
701
  if (!res.writableEnded && !res.destroyed)
667
702
  emitAsk(frame);
668
703
  };
669
- const approvalCtx = deps.toolApproval && !windowZero
704
+ const approvalCtx = deps.toolApproval && unattended === undefined
670
705
  ? {
671
706
  taskId: askTaskId,
672
707
  owner: askOwner,
673
- emit: emitApproval,
674
708
  abortSignal: ac.signal,
675
709
  ...(prepared.spec.sessionId ? { sessionId: prepared.spec.sessionId } : {}),
676
710
  ...(streamApprovalOn
@@ -680,13 +714,13 @@ export async function handleTasks(req, res, match, ctx) {
680
714
  legKey: "",
681
715
  ...(legDeadlineMonotonic !== undefined ? { legDeadlineMonotonic } : {}),
682
716
  }
683
- : {}),
717
+ : { emit: emitApproval }),
684
718
  }
685
719
  : undefined;
686
720
  if (deps.toolApproval) {
687
721
  const toolApproval = deps.toolApproval;
688
- prepared.spec.onAsk = windowZero
689
- ? toolApproval.boundUnattendedAsk({ owner: askOwner, taskId: askTaskId, ...(prepared.spec.sessionId ? { sessionId: prepared.spec.sessionId } : {}) })
722
+ prepared.spec.onAsk = unattended
723
+ ? toolApproval.boundUnattendedAsk({ owner: askOwner, taskId: askTaskId, ...(prepared.spec.sessionId ? { sessionId: prepared.spec.sessionId } : {}) }, unattended)
690
724
  : toolApproval.boundAsk({
691
725
  owner: askOwner,
692
726
  taskId: askTaskId,
@@ -843,7 +877,13 @@ export async function handleTasks(req, res, match, ctx) {
843
877
  res.end();
844
878
  }
845
879
  else {
846
- const withSyncSubmitKeys = (body) => prepared.verify || prepared.cascade ? { ...body, notice: MULTI_ATTEMPT_NO_EVENT_CHANNEL_NOTICE } : body;
880
+ const withSyncSubmitKeys = (body) => {
881
+ const extra = {
882
+ ...(prepared.verify || prepared.cascade ? { notice: MULTI_ATTEMPT_NO_EVENT_CHANNEL_NOTICE } : {}),
883
+ ...(prepared.warnings !== undefined ? { warnings: prepared.warnings } : {}),
884
+ };
885
+ return Object.keys(extra).length > 0 ? { ...body, ...extra } : body;
886
+ };
847
887
  const runSyncSubmitLeg = async () => {
848
888
  const syncLegStartedAt = Date.now();
849
889
  let durableTaskId;
@@ -902,10 +942,11 @@ export async function handleTasks(req, res, match, ctx) {
902
942
  let result;
903
943
  counters.uncountedBillableInflight++;
904
944
  try {
905
- const verifyLeg = (v) => runWithVerification(prepared.runner, specWithSignal, v);
906
- const cascadeLeg = () => runCascade(prepared.runner, specWithSignal, cascadeConfig(deps.config.cascadeLadder, prepared.spec.limits?.maxCostUsd));
945
+ const heldDecisions = prepared.spec.sessionId !== undefined ? await heldWorkflowParkDecisions(deps, prepared.spec.sessionId) : {};
946
+ const verifyLeg = (v) => runWithVerification(prepared.runner, specWithSignal, v, heldDecisions);
947
+ const cascadeLeg = () => runCascade(prepared.runner, specWithSignal, cascadeConfig(deps.config.cascadeLadder, prepared.spec.limits?.maxCostUsd), heldDecisions);
907
948
  const plainLeg = async () => {
908
- const stream = prepared.runner.runTaskStream(specWithSignal);
949
+ const stream = prepared.runner.runTaskStream(specWithSignal, undefined, heldDecisions);
909
950
  for await (const ev of stream) {
910
951
  observeSyncLegEvent(ev);
911
952
  prepared.acceptance.observe(ev);
@@ -942,8 +983,8 @@ export async function handleTasks(req, res, match, ctx) {
942
983
  const retryAfterSec = resumeAtPlane.errorCode === "memory.admission_required" && result.retryAfterMs !== undefined
943
984
  ? Math.max(1, Math.ceil(result.retryAfterMs / 1000))
944
985
  : undefined;
945
- const refusalFacts = zeroWorkRefusalFacts(redactTerminalResult(sealResultForExit(result)).terminal);
946
- return { status: resumeAtStatus, body: { errorCode: resumeAtPlane.errorCode, error: redactErrorMessage(resumeAtPlane.errorMessage) ?? "resume-at failed", ...(retryAfterSec !== undefined ? { retryAfterSec } : {}), ...refusalFacts } };
986
+ const refusalFacts = zeroWorkRefusalFacts(redactTerminalResult(sealResultForExit(result)).terminal, prepared.warnings);
987
+ return { status: resumeAtStatus, body: refusalBody({ errorCode: httpErrorCode(resumeAtStatus, resumeAtPlane.errorCode), message: redactErrorMessage(resumeAtPlane.errorMessage) ?? "resume-at failed", facts: { ...(retryAfterSec !== undefined ? { retryAfterSec } : {}), ...refusalFacts } }) };
947
988
  }
948
989
  const exitResult = await mintSubmitExitResult(result, deps.checkpointStore);
949
990
  const syncPlane = outwardPlane(result.terminal);
@@ -6,16 +6,16 @@ import { sleep } from "../sse-log.js";
6
6
  import { bindSseLifecycle } from "../sse-lifecycle.js";
7
7
  import { sendJson, sendError, sseHeaders, SSE_MAX_STREAM_MS, SSE_HEARTBEAT_IDLE_MS } from "../send.js";
8
8
  import { filterFingerprint } from "../cursor-fingerprint.js";
9
- import { gatedPrincipal, sendUnauthorized } from "../principal-gate.js";
9
+ import { fleetViewOf, sendUnauthorized } from "../principal-gate.js";
10
10
  import { assertNever } from "../route-ctx.js";
11
11
  import * as facts from "../../capability-facts.js";
12
12
  const TOOL_RESULT_LIMIT_CAP = 262_144;
13
13
  const TOOL_RESULT_OFFSET_CAP = 2_147_483_646;
14
14
  export async function handleTraceUsage(req, res, match, ctx) {
15
15
  const { deps } = ctx;
16
- const { isFleetWide, safeDecode } = ctx.helpers;
16
+ const { safeDecode } = ctx.helpers;
17
17
  if (match.decl.id === "tasks-source-summary") {
18
- if (!isFleetWide(req)) {
18
+ if (!fleetViewOf(req, deps, "read").fleetWide) {
19
19
  sendUnauthorized(res, "operator");
20
20
  return;
21
21
  }
@@ -35,8 +35,7 @@ export async function handleTraceUsage(req, res, match, ctx) {
35
35
  match.decl.id === "task-trace-stream" ||
36
36
  match.decl.id === "task-trace-artifacts" ||
37
37
  match.decl.id === "task-tool-result") {
38
- const fleetWide = isFleetWide(req);
39
- const gateOwner = fleetWide ? null : (gatedPrincipal(req, deps.config) || null);
38
+ const { fleetWide, gateOwner } = fleetViewOf(req, deps, "read");
40
39
  if (!fleetWide && gateOwner === null) {
41
40
  sendUnauthorized(res, "identity");
42
41
  return;
@@ -89,9 +88,8 @@ export async function handleTraceUsage(req, res, match, ctx) {
89
88
  return;
90
89
  }
91
90
  const runStore = runs.runStore;
92
- const fleetWide = isFleetWide(req);
93
- const jwtOwner = fleetWide ? undefined : gatedPrincipal(req, deps.config);
94
- if (!fleetWide && !jwtOwner) {
91
+ const { fleetWide, gateOwner } = fleetViewOf(req, deps, "read");
92
+ if (!fleetWide && gateOwner === null) {
95
93
  sendUnauthorized(res, "identity");
96
94
  return;
97
95
  }
@@ -109,7 +107,7 @@ export async function handleTraceUsage(req, res, match, ctx) {
109
107
  sendError(res, 400, "request.query_invalid", "invalid from/to (ISO-8601 or epoch-ms; from < to)");
110
108
  return;
111
109
  }
112
- const owner = jwtOwner ?? (q.get("principal") ?? undefined);
110
+ const owner = gateOwner ?? (q.get("principal") ?? undefined);
113
111
  try {
114
112
  const scan = await runStore.usageScan(from, to, owner !== undefined ? { owner } : undefined);
115
113
  const base = { from: new Date(from).toISOString(), to: new Date(to).toISOString(), ...(scan.truncated ? { truncated: true } : {}) };