@sema-agent/server 7.132.0 → 7.133.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 (402) hide show
  1. package/MIGRATION.md +266 -0
  2. package/README.md +8 -9
  3. package/README.zh-CN.md +7 -6
  4. package/USAGE.md +174 -55
  5. package/deploy/sema-up/README.md +19 -1
  6. package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -2
  7. package/deploy/sema-up/chart/templates/server.yaml +5 -2
  8. package/deploy/sema-up/stack/compose.yaml +3 -0
  9. package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -2
  10. package/dist/adoption/plan.d.ts +3 -2
  11. package/dist/adoption/plan.js +7 -5
  12. package/dist/adoption/runner.js +3 -10
  13. package/dist/adoption/sql.d.ts +3 -2
  14. package/dist/adoption/sql.js +3 -5
  15. package/dist/adoption/wire.d.ts +4 -1
  16. package/dist/adoption/wire.js +1 -0
  17. package/dist/approval-ask-audit-store.d.ts +31 -13
  18. package/dist/approval-ask-audit-store.js +272 -74
  19. package/dist/approval-ask-machine.d.ts +15 -0
  20. package/dist/approval-ask-machine.js +6 -0
  21. package/dist/approval-ask-retention.d.ts +136 -0
  22. package/dist/approval-ask-retention.js +102 -0
  23. package/dist/approval-card.d.ts +79 -19
  24. package/dist/approval-card.js +44 -13
  25. package/dist/approval-deny-reasons.d.ts +1 -1
  26. package/dist/approval.d.ts +9 -0
  27. package/dist/approval.js +24 -3
  28. package/dist/audit.d.ts +27 -10
  29. package/dist/audit.js +12 -16
  30. package/dist/bake-runner/main.js +3 -2
  31. package/dist/boot/deferred-sandbox-path-env.js +1 -1
  32. package/dist/boot/execution-env.js +9 -7
  33. package/dist/boot/execution-lane.js +11 -0
  34. package/dist/boot/leader.js +2 -0
  35. package/dist/boot/memory-boundary.js +2 -2
  36. package/dist/boot/memory-consolidation.d.ts +5 -4
  37. package/dist/boot/memory-consolidation.js +7 -6
  38. package/dist/boot/org-delivery.d.ts +28 -0
  39. package/dist/boot/org-delivery.js +20 -0
  40. package/dist/boot/reapers.d.ts +3 -0
  41. package/dist/boot/reapers.js +21 -1
  42. package/dist/boot/resolve-spec.d.ts +3 -0
  43. package/dist/boot/resolve-spec.js +60 -81
  44. package/dist/boot/runner-deps.js +1 -0
  45. package/dist/boot/session-faces.d.ts +1 -0
  46. package/dist/boot/session-faces.js +4 -2
  47. package/dist/boot/stage-02-web-admin-pull.js +4 -1
  48. package/dist/boot/stage-06-runners.d.ts +2 -0
  49. package/dist/boot/stage-06-runners.js +6 -3
  50. package/dist/boot/stage-07-capability-layer.d.ts +2 -0
  51. package/dist/boot/stage-07-capability-layer.js +24 -3
  52. package/dist/boot/stage-08-reapers.d.ts +2 -0
  53. package/dist/boot/stage-08-reapers.js +2 -2
  54. package/dist/boot/stage-09-leader.d.ts +3 -0
  55. package/dist/boot/stage-10-http-server.d.ts +3 -0
  56. package/dist/boot/stage-10-http-server.js +5 -6
  57. package/dist/boot/stores.js +2 -2
  58. package/dist/boot/web-admin.d.ts +4 -0
  59. package/dist/boot/web-admin.js +151 -63
  60. package/dist/boot/workflow-orchestration.d.ts +2 -0
  61. package/dist/boot/workflow-orchestration.js +2 -1
  62. package/dist/brain.js +8 -3
  63. package/dist/breaker-key.d.ts +6 -0
  64. package/dist/breaker-key.js +29 -0
  65. package/dist/caller-text-echo.d.ts +9 -6
  66. package/dist/caller-text-echo.js +8 -11
  67. package/dist/capabilities/center-plugins.d.ts +7 -0
  68. package/dist/capabilities/center-plugins.js +1 -1
  69. package/dist/capabilities/composite-members.d.ts +1 -1
  70. package/dist/capabilities/composite-members.js +1 -1
  71. package/dist/capabilities/execution-lane.js +2 -2
  72. package/dist/capabilities/hands-lane.d.ts +21 -0
  73. package/dist/capabilities/hands-lane.js +10 -0
  74. package/dist/capabilities/mcp-probe.d.ts +36 -4
  75. package/dist/capabilities/mcp-probe.js +27 -4
  76. package/dist/capabilities/scenarios.d.ts +63 -7
  77. package/dist/capabilities/scenarios.js +39 -7
  78. package/dist/capability-facts.d.ts +34 -4
  79. package/dist/capability-facts.js +28 -2
  80. package/dist/center-config-tier.d.ts +69 -0
  81. package/dist/center-config-tier.js +42 -0
  82. package/dist/checkpoint-identity.d.ts +16 -0
  83. package/dist/checkpoint-identity.js +19 -0
  84. package/dist/config-catalog.d.ts +17 -10
  85. package/dist/config-catalog.js +43 -28
  86. package/dist/config-d-migration.d.ts +3 -1
  87. package/dist/config-d-migration.js +2 -2
  88. package/dist/config-dir-trust.d.ts +114 -0
  89. package/dist/config-dir-trust.js +388 -0
  90. package/dist/config-invariants.d.ts +18 -5
  91. package/dist/config-invariants.js +35 -3
  92. package/dist/config-provider.d.ts +6 -1
  93. package/dist/config-provider.js +6 -2
  94. package/dist/config-types.d.ts +71 -14
  95. package/dist/config-types.js +8 -0
  96. package/dist/config.d.ts +13 -0
  97. package/dist/config.js +121 -59
  98. package/dist/delegated-session-owner.d.ts +185 -0
  99. package/dist/delegated-session-owner.js +119 -0
  100. package/dist/device-protocol.d.ts +5 -3
  101. package/dist/device-protocol.js +1 -1
  102. package/dist/device-ws-hub.js +21 -2
  103. package/dist/device-ws-protocol.d.ts +70 -6
  104. package/dist/device-ws-protocol.js +50 -23
  105. package/dist/elicitation.js +3 -2
  106. package/dist/entry-problems.d.ts +34 -0
  107. package/dist/entry-problems.js +14 -0
  108. package/dist/execution-lane-caps.d.ts +49 -10
  109. package/dist/execution-lane-caps.js +43 -4
  110. package/dist/field-conflict.d.ts +43 -0
  111. package/dist/field-conflict.js +20 -0
  112. package/dist/fleet/fleet-bus.d.ts +80 -6
  113. package/dist/fleet/fleet-bus.js +41 -9
  114. package/dist/hooks/classic-stations.d.ts +10 -5
  115. package/dist/hooks/classic-stations.js +4 -4
  116. package/dist/hooks/command-spawn.d.ts +57 -0
  117. package/dist/hooks/command-spawn.js +139 -0
  118. package/dist/hooks/hook-llm.js +2 -2
  119. package/dist/hooks/hook-runner.d.ts +127 -25
  120. package/dist/hooks/hook-runner.js +668 -287
  121. package/dist/hooks/hook-source.d.ts +44 -0
  122. package/dist/hooks/hook-source.js +40 -0
  123. package/dist/http/active-run-conflict.d.ts +5 -13
  124. package/dist/http/active-run-conflict.js +17 -27
  125. package/dist/http/admission.js +103 -60
  126. package/dist/http/approval-sweeps.js +55 -18
  127. package/dist/http/caller-trust.d.ts +77 -0
  128. package/dist/http/caller-trust.js +143 -0
  129. package/dist/http/checkpoint-ctx.d.ts +16 -16
  130. package/dist/http/checkpoint-ctx.js +13 -10
  131. package/dist/http/claimed-run.d.ts +4 -3
  132. package/dist/http/device-placement.d.ts +2 -4
  133. package/dist/http/device-placement.js +2 -1
  134. package/dist/http/dispatch.js +10 -4
  135. package/dist/http/durable-run-leg.d.ts +4 -32
  136. package/dist/http/durable-run-leg.js +34 -10
  137. package/dist/http/owner-access.d.ts +56 -0
  138. package/dist/http/owner-access.js +42 -0
  139. package/dist/http/principal-gate.d.ts +48 -23
  140. package/dist/http/principal-gate.js +39 -12
  141. package/dist/http/readiness.d.ts +11 -5
  142. package/dist/http/readiness.js +10 -3
  143. package/dist/http/request-guards.d.ts +16 -23
  144. package/dist/http/request-guards.js +30 -15
  145. package/dist/http/resume-ctx-read.d.ts +2 -5
  146. package/dist/http/resume-ctx-read.js +7 -4
  147. package/dist/http/resume-legs.d.ts +3 -4
  148. package/dist/http/resume-legs.js +126 -69
  149. package/dist/http/retired-service-deps.d.ts +43 -0
  150. package/dist/http/retired-service-deps.js +18 -0
  151. package/dist/http/route-ctx.d.ts +44 -28
  152. package/dist/http/route-ctx.js +4 -0
  153. package/dist/http/route-table.js +2 -0
  154. package/dist/http/routes/a2a-serve.js +3 -4
  155. package/dist/http/routes/admin-config-refresh.js +1 -1
  156. package/dist/http/routes/admin-drain.js +1 -1
  157. package/dist/http/routes/admin-memory-optout.js +5 -1
  158. package/dist/http/routes/adoption.js +2 -9
  159. package/dist/http/routes/approvals-assistant.js +49 -48
  160. package/dist/http/routes/background.js +3 -2
  161. package/dist/http/routes/capabilities.js +20 -4
  162. package/dist/http/routes/config-catalog.d.ts +3 -3
  163. package/dist/http/routes/config-catalog.js +1 -1
  164. package/dist/http/routes/devices.js +3 -17
  165. package/dist/http/routes/diagnostics.js +5 -1
  166. package/dist/http/routes/images.js +6 -7
  167. package/dist/http/routes/leader.js +1 -8
  168. package/dist/http/routes/mcp-reconnect.d.ts +1 -1
  169. package/dist/http/routes/mcp-reconnect.js +3 -2
  170. package/dist/http/routes/memory-bundle.js +1 -1
  171. package/dist/http/routes/memory-compliance.js +1 -1
  172. package/dist/http/routes/memory-consolidation.js +1 -1
  173. package/dist/http/routes/memory-origin.js +1 -1
  174. package/dist/http/routes/memory-policy.d.ts +1 -1
  175. package/dist/http/routes/memory-policy.js +3 -2
  176. package/dist/http/routes/notify-wake.js +8 -21
  177. package/dist/http/routes/observability.js +2 -2
  178. package/dist/http/routes/principal-inbox.d.ts +39 -0
  179. package/dist/http/routes/principal-inbox.js +76 -0
  180. package/dist/http/routes/retention-ops.js +2 -9
  181. package/dist/http/routes/rules.js +5 -18
  182. package/dist/http/routes/runs.d.ts +5 -0
  183. package/dist/http/routes/runs.js +33 -106
  184. package/dist/http/routes/session-sync.js +15 -28
  185. package/dist/http/routes/sessions.js +30 -40
  186. package/dist/http/routes/side-query.js +6 -4
  187. package/dist/http/routes/tasks.js +50 -14
  188. package/dist/http/routes/workflows.d.ts +351 -0
  189. package/dist/http/routes/workflows.js +153 -119
  190. package/dist/http/send.d.ts +24 -3
  191. package/dist/http/send.js +14 -2
  192. package/dist/http/server.d.ts +17 -18
  193. package/dist/http/server.js +15 -13
  194. package/dist/http/stored-body-replay.js +17 -4
  195. package/dist/http/submit-ctx.js +4 -3
  196. package/dist/http/submit-replay.d.ts +4 -3
  197. package/dist/http/submit-replay.js +5 -4
  198. package/dist/http/wire-types.d.ts +10 -7
  199. package/dist/index.d.ts +1 -1
  200. package/dist/index.js +0 -1
  201. package/dist/lane-home-probe.d.ts +78 -9
  202. package/dist/lane-home-probe.js +78 -12
  203. package/dist/leader/endpoint.d.ts +4 -1
  204. package/dist/leader/endpoint.js +11 -10
  205. package/dist/limit-refusal.d.ts +17 -5
  206. package/dist/limit-refusal.js +4 -1
  207. package/dist/mcp-assertion-header.d.ts +31 -10
  208. package/dist/mcp-assertion-header.js +10 -3
  209. package/dist/mcp-tool-faces.js +1 -3
  210. package/dist/memory-project-layer.d.ts +37 -0
  211. package/dist/memory-project-layer.js +46 -0
  212. package/dist/memory-scope.d.ts +23 -16
  213. package/dist/memory-scope.js +24 -8
  214. package/dist/memory-sync-client.d.ts +27 -13
  215. package/dist/memory-sync-client.js +107 -18
  216. package/dist/model-entry-refusal.d.ts +9 -1
  217. package/dist/model-entry-refusal.js +6 -1
  218. package/dist/model-plane-face.d.ts +51 -0
  219. package/dist/model-plane-face.js +24 -0
  220. package/dist/model-provider.d.ts +5 -0
  221. package/dist/model-provider.js +4 -2
  222. package/dist/model-route-endpoint.d.ts +8 -11
  223. package/dist/model-route-endpoint.js +4 -7
  224. package/dist/model-route-env.d.ts +22 -0
  225. package/dist/model-route-env.js +2 -0
  226. package/dist/model-route-gap.d.ts +60 -30
  227. package/dist/model-route-gap.js +21 -15
  228. package/dist/observability/corrupt-read-seat.d.ts +7 -0
  229. package/dist/observability/corrupt-read-seat.js +9 -0
  230. package/dist/observability/err-text.d.ts +6 -0
  231. package/dist/observability/err-text.js +18 -4
  232. package/dist/observability/fail-open.d.ts +35 -9
  233. package/dist/observability/fail-open.js +35 -9
  234. package/dist/observability/metrics.js +1 -0
  235. package/dist/observability/prompt-manifest.d.ts +3 -17
  236. package/dist/observability/prompt-manifest.js +45 -42
  237. package/dist/observability/tool-trace.js +9 -9
  238. package/dist/operator-ask.d.ts +10 -0
  239. package/dist/operator-ask.js +3 -0
  240. package/dist/orchestration/workflow-agent-session-index.d.ts +12 -12
  241. package/dist/orchestration/workflow-agent-session-index.js +9 -13
  242. package/dist/orchestration/workflow-completion-inbox.d.ts +42 -15
  243. package/dist/orchestration/workflow-completion-inbox.js +13 -0
  244. package/dist/orchestration/workflow-notify-journal.d.ts +13 -32
  245. package/dist/orchestration/workflow-notify-journal.js +27 -34
  246. package/dist/orchestration/workflow-park-decision.d.ts +89 -0
  247. package/dist/orchestration/workflow-park-decision.js +118 -0
  248. package/dist/org-delivery-gate.d.ts +81 -0
  249. package/dist/org-delivery-gate.js +59 -0
  250. package/dist/panel-tool-names.d.ts +23 -0
  251. package/dist/panel-tool-names.js +8 -0
  252. package/dist/parked-decide.d.ts +39 -6
  253. package/dist/parked-decide.js +98 -51
  254. package/dist/parked-revive-surface.d.ts +9 -2
  255. package/dist/parked-revive-surface.js +11 -8
  256. package/dist/permission-rule-list.d.ts +1 -1
  257. package/dist/permission-rule-list.js +2 -2
  258. package/dist/plugins/approval-ask-store-file.d.ts +16 -1
  259. package/dist/plugins/approval-ask-store-file.js +21 -0
  260. package/dist/plugins/approval-ask-store-memory.d.ts +18 -1
  261. package/dist/plugins/approval-ask-store-memory.js +34 -2
  262. package/dist/plugins/approval-ask-store-sql.d.ts +25 -0
  263. package/dist/plugins/approval-ask-store-sql.js +37 -1
  264. package/dist/plugins/blob-backend.d.ts +38 -25
  265. package/dist/plugins/blob-backend.js +29 -19
  266. package/dist/plugins/breaker-state-sql.d.ts +2 -2
  267. package/dist/plugins/breaker-state-sql.js +4 -4
  268. package/dist/plugins/caching-session-store.d.ts +3 -0
  269. package/dist/plugins/caching-session-store.js +3 -0
  270. package/dist/plugins/checkpoint-store-sql.d.ts +14 -0
  271. package/dist/plugins/checkpoint-store-sql.js +20 -2
  272. package/dist/plugins/file-history-store-sql.d.ts +5 -2
  273. package/dist/plugins/file-history-store-sql.js +3 -1
  274. package/dist/plugins/file-run-store.d.ts +5 -13
  275. package/dist/plugins/file-run-store.js +9 -0
  276. package/dist/plugins/fork-routing-session-store.d.ts +9 -1
  277. package/dist/plugins/fork-routing-session-store.js +12 -1
  278. package/dist/plugins/host-platform.d.ts +2 -0
  279. package/dist/plugins/host-platform.js +2 -1
  280. package/dist/plugins/local-checkpoint-store.d.ts +2 -0
  281. package/dist/plugins/local-checkpoint-store.js +6 -1
  282. package/dist/plugins/local-session-store.d.ts +1 -1
  283. package/dist/plugins/local-session-window.d.ts +39 -0
  284. package/dist/plugins/local-session-window.js +54 -0
  285. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +3 -2
  286. package/dist/plugins/mailbox-store-sql.d.ts +30 -48
  287. package/dist/plugins/mailbox-store-sql.js +77 -52
  288. package/dist/plugins/memory-embedder-fingerprint.js +2 -1
  289. package/dist/plugins/memory-run-store.d.ts +5 -13
  290. package/dist/plugins/memory-run-store.js +8 -0
  291. package/dist/plugins/one-time-migrations.d.ts +110 -5
  292. package/dist/plugins/one-time-migrations.js +320 -8
  293. package/dist/plugins/org-delivery-quota-store.d.ts +123 -0
  294. package/dist/plugins/org-delivery-quota-store.js +228 -0
  295. package/dist/plugins/pg-pool.js +39 -7
  296. package/dist/plugins/pg-session-storage.d.ts +17 -4
  297. package/dist/plugins/pg-session-storage.js +29 -6
  298. package/dist/plugins/remote-env-adb.d.ts +6 -12
  299. package/dist/plugins/remote-env-adb.js +12 -2
  300. package/dist/plugins/remote-env-k8s.d.ts +8 -12
  301. package/dist/plugins/remote-env-k8s.js +23 -5
  302. package/dist/plugins/remote-env-local-docker.d.ts +10 -15
  303. package/dist/plugins/remote-env-local-docker.js +12 -9
  304. package/dist/plugins/remote-env-ssh.d.ts +10 -16
  305. package/dist/plugins/remote-env-ssh.js +17 -11
  306. package/dist/plugins/run-store-sql.d.ts +16 -14
  307. package/dist/plugins/run-store-sql.js +22 -2
  308. package/dist/plugins/schema-indexes.js +2 -0
  309. package/dist/plugins/send-user-file.js +2 -2
  310. package/dist/plugins/session-epoch-anchor.d.ts +32 -6
  311. package/dist/plugins/session-epoch-anchor.js +2 -3
  312. package/dist/plugins/session-store.d.ts +18 -8
  313. package/dist/plugins/session-store.js +15 -4
  314. package/dist/plugins/sql-driver.d.ts +74 -11
  315. package/dist/plugins/sql-driver.js +210 -12
  316. package/dist/plugins/sql-errors.d.ts +23 -0
  317. package/dist/plugins/sql-errors.js +21 -0
  318. package/dist/plugins/store-backend.d.ts +36 -1
  319. package/dist/plugins/store-backend.js +40 -14
  320. package/dist/plugins/store-contracts.d.ts +42 -0
  321. package/dist/plugins/store-contracts.js +1 -0
  322. package/dist/plugins/tidb-pool.d.ts +6 -1
  323. package/dist/plugins/tidb-pool.js +44 -10
  324. package/dist/plugins/tidb-session-storage.d.ts +3 -2
  325. package/dist/plugins/tidb-session-storage.js +2 -2
  326. package/dist/plugins/tidb-session-store.d.ts +24 -4
  327. package/dist/plugins/tidb-session-store.js +28 -4
  328. package/dist/plugins/workflow-journal-store-sql.d.ts +73 -19
  329. package/dist/plugins/workflow-journal-store-sql.js +19 -6
  330. package/dist/plugins/workflow-run-store-sql.d.ts +30 -8
  331. package/dist/plugins/workflow-run-store-sql.js +50 -9
  332. package/dist/posture-source.d.ts +18 -10
  333. package/dist/posture-source.js +4 -1
  334. package/dist/project-identity.d.ts +45 -6
  335. package/dist/project-identity.js +162 -8
  336. package/dist/project-layer-key.d.ts +28 -0
  337. package/dist/project-layer-key.js +29 -0
  338. package/dist/question.js +3 -2
  339. package/dist/read-deny-entry.d.ts +25 -0
  340. package/dist/read-deny-entry.js +12 -0
  341. package/dist/read-face-posture.d.ts +37 -11
  342. package/dist/read-face-posture.js +32 -3
  343. package/dist/request-key-closure.d.ts +7 -0
  344. package/dist/request-key-closure.js +9 -1
  345. package/dist/request-value-closure.d.ts +5 -0
  346. package/dist/request-value-closure.js +11 -3
  347. package/dist/rule-entry-list.d.ts +26 -2
  348. package/dist/rule-entry-list.js +72 -12
  349. package/dist/rules-consent.js +3 -4
  350. package/dist/run-acceptance.d.ts +19 -3
  351. package/dist/run-acceptance.js +13 -1
  352. package/dist/run-local.js +36 -6
  353. package/dist/runs.d.ts +10 -9
  354. package/dist/runs.js +21 -3
  355. package/dist/runtime-caps-resolver.d.ts +16 -6
  356. package/dist/runtime-caps-resolver.js +18 -5
  357. package/dist/sandbox-pkg-source.d.ts +19 -1
  358. package/dist/sandbox-pkg-source.js +29 -7
  359. package/dist/security.d.ts +87 -9
  360. package/dist/security.js +52 -9
  361. package/dist/session-error-wire.d.ts +19 -2
  362. package/dist/session-error-wire.js +5 -1
  363. package/dist/session-titled-frame.d.ts +33 -0
  364. package/dist/session-titled-frame.js +4 -0
  365. package/dist/session-titler.d.ts +9 -1
  366. package/dist/session-titler.js +15 -4
  367. package/dist/spec-fields.js +21 -2
  368. package/dist/sql-engine-posture.d.ts +3 -1
  369. package/dist/task-cwd.d.ts +1 -1
  370. package/dist/task-mcp.d.ts +3 -3
  371. package/dist/task-mcp.js +7 -66
  372. package/dist/task-settings.d.ts +89 -88
  373. package/dist/task-settings.js +71 -63
  374. package/dist/text-bidi.d.ts +0 -4
  375. package/dist/text-bidi.js +1 -3
  376. package/dist/tighten-only-seats.d.ts +150 -0
  377. package/dist/tighten-only-seats.js +196 -0
  378. package/dist/tool-approval.d.ts +303 -87
  379. package/dist/tool-approval.js +623 -239
  380. package/dist/trace/core-keyset-guard.d.ts +104 -22
  381. package/dist/trace/exit-seat.d.ts +28 -0
  382. package/dist/trace/exit-seat.js +76 -0
  383. package/dist/trace/ledger-events.d.ts +3 -2
  384. package/dist/trace/project.d.ts +80 -12
  385. package/dist/trace/project.js +41 -28
  386. package/dist/trace/projection-table.d.ts +100 -0
  387. package/dist/trace/projection-table.js +130 -0
  388. package/dist/trace/redact.d.ts +54 -0
  389. package/dist/trace/redact.js +778 -152
  390. package/dist/trace/self-minted-wire.d.ts +345 -1
  391. package/dist/trace/self-minted-wire.js +117 -1
  392. package/dist/trace/wire-projection-faces.d.ts +298 -2
  393. package/dist/trace/wire-projection-faces.js +154 -13
  394. package/dist/url-refusal.js +2 -0
  395. package/dist/web-admin-client/apply-effective.d.ts +12 -0
  396. package/dist/web-admin-client/apply-effective.js +56 -5
  397. package/dist/web-admin-client/facade.d.ts +1 -1
  398. package/dist/web-admin-client/facade.js +1 -1
  399. package/dist/web-admin-client/read-face.js +5 -9
  400. package/dist/web-admin-client/skills-mcp.js +4 -5
  401. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -9
  402. package/package.json +7 -3
@@ -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 { 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--) {
@@ -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) {
@@ -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
  }
@@ -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,7 +18,7 @@ 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
24
  import { createApprovalCardEmitter, resolveApprovalLeg, resolveStreamApprovalGate } from "../../tool-approval.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))
@@ -148,13 +151,13 @@ export async function handleTasks(req, res, match, ctx) {
148
151
  if (!prepared)
149
152
  return;
150
153
  const principal = prepared.auth?.principal;
151
- const wiringOperatorFace = explicitOperatorOk(gatedPrincipal(req, deps.config), deps.config.operatorPrincipals);
154
+ const wiringOperatorFace = explicitOperatorOk(gatedPrincipal(req, deps.config), deps.config);
152
155
  let wiringReceipt;
153
156
  const instructionLeg = createInstructionSelectionLeg();
154
157
  const withRunReceipt = (out) => wiringReceipt !== undefined ? { ...out, wiringManifest: wiringReceipt } : out;
155
158
  if (liveStream) {
156
159
  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");
160
+ 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
161
  return;
159
162
  }
160
163
  const earlyDurableTid = facts.durableRuns(deps).available && prepared.spec.sessionId ? uuidv7() : undefined;
@@ -169,7 +172,7 @@ export async function handleTasks(req, res, match, ctx) {
169
172
  reqState.streamDetached = detachOnDisconnect;
170
173
  sseHeaders(res, earlyDurableTid ? { "x-task-id": earlyDurableTid } : undefined);
171
174
  if (earlyDurableTid)
172
- writeMetaFrame(res, earlyDurableTid, prepared.spec.sessionId);
175
+ writeMetaFrame(res, earlyDurableTid, prepared.spec.sessionId, prepared.warnings);
173
176
  const ac = createRunAbort();
174
177
  let closed = false;
175
178
  let detachLogged = false;
@@ -215,14 +218,26 @@ export async function handleTasks(req, res, match, ctx) {
215
218
  parkFacility: deps.checkpointStore !== undefined,
216
219
  });
217
220
  const replaySessionId = replayGate.active ? prepared.spec.sessionId : undefined;
221
+ const presentedOnConnection = new Set();
222
+ const presentedCompleted = new Set();
223
+ const admitPresentedComplete = (askId) => {
224
+ if (!presentedOnConnection.has(askId))
225
+ return true;
226
+ if (presentedCompleted.has(askId))
227
+ return false;
228
+ presentedCompleted.add(askId);
229
+ return true;
230
+ };
218
231
  if (replaySessionId) {
219
232
  const replayOwner = gatedPrincipal(req, deps.config) ?? null;
220
233
  const askStore = replayGate.active ? replayGate.askStore : undefined;
234
+ let presentedAskIds = [];
221
235
  const preambleFrames = await collectSsePreamble(async (signal) => {
222
236
  if (!askStore)
223
237
  return [];
224
238
  const rows = await askStore.listPendingBySession(replaySessionId, replayOwner, signal);
225
239
  const { frames, skipped, dropped } = buildApprovalPreamble(rows, Date.now(), deps.config.streamApproval.replayMax);
240
+ presentedAskIds = frames.map((f) => f.askId);
226
241
  if (skipped > 0)
227
242
  deps.logger?.warn?.("approval_preamble_row_skipped", { sessionId: replaySessionId, skipped, face: "tasks.stream" });
228
243
  if (dropped > 0)
@@ -232,6 +247,16 @@ export async function handleTasks(req, res, match, ctx) {
232
247
  if (!res.writableEnded && !res.destroyed) {
233
248
  for (const f of preambleFrames)
234
249
  res.write(`event: ${f.event}\ndata: ${JSON.stringify(f.data)}\n\n`);
250
+ if (deps.toolApproval && preambleFrames.length > 0) {
251
+ for (const askId of presentedAskIds)
252
+ presentedOnConnection.add(askId);
253
+ const unwatch = deps.toolApproval.watchPresentedCards(presentedAskIds, (frame) => {
254
+ if (res.writableEnded || res.destroyed || !admitPresentedComplete(frame.askId))
255
+ return;
256
+ res.write(`event: ${frame.type}\ndata: ${JSON.stringify(frame)}\n\n`);
257
+ });
258
+ res.once("close", unwatch);
259
+ }
235
260
  }
236
261
  }
237
262
  const hb = setInterval(() => {
@@ -378,7 +403,9 @@ export async function handleTasks(req, res, match, ctx) {
378
403
  const tailContentMode = prepared.spec.forwardSubagentEvents === true ? "on" : "progress_only";
379
404
  const childReasoning = createReasoningSegments();
380
405
  const topReasoning = createReasoningSegments();
406
+ const heldDecisions = prepared.spec.sessionId !== undefined ? await heldWorkflowParkDecisions(deps, prepared.spec.sessionId) : {};
381
407
  const fwdInternals = {
408
+ ...heldDecisions,
382
409
  onForwardEvent: (e) => {
383
410
  fleetPub?.onForwardEvent(e);
384
411
  ledgerSink?.onForwardEvent(e);
@@ -457,6 +484,7 @@ export async function handleTasks(req, res, match, ctx) {
457
484
  liveStreamRef = liveStream;
458
485
  if (durableTaskId)
459
486
  steerableRuns.set(durableTaskId, liveStream);
487
+ prepared.acceptance.attachStream({ reachable: () => !closed && !res.writableEnded && !res.destroyed, write: (frame) => sseData(res, { ...frame }) });
460
488
  for await (const ev of liveStream) {
461
489
  if (closed)
462
490
  break;
@@ -659,6 +687,8 @@ export async function handleTasks(req, res, match, ctx) {
659
687
  writeLive: (frame) => {
660
688
  if (res.writableEnded || res.destroyed)
661
689
  throw new Error("live stream ended");
690
+ if (frame.type === "approval_complete" && !admitPresentedComplete(frame.askId))
691
+ return;
662
692
  emitAsk(frame);
663
693
  },
664
694
  });
@@ -670,7 +700,6 @@ export async function handleTasks(req, res, match, ctx) {
670
700
  ? {
671
701
  taskId: askTaskId,
672
702
  owner: askOwner,
673
- emit: emitApproval,
674
703
  abortSignal: ac.signal,
675
704
  ...(prepared.spec.sessionId ? { sessionId: prepared.spec.sessionId } : {}),
676
705
  ...(streamApprovalOn
@@ -680,7 +709,7 @@ export async function handleTasks(req, res, match, ctx) {
680
709
  legKey: "",
681
710
  ...(legDeadlineMonotonic !== undefined ? { legDeadlineMonotonic } : {}),
682
711
  }
683
- : {}),
712
+ : { emit: emitApproval }),
684
713
  }
685
714
  : undefined;
686
715
  if (deps.toolApproval) {
@@ -843,7 +872,13 @@ export async function handleTasks(req, res, match, ctx) {
843
872
  res.end();
844
873
  }
845
874
  else {
846
- const withSyncSubmitKeys = (body) => prepared.verify || prepared.cascade ? { ...body, notice: MULTI_ATTEMPT_NO_EVENT_CHANNEL_NOTICE } : body;
875
+ const withSyncSubmitKeys = (body) => {
876
+ const extra = {
877
+ ...(prepared.verify || prepared.cascade ? { notice: MULTI_ATTEMPT_NO_EVENT_CHANNEL_NOTICE } : {}),
878
+ ...(prepared.warnings !== undefined ? { warnings: prepared.warnings } : {}),
879
+ };
880
+ return Object.keys(extra).length > 0 ? { ...body, ...extra } : body;
881
+ };
847
882
  const runSyncSubmitLeg = async () => {
848
883
  const syncLegStartedAt = Date.now();
849
884
  let durableTaskId;
@@ -902,10 +937,11 @@ export async function handleTasks(req, res, match, ctx) {
902
937
  let result;
903
938
  counters.uncountedBillableInflight++;
904
939
  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));
940
+ const heldDecisions = prepared.spec.sessionId !== undefined ? await heldWorkflowParkDecisions(deps, prepared.spec.sessionId) : {};
941
+ const verifyLeg = (v) => runWithVerification(prepared.runner, specWithSignal, v, heldDecisions);
942
+ const cascadeLeg = () => runCascade(prepared.runner, specWithSignal, cascadeConfig(deps.config.cascadeLadder, prepared.spec.limits?.maxCostUsd), heldDecisions);
907
943
  const plainLeg = async () => {
908
- const stream = prepared.runner.runTaskStream(specWithSignal);
944
+ const stream = prepared.runner.runTaskStream(specWithSignal, undefined, heldDecisions);
909
945
  for await (const ev of stream) {
910
946
  observeSyncLegEvent(ev);
911
947
  prepared.acceptance.observe(ev);
@@ -942,8 +978,8 @@ export async function handleTasks(req, res, match, ctx) {
942
978
  const retryAfterSec = resumeAtPlane.errorCode === "memory.admission_required" && result.retryAfterMs !== undefined
943
979
  ? Math.max(1, Math.ceil(result.retryAfterMs / 1000))
944
980
  : 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 } };
981
+ const refusalFacts = zeroWorkRefusalFacts(redactTerminalResult(sealResultForExit(result)).terminal, prepared.warnings);
982
+ return { status: resumeAtStatus, body: refusalBody({ errorCode: httpErrorCode(resumeAtStatus, resumeAtPlane.errorCode), message: redactErrorMessage(resumeAtPlane.errorMessage) ?? "resume-at failed", facts: { ...(retryAfterSec !== undefined ? { retryAfterSec } : {}), ...refusalFacts } }) };
947
983
  }
948
984
  const exitResult = await mintSubmitExitResult(result, deps.checkpointStore);
949
985
  const syncPlane = outwardPlane(result.terminal);