@sema-agent/server 7.131.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 (509) hide show
  1. package/MIGRATION.md +575 -0
  2. package/README.md +12 -9
  3. package/README.zh-CN.md +9 -6
  4. package/USAGE.md +326 -98
  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 +82 -20
  24. package/dist/approval-card.js +46 -16
  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 +33 -19
  29. package/dist/audit.js +12 -16
  30. package/dist/auth-bridge.d.ts +4 -0
  31. package/dist/auth-bridge.js +10 -11
  32. package/dist/bake-runner/main.js +3 -2
  33. package/dist/boot/deferred-sandbox-path-env.js +1 -1
  34. package/dist/boot/deployment-mods.d.ts +31 -0
  35. package/dist/boot/deployment-mods.js +26 -0
  36. package/dist/boot/execution-env.d.ts +1 -1
  37. package/dist/boot/execution-env.js +27 -12
  38. package/dist/boot/execution-lane.js +11 -0
  39. package/dist/boot/leader.js +2 -0
  40. package/dist/boot/memory-boundary.d.ts +2 -2
  41. package/dist/boot/memory-boundary.js +2 -2
  42. package/dist/boot/memory-consolidation.d.ts +5 -4
  43. package/dist/boot/memory-consolidation.js +7 -6
  44. package/dist/boot/org-delivery.d.ts +28 -0
  45. package/dist/boot/org-delivery.js +20 -0
  46. package/dist/boot/read-deny-anchor-audit.d.ts +17 -0
  47. package/dist/boot/read-deny-anchor-audit.js +36 -0
  48. package/dist/boot/reapers.d.ts +3 -0
  49. package/dist/boot/reapers.js +21 -1
  50. package/dist/boot/resolve-spec.d.ts +4 -5
  51. package/dist/boot/resolve-spec.js +74 -123
  52. package/dist/boot/runner-deps.d.ts +19 -8
  53. package/dist/boot/runner-deps.js +15 -2
  54. package/dist/boot/session-faces.d.ts +2 -7
  55. package/dist/boot/session-faces.js +4 -2
  56. package/dist/boot/stage-02-web-admin-pull.js +4 -1
  57. package/dist/boot/stage-03-store-backend.d.ts +1 -1
  58. package/dist/boot/stage-03-store-backend.js +2 -2
  59. package/dist/boot/stage-04-stores.d.ts +1 -1
  60. package/dist/boot/stage-05-execution-env.d.ts +4 -4
  61. package/dist/boot/stage-05-execution-env.js +7 -10
  62. package/dist/boot/stage-06-runners.d.ts +4 -2
  63. package/dist/boot/stage-06-runners.js +11 -7
  64. package/dist/boot/stage-07-capability-layer.d.ts +4 -2
  65. package/dist/boot/stage-07-capability-layer.js +27 -6
  66. package/dist/boot/stage-08-reapers.d.ts +4 -2
  67. package/dist/boot/stage-08-reapers.js +2 -2
  68. package/dist/boot/stage-09-leader.d.ts +6 -9
  69. package/dist/boot/stage-10-http-server.d.ts +6 -9
  70. package/dist/boot/stage-10-http-server.js +7 -9
  71. package/dist/boot/stores.d.ts +1 -1
  72. package/dist/boot/stores.js +7 -8
  73. package/dist/boot/web-admin.d.ts +4 -3
  74. package/dist/boot/web-admin.js +186 -98
  75. package/dist/boot/workflow-orchestration.d.ts +2 -0
  76. package/dist/boot/workflow-orchestration.js +2 -1
  77. package/dist/brain.js +25 -25
  78. package/dist/breaker-key.d.ts +6 -0
  79. package/dist/breaker-key.js +29 -0
  80. package/dist/budget.js +5 -4
  81. package/dist/caller-text-echo.d.ts +23 -0
  82. package/dist/caller-text-echo.js +21 -0
  83. package/dist/capabilities/brand-identity.d.ts +26 -0
  84. package/dist/capabilities/brand-identity.js +27 -0
  85. package/dist/capabilities/center-plugins.d.ts +7 -0
  86. package/dist/capabilities/center-plugins.js +1 -1
  87. package/dist/capabilities/center-prompts.d.ts +32 -59
  88. package/dist/capabilities/center-prompts.js +18 -32
  89. package/dist/capabilities/composite-members.d.ts +1 -1
  90. package/dist/capabilities/composite-members.js +1 -1
  91. package/dist/capabilities/engine-capabilities.js +2 -1
  92. package/dist/capabilities/execution-lane.js +2 -2
  93. package/dist/capabilities/hands-lane.d.ts +30 -6
  94. package/dist/capabilities/hands-lane.js +11 -1
  95. package/dist/capabilities/mcp-probe.d.ts +48 -3
  96. package/dist/capabilities/mcp-probe.js +47 -135
  97. package/dist/capabilities/scenarios.d.ts +95 -45
  98. package/dist/capabilities/scenarios.js +53 -38
  99. package/dist/capabilities/skills.d.ts +19 -4
  100. package/dist/capabilities/skills.js +30 -10
  101. package/dist/capability-facts.d.ts +34 -4
  102. package/dist/capability-facts.js +28 -2
  103. package/dist/center-config-tier.d.ts +69 -0
  104. package/dist/center-config-tier.js +42 -0
  105. package/dist/checkpoint-identity.d.ts +16 -0
  106. package/dist/checkpoint-identity.js +19 -0
  107. package/dist/config-catalog.d.ts +17 -10
  108. package/dist/config-catalog.js +47 -32
  109. package/dist/config-d-migration.d.ts +3 -1
  110. package/dist/config-d-migration.js +2 -2
  111. package/dist/config-dir-trust.d.ts +114 -0
  112. package/dist/config-dir-trust.js +388 -0
  113. package/dist/config-invariants.d.ts +18 -5
  114. package/dist/config-invariants.js +35 -3
  115. package/dist/config-lkg.d.ts +9 -9
  116. package/dist/config-lkg.js +20 -4
  117. package/dist/config-provider.d.ts +9 -2
  118. package/dist/config-provider.js +18 -6
  119. package/dist/config-types.d.ts +75 -20
  120. package/dist/config-types.js +8 -0
  121. package/dist/config.d.ts +13 -0
  122. package/dist/config.js +137 -62
  123. package/dist/delegated-session-owner.d.ts +185 -0
  124. package/dist/delegated-session-owner.js +119 -0
  125. package/dist/device-protocol.d.ts +5 -3
  126. package/dist/device-protocol.js +1 -1
  127. package/dist/device-ws-hub.js +21 -2
  128. package/dist/device-ws-protocol.d.ts +70 -6
  129. package/dist/device-ws-protocol.js +50 -22
  130. package/dist/elicitation.js +3 -2
  131. package/dist/entry-problems.d.ts +34 -0
  132. package/dist/entry-problems.js +14 -0
  133. package/dist/env-name-allowlist-knobs.d.ts +12 -2
  134. package/dist/env-name-allowlist-knobs.js +5 -4
  135. package/dist/exec-bounds.d.ts +15 -3
  136. package/dist/exec-bounds.js +4 -0
  137. package/dist/execution-lane-caps.d.ts +56 -10
  138. package/dist/execution-lane-caps.js +50 -0
  139. package/dist/field-conflict.d.ts +43 -0
  140. package/dist/field-conflict.js +20 -0
  141. package/dist/fleet/fleet-bus.d.ts +80 -6
  142. package/dist/fleet/fleet-bus.js +41 -9
  143. package/dist/hooks/classic-stations.d.ts +91 -0
  144. package/dist/hooks/classic-stations.js +27 -0
  145. package/dist/hooks/command-spawn.d.ts +57 -0
  146. package/dist/hooks/command-spawn.js +139 -0
  147. package/dist/hooks/hook-llm.d.ts +8 -5
  148. package/dist/hooks/hook-llm.js +79 -36
  149. package/dist/hooks/hook-runner.d.ts +349 -95
  150. package/dist/hooks/hook-runner.js +855 -568
  151. package/dist/hooks/hook-source.d.ts +44 -0
  152. package/dist/hooks/hook-source.js +40 -0
  153. package/dist/http/active-run-conflict.d.ts +5 -13
  154. package/dist/http/active-run-conflict.js +17 -27
  155. package/dist/http/admission.d.ts +8 -2
  156. package/dist/http/admission.js +188 -101
  157. package/dist/http/approval-sweeps.js +99 -21
  158. package/dist/http/caller-trust.d.ts +77 -0
  159. package/dist/http/caller-trust.js +143 -0
  160. package/dist/http/checkpoint-ctx.d.ts +41 -24
  161. package/dist/http/checkpoint-ctx.js +23 -16
  162. package/dist/http/claimed-run.d.ts +14 -0
  163. package/dist/http/claimed-run.js +15 -0
  164. package/dist/http/device-placement.d.ts +2 -4
  165. package/dist/http/device-placement.js +7 -11
  166. package/dist/http/dispatch.d.ts +0 -4
  167. package/dist/http/dispatch.js +15 -13
  168. package/dist/http/durable-run-leg.d.ts +6 -33
  169. package/dist/http/durable-run-leg.js +36 -10
  170. package/dist/http/health-self-report.d.ts +7 -5
  171. package/dist/http/health-self-report.js +4 -18
  172. package/dist/http/owner-access.d.ts +56 -0
  173. package/dist/http/owner-access.js +42 -0
  174. package/dist/http/principal-gate.d.ts +70 -28
  175. package/dist/http/principal-gate.js +61 -15
  176. package/dist/http/readiness.d.ts +11 -5
  177. package/dist/http/readiness.js +10 -3
  178. package/dist/http/refusal-body.d.ts +21 -0
  179. package/dist/http/refusal-body.js +4 -0
  180. package/dist/http/request-guards.d.ts +43 -23
  181. package/dist/http/request-guards.js +53 -17
  182. package/dist/http/resume-ctx-read.d.ts +2 -5
  183. package/dist/http/resume-ctx-read.js +7 -4
  184. package/dist/http/resume-legs.d.ts +28 -4
  185. package/dist/http/resume-legs.js +169 -91
  186. package/dist/http/retired-service-deps.d.ts +43 -0
  187. package/dist/http/retired-service-deps.js +18 -0
  188. package/dist/http/route-ctx.d.ts +44 -28
  189. package/dist/http/route-ctx.js +4 -0
  190. package/dist/http/route-table.js +2 -0
  191. package/dist/http/routes/a2a-serve.js +3 -4
  192. package/dist/http/routes/admin-config-refresh.js +1 -1
  193. package/dist/http/routes/admin-drain.js +1 -1
  194. package/dist/http/routes/admin-memory-optout.js +5 -1
  195. package/dist/http/routes/adoption.js +2 -9
  196. package/dist/http/routes/approvals-assistant.js +49 -48
  197. package/dist/http/routes/background.js +3 -2
  198. package/dist/http/routes/capabilities.js +21 -5
  199. package/dist/http/routes/config-catalog.d.ts +3 -3
  200. package/dist/http/routes/config-catalog.js +1 -1
  201. package/dist/http/routes/devices.js +3 -17
  202. package/dist/http/routes/diagnostics.js +6 -2
  203. package/dist/http/routes/images.js +6 -7
  204. package/dist/http/routes/leader.js +1 -8
  205. package/dist/http/routes/mcp-reconnect.d.ts +1 -1
  206. package/dist/http/routes/mcp-reconnect.js +3 -2
  207. package/dist/http/routes/memory-bundle.js +1 -1
  208. package/dist/http/routes/memory-compliance.js +1 -1
  209. package/dist/http/routes/memory-consolidation.js +1 -1
  210. package/dist/http/routes/memory-origin.js +1 -1
  211. package/dist/http/routes/memory-policy.d.ts +1 -1
  212. package/dist/http/routes/memory-policy.js +3 -2
  213. package/dist/http/routes/notify-wake.js +8 -21
  214. package/dist/http/routes/observability.js +2 -2
  215. package/dist/http/routes/principal-inbox.d.ts +39 -0
  216. package/dist/http/routes/principal-inbox.js +76 -0
  217. package/dist/http/routes/retention-ops.js +2 -9
  218. package/dist/http/routes/rules.js +5 -18
  219. package/dist/http/routes/runs.d.ts +5 -0
  220. package/dist/http/routes/runs.js +34 -107
  221. package/dist/http/routes/session-sync.js +15 -26
  222. package/dist/http/routes/sessions.js +30 -40
  223. package/dist/http/routes/shared-memory.js +2 -13
  224. package/dist/http/routes/side-query.js +8 -7
  225. package/dist/http/routes/tasks.js +67 -21
  226. package/dist/http/routes/workflows.d.ts +351 -0
  227. package/dist/http/routes/workflows.js +153 -119
  228. package/dist/http/send.d.ts +33 -10
  229. package/dist/http/send.js +21 -4
  230. package/dist/http/server.d.ts +27 -18
  231. package/dist/http/server.js +34 -6
  232. package/dist/http/stored-body-replay.js +17 -4
  233. package/dist/http/submit-ctx.d.ts +25 -0
  234. package/dist/http/submit-ctx.js +40 -0
  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 +11 -8
  238. package/dist/index.d.ts +2 -2
  239. package/dist/index.js +1 -2
  240. package/dist/lane-home-probe.d.ts +112 -0
  241. package/dist/lane-home-probe.js +101 -0
  242. package/dist/leader/endpoint.d.ts +4 -1
  243. package/dist/leader/endpoint.js +11 -10
  244. package/dist/limit-refusal.d.ts +59 -0
  245. package/dist/limit-refusal.js +15 -0
  246. package/dist/main.js +1 -1
  247. package/dist/mcp-assertion-header.d.ts +32 -19
  248. package/dist/mcp-assertion-header.js +10 -9
  249. package/dist/mcp-tool-faces.d.ts +5 -0
  250. package/dist/mcp-tool-faces.js +6 -4
  251. package/dist/memory-project-layer.d.ts +37 -0
  252. package/dist/memory-project-layer.js +46 -0
  253. package/dist/memory-scope.d.ts +24 -17
  254. package/dist/memory-scope.js +24 -8
  255. package/dist/memory-sync-client.d.ts +27 -13
  256. package/dist/memory-sync-client.js +107 -18
  257. package/dist/model-entry-refusal.d.ts +9 -1
  258. package/dist/model-entry-refusal.js +6 -1
  259. package/dist/model-plane-face.d.ts +51 -0
  260. package/dist/model-plane-face.js +24 -0
  261. package/dist/model-provider.d.ts +44 -12
  262. package/dist/model-provider.js +21 -2
  263. package/dist/model-route-endpoint.d.ts +9 -12
  264. package/dist/model-route-endpoint.js +8 -11
  265. package/dist/model-route-env.d.ts +22 -0
  266. package/dist/model-route-env.js +2 -0
  267. package/dist/model-route-gap.d.ts +60 -30
  268. package/dist/model-route-gap.js +21 -15
  269. package/dist/observability/corrupt-read-seat.d.ts +7 -0
  270. package/dist/observability/corrupt-read-seat.js +9 -0
  271. package/dist/observability/cost-taxonomy.d.ts +7 -7
  272. package/dist/observability/err-text.d.ts +6 -0
  273. package/dist/observability/err-text.js +18 -4
  274. package/dist/observability/fail-open.d.ts +76 -14
  275. package/dist/observability/fail-open.js +76 -14
  276. package/dist/observability/metrics.js +4 -1
  277. package/dist/observability/prompt-manifest.d.ts +33 -82
  278. package/dist/observability/prompt-manifest.js +122 -17
  279. package/dist/observability/run-terminal.js +14 -6
  280. package/dist/observability/secret-env-scrub.d.ts +13 -1
  281. package/dist/observability/secret-env-scrub.js +13 -1
  282. package/dist/observability/tool-trace.d.ts +16 -21
  283. package/dist/observability/tool-trace.js +58 -49
  284. package/dist/operator-ask.d.ts +10 -0
  285. package/dist/operator-ask.js +3 -0
  286. package/dist/orchestration/workflow-agent-session-index.d.ts +12 -12
  287. package/dist/orchestration/workflow-agent-session-index.js +9 -13
  288. package/dist/orchestration/workflow-completion-inbox.d.ts +42 -15
  289. package/dist/orchestration/workflow-completion-inbox.js +13 -0
  290. package/dist/orchestration/workflow-notify-journal.d.ts +13 -32
  291. package/dist/orchestration/workflow-notify-journal.js +27 -34
  292. package/dist/orchestration/workflow-park-decision.d.ts +89 -0
  293. package/dist/orchestration/workflow-park-decision.js +118 -0
  294. package/dist/org-delivery-gate.d.ts +81 -0
  295. package/dist/org-delivery-gate.js +59 -0
  296. package/dist/panel-tool-names.d.ts +23 -0
  297. package/dist/panel-tool-names.js +8 -0
  298. package/dist/parked-decide.d.ts +39 -6
  299. package/dist/parked-decide.js +98 -51
  300. package/dist/parked-revive-surface.d.ts +9 -2
  301. package/dist/parked-revive-surface.js +11 -8
  302. package/dist/per-task-image.d.ts +7 -1
  303. package/dist/per-task-image.js +3 -3
  304. package/dist/permission-rule-list.d.ts +1 -1
  305. package/dist/permission-rule-list.js +2 -2
  306. package/dist/plain-string-record.d.ts +25 -0
  307. package/dist/plain-string-record.js +32 -0
  308. package/dist/plugins/approval-ask-store-file.d.ts +16 -1
  309. package/dist/plugins/approval-ask-store-file.js +21 -0
  310. package/dist/plugins/approval-ask-store-memory.d.ts +18 -1
  311. package/dist/plugins/approval-ask-store-memory.js +34 -2
  312. package/dist/plugins/approval-ask-store-sql.d.ts +25 -0
  313. package/dist/plugins/approval-ask-store-sql.js +37 -1
  314. package/dist/plugins/blob-backend.d.ts +83 -15
  315. package/dist/plugins/blob-backend.js +68 -15
  316. package/dist/plugins/breaker-state-sql.d.ts +2 -2
  317. package/dist/plugins/breaker-state-sql.js +4 -4
  318. package/dist/plugins/caching-session-store.d.ts +3 -0
  319. package/dist/plugins/caching-session-store.js +3 -0
  320. package/dist/plugins/checkpoint-store-sql.d.ts +28 -4
  321. package/dist/plugins/checkpoint-store-sql.js +59 -28
  322. package/dist/plugins/file-history-store-sql.d.ts +5 -2
  323. package/dist/plugins/file-history-store-sql.js +3 -1
  324. package/dist/plugins/file-run-store.d.ts +5 -13
  325. package/dist/plugins/file-run-store.js +9 -0
  326. package/dist/plugins/fork-routing-session-store.d.ts +9 -1
  327. package/dist/plugins/fork-routing-session-store.js +12 -1
  328. package/dist/plugins/host-platform.d.ts +2 -0
  329. package/dist/plugins/host-platform.js +2 -1
  330. package/dist/plugins/k8s-bg-scripts.d.ts +11 -0
  331. package/dist/plugins/k8s-bg-scripts.js +22 -0
  332. package/dist/plugins/local-checkpoint-store.d.ts +2 -0
  333. package/dist/plugins/local-checkpoint-store.js +11 -3
  334. package/dist/plugins/local-session-store.d.ts +1 -1
  335. package/dist/plugins/local-session-store.js +1 -1
  336. package/dist/plugins/local-session-window.d.ts +39 -0
  337. package/dist/plugins/local-session-window.js +54 -0
  338. package/dist/plugins/mailbox-recipient-lifecycle.d.ts +3 -2
  339. package/dist/plugins/mailbox-store-sql.d.ts +30 -48
  340. package/dist/plugins/mailbox-store-sql.js +77 -52
  341. package/dist/plugins/memory-embedder-fingerprint.js +2 -1
  342. package/dist/plugins/memory-run-store.d.ts +5 -13
  343. package/dist/plugins/memory-run-store.js +8 -0
  344. package/dist/plugins/one-time-migrations.d.ts +245 -93
  345. package/dist/plugins/one-time-migrations.js +668 -207
  346. package/dist/plugins/org-delivery-quota-store.d.ts +123 -0
  347. package/dist/plugins/org-delivery-quota-store.js +228 -0
  348. package/dist/plugins/permission-rule-store-sql.d.ts +13 -7
  349. package/dist/plugins/permission-rule-store-sql.js +4 -18
  350. package/dist/plugins/pg-pool.js +39 -7
  351. package/dist/plugins/pg-session-storage.d.ts +20 -8
  352. package/dist/plugins/pg-session-storage.js +34 -21
  353. package/dist/plugins/remote-env-adb.d.ts +12 -12
  354. package/dist/plugins/remote-env-adb.js +21 -6
  355. package/dist/plugins/remote-env-device.js +3 -0
  356. package/dist/plugins/remote-env-e2b.d.ts +1 -1
  357. package/dist/plugins/remote-env-e2b.js +21 -9
  358. package/dist/plugins/remote-env-host.d.ts +9 -9
  359. package/dist/plugins/remote-env-host.js +10 -32
  360. package/dist/plugins/remote-env-k8s.d.ts +103 -38
  361. package/dist/plugins/remote-env-k8s.js +288 -95
  362. package/dist/plugins/remote-env-local-docker.d.ts +27 -13
  363. package/dist/plugins/remote-env-local-docker.js +82 -11
  364. package/dist/plugins/remote-env-ssh.d.ts +21 -12
  365. package/dist/plugins/remote-env-ssh.js +117 -5
  366. package/dist/plugins/remote-shell.d.ts +0 -1
  367. package/dist/plugins/remote-shell.js +1 -2
  368. package/dist/plugins/retention-store-sql.js +6 -2
  369. package/dist/plugins/run-store-sql.d.ts +16 -14
  370. package/dist/plugins/run-store-sql.js +22 -2
  371. package/dist/plugins/schema-consistency.d.ts +54 -0
  372. package/dist/plugins/schema-consistency.js +52 -0
  373. package/dist/plugins/schema-indexes.js +2 -0
  374. package/dist/plugins/send-user-file.js +2 -2
  375. package/dist/plugins/session-epoch-anchor.d.ts +39 -0
  376. package/dist/plugins/session-epoch-anchor.js +22 -0
  377. package/dist/plugins/session-store.d.ts +18 -8
  378. package/dist/plugins/session-store.js +15 -4
  379. package/dist/plugins/shared-memory-store-sql.d.ts +9 -3
  380. package/dist/plugins/shared-memory-store-sql.js +5 -16
  381. package/dist/plugins/sql-driver.d.ts +205 -1
  382. package/dist/plugins/sql-driver.js +325 -13
  383. package/dist/plugins/sql-errors.d.ts +64 -0
  384. package/dist/plugins/sql-errors.js +57 -0
  385. package/dist/plugins/store-backend.d.ts +36 -1
  386. package/dist/plugins/store-backend.js +42 -15
  387. package/dist/plugins/store-contracts.d.ts +42 -0
  388. package/dist/plugins/store-contracts.js +1 -0
  389. package/dist/plugins/tidb-pool.d.ts +6 -1
  390. package/dist/plugins/tidb-pool.js +44 -10
  391. package/dist/plugins/tidb-session-storage.d.ts +8 -11
  392. package/dist/plugins/tidb-session-storage.js +6 -16
  393. package/dist/plugins/tidb-session-store.d.ts +24 -4
  394. package/dist/plugins/tidb-session-store.js +29 -5
  395. package/dist/plugins/workflow-journal-store-sql.d.ts +73 -19
  396. package/dist/plugins/workflow-journal-store-sql.js +19 -6
  397. package/dist/plugins/workflow-run-store-sql.d.ts +30 -8
  398. package/dist/plugins/workflow-run-store-sql.js +50 -9
  399. package/dist/posture-source.d.ts +18 -10
  400. package/dist/posture-source.js +4 -1
  401. package/dist/project-identity.d.ts +45 -6
  402. package/dist/project-identity.js +162 -8
  403. package/dist/project-layer-key.d.ts +28 -0
  404. package/dist/project-layer-key.js +29 -0
  405. package/dist/prompts-domain-validate.d.ts +17 -61
  406. package/dist/prompts-domain-validate.js +9 -119
  407. package/dist/question.js +3 -2
  408. package/dist/read-deny-entry.d.ts +25 -0
  409. package/dist/read-deny-entry.js +12 -0
  410. package/dist/read-face-posture.d.ts +37 -11
  411. package/dist/read-face-posture.js +32 -3
  412. package/dist/request-key-closure.d.ts +9 -2
  413. package/dist/request-key-closure.js +11 -5
  414. package/dist/request-value-closure.d.ts +5 -0
  415. package/dist/request-value-closure.js +11 -3
  416. package/dist/rule-entry-list.d.ts +38 -11
  417. package/dist/rule-entry-list.js +106 -30
  418. package/dist/rules-consent.js +3 -4
  419. package/dist/run-acceptance.d.ts +19 -3
  420. package/dist/run-acceptance.js +13 -1
  421. package/dist/run-local.js +54 -24
  422. package/dist/runs.d.ts +15 -8
  423. package/dist/runs.js +35 -1
  424. package/dist/runtime-caps-resolver.d.ts +16 -6
  425. package/dist/runtime-caps-resolver.js +18 -5
  426. package/dist/sandbox-pkg-source.d.ts +19 -1
  427. package/dist/sandbox-pkg-source.js +29 -7
  428. package/dist/security.d.ts +87 -9
  429. package/dist/security.js +52 -9
  430. package/dist/server-secret-env.d.ts +44 -18
  431. package/dist/server-secret-env.js +49 -8
  432. package/dist/session-error-wire.d.ts +19 -2
  433. package/dist/session-error-wire.js +5 -1
  434. package/dist/session-incarnation.d.ts +15 -5
  435. package/dist/session-incarnation.js +16 -9
  436. package/dist/session-titled-frame.d.ts +33 -0
  437. package/dist/session-titled-frame.js +4 -0
  438. package/dist/session-titler.d.ts +9 -1
  439. package/dist/session-titler.js +27 -6
  440. package/dist/spec-fields.d.ts +28 -16
  441. package/dist/spec-fields.js +66 -54
  442. package/dist/sql-engine-posture.d.ts +31 -4
  443. package/dist/sql-engine-posture.js +36 -1
  444. package/dist/stored-request-tool-axes-m19.d.ts +19 -4
  445. package/dist/stored-request-tool-axes-m19.js +30 -2
  446. package/dist/task-a2a.d.ts +9 -1
  447. package/dist/task-a2a.js +73 -47
  448. package/dist/task-cwd.d.ts +1 -1
  449. package/dist/task-mcp.d.ts +46 -58
  450. package/dist/task-mcp.js +82 -107
  451. package/dist/task-settings.d.ts +95 -108
  452. package/dist/task-settings.js +77 -98
  453. package/dist/text-bidi.d.ts +1 -48
  454. package/dist/text-bidi.js +3 -5
  455. package/dist/tighten-only-seats.d.ts +150 -0
  456. package/dist/tighten-only-seats.js +196 -0
  457. package/dist/tool-approval.d.ts +304 -88
  458. package/dist/tool-approval.js +623 -239
  459. package/dist/trace/core-keyset-guard.d.ts +122 -20
  460. package/dist/trace/engine-notice-wire.d.ts +11 -3
  461. package/dist/trace/engine-notice-wire.js +8 -1
  462. package/dist/trace/exit-seat.d.ts +28 -0
  463. package/dist/trace/exit-seat.js +76 -0
  464. package/dist/trace/ledger-events.d.ts +6 -3
  465. package/dist/trace/ledger-sink.js +4 -1
  466. package/dist/trace/model-segment.js +1 -1
  467. package/dist/trace/project.d.ts +98 -17
  468. package/dist/trace/project.js +98 -50
  469. package/dist/trace/projection-table.d.ts +100 -0
  470. package/dist/trace/projection-table.js +130 -0
  471. package/dist/trace/redact.d.ts +54 -0
  472. package/dist/trace/redact.js +778 -152
  473. package/dist/trace/self-minted-wire.d.ts +345 -1
  474. package/dist/trace/self-minted-wire.js +117 -1
  475. package/dist/trace/wire-projection-faces.d.ts +377 -3
  476. package/dist/trace/wire-projection-faces.js +164 -1
  477. package/dist/url-refusal.js +2 -0
  478. package/dist/web-admin-client/apply-effective.d.ts +12 -0
  479. package/dist/web-admin-client/apply-effective.js +56 -5
  480. package/dist/web-admin-client/candidate-gate.d.ts +6 -6
  481. package/dist/web-admin-client/candidate-gate.js +3 -3
  482. package/dist/web-admin-client/facade.d.ts +1 -1
  483. package/dist/web-admin-client/facade.js +1 -1
  484. package/dist/web-admin-client/http-client.js +0 -6
  485. package/dist/web-admin-client/read-face.js +5 -9
  486. package/dist/web-admin-client/read-warnings.d.ts +13 -0
  487. package/dist/web-admin-client/read-warnings.js +10 -0
  488. package/dist/web-admin-client/skills-mcp.d.ts +3 -0
  489. package/dist/web-admin-client/skills-mcp.js +11 -9
  490. package/dist/web-admin-client/types.d.ts +2 -3
  491. package/dist/workspace-cache.d.ts +35 -0
  492. package/dist/workspace-cache.js +36 -0
  493. package/dist/workspace-space.d.ts +3 -2
  494. package/dist/workspace-space.js +2 -0
  495. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +65 -10
  496. package/package.json +8 -4
  497. package/scripts/drain-check-local.mjs +34 -1
  498. package/scripts/drain-check.mysql.sql +30 -2
  499. package/scripts/drain-check.pg.sql +29 -2
  500. package/dist/capabilities/memory-notice.d.ts +0 -138
  501. package/dist/capabilities/memory-notice.js +0 -64
  502. package/dist/capabilities/prompt.d.ts +0 -17
  503. package/dist/capabilities/prompt.js +0 -6
  504. package/dist/mcp-content-origin.d.ts +0 -34
  505. package/dist/mcp-content-origin.js +0 -10
  506. package/dist/tool-axis-words.d.ts +0 -27
  507. package/dist/tool-axis-words.js +0 -9
  508. package/dist/wire-name-bound.d.ts +0 -14
  509. package/dist/wire-name-bound.js +0 -13
@@ -1,15 +1,17 @@
1
1
  import { redactHead } from "../observability/run-terminal.js";
2
+ const errText = (e) => redactHead(e instanceof Error ? e.message : String(e), 2000);
2
3
  import { findParkOrigin } from "../parked-decide.js";
3
4
  import { decodeCheckpointScope } from "../security.js";
4
5
  import { hostDecisionFacts } from "../host-decision.js";
5
6
  import { APPROVAL_GATE_KINDS } from "../tool-approval.js";
6
7
  import { createWallClockJumpGuard } from "../wall-clock-jump-guard.js";
7
- import { hasServiceAuth } from "./dispatch.js";
8
- import { gatedPrincipal } from "./principal-gate.js";
8
+ import { gatedPrincipal, hasServiceAuth } from "./principal-gate.js";
9
9
  import { costQuotaRefusalOf } from "./request-guards.js";
10
10
  import { admissionRefusalOf, readinessOf } from "./readiness.js";
11
11
  import { readResumeCtx } from "./resume-ctx-read.js";
12
+ import { isResumeBlockedByPolicy } from "./checkpoint-ctx.js";
12
13
  import { storedBodyReplayRefusal } from "./stored-body-replay.js";
14
+ import { refusalBody } from "./refusal-body.js";
13
15
  const BLOCKED_SCALAR_KEYS = ["errorCode", "blockedBy", "field", "reason", "count", "cap", "index"];
14
16
  function blockedScalars(body) {
15
17
  const out = {};
@@ -22,8 +24,27 @@ function blockedScalars(body) {
22
24
  }
23
25
  return out;
24
26
  }
27
+ const BLOCKED_WARNED_MAX = 1024;
25
28
  export function createApprovalSweeps(ctx) {
26
29
  const { deps, resumeCheckpoint, mayDiscloseRowError } = ctx;
30
+ const blockedWarned = new Map();
31
+ const noteResumeBlocked = (cardToken, sessionId, status, body) => {
32
+ deps.metrics?.inc("deny_sweep_resume_blocked_total");
33
+ const fields = { status, ...blockedScalars(body) };
34
+ if (cardToken !== undefined) {
35
+ const fingerprint = JSON.stringify(fields);
36
+ if (blockedWarned.get(cardToken) === fingerprint)
37
+ return;
38
+ blockedWarned.delete(cardToken);
39
+ if (blockedWarned.size >= BLOCKED_WARNED_MAX) {
40
+ const oldest = blockedWarned.keys().next();
41
+ if (oldest.done !== true)
42
+ blockedWarned.delete(oldest.value);
43
+ }
44
+ blockedWarned.set(cardToken, fingerprint);
45
+ }
46
+ deps.logger?.warn?.("deny_sweep_resume_blocked", { sessionId, ...fields });
47
+ };
27
48
  const denySweepClockGuard = createWallClockJumpGuard({
28
49
  slaMs: deps.config.approvalTimeoutSec > 0 ? deps.config.approvalTimeoutSec * 1000 : undefined,
29
50
  onJump: ({ jumpMs, graceMs }) => deps.logger?.warn?.("deny_sweep_wall_clock_jump", {
@@ -45,26 +66,41 @@ export function createApprovalSweeps(ctx) {
45
66
  return;
46
67
  if (!denySweepClockGuard.admit(now))
47
68
  return;
48
- const expired = await cs.listExpiredApprovalGates(now).catch(() => []);
49
- const isParkedOwned = async (sessionId) => {
50
- if (deps.backgroundAgentStore === undefined && deps.workflowAgentSessionIndex === undefined)
51
- return false;
69
+ let expired;
70
+ try {
71
+ expired = await cs.listExpiredApprovalGates(now);
72
+ }
73
+ catch (e) {
74
+ deps.metrics?.inc("deny_sweep_list_failed_total");
75
+ deps.logger?.warn?.("deny_sweep_list_failed", {
76
+ err: errText(e),
77
+ note: "the SLA deny-sweep could not read the expired approvals this tick, so nothing was denied and nothing was skipped; the rows stay suspended and are read again next tick (the terminal backstop still reaps them)",
78
+ });
79
+ return;
80
+ }
81
+ const parkSources = deps.backgroundAgentStore !== undefined || deps.workflowAgentSessionIndex !== undefined;
82
+ const cardOf = async (sessionId) => {
83
+ let token;
52
84
  try {
53
- const token = await cs.findPendingTokenBySession(sessionId, undefined, { gateKinds: APPROVAL_GATE_KINDS });
85
+ token = (await cs.findPendingTokenBySession(sessionId, undefined, { gateKinds: APPROVAL_GATE_KINDS })) ?? undefined;
54
86
  if (!token)
55
- return false;
87
+ return { token, parked: false, rev: undefined };
56
88
  const cp = await cs.get(token);
57
89
  if (!cp)
58
- return false;
59
- return (await findParkOrigin({
90
+ return { token, parked: false, rev: undefined };
91
+ const rev = cp.rev ?? 0;
92
+ if (!parkSources)
93
+ return { token, parked: false, rev };
94
+ const origin = await findParkOrigin({
60
95
  ...(deps.backgroundAgentStore !== undefined ? { agentStore: deps.backgroundAgentStore } : {}),
61
96
  ...(deps.workflowAgentSessionIndex !== undefined && deps.workflowRunStore !== undefined
62
97
  ? { workflowIndex: deps.workflowAgentSessionIndex, workflowRunStore: deps.workflowRunStore }
63
98
  : {}),
64
- }, { token, scope: cp.scope, sessionId: cp.sessionId })) !== undefined;
99
+ }, { token, scope: cp.scope, sessionId: cp.sessionId });
100
+ return { token, parked: origin !== undefined, rev };
65
101
  }
66
102
  catch {
67
- return false;
103
+ return { token, parked: false, rev: undefined };
68
104
  }
69
105
  };
70
106
  const storedBodyUnservable = async (sessionId) => {
@@ -75,10 +111,35 @@ export function createApprovalSweeps(ctx) {
75
111
  return undefined;
76
112
  return storedBodyReplayRefusal(read.ctx, deps.config);
77
113
  };
114
+ const expirePolicyBlockedCard = async (cardToken, observedRev, sessionId, body) => {
115
+ let won;
116
+ try {
117
+ const cp = await cs.get(cardToken);
118
+ if (!cp)
119
+ return;
120
+ if (cp.status !== "pending" || (cp.rev ?? 0) !== observedRev) {
121
+ deps.logger?.warn?.("deny_sweep_policy_blocked_expire_skipped", { sessionId, skipReason: cp.status !== "pending" ? "not_pending" : "card_changed", ...blockedScalars(body) });
122
+ return;
123
+ }
124
+ won = await cs.expire(cardToken, cp.scope);
125
+ }
126
+ catch (e) {
127
+ deps.logger?.warn?.("deny_sweep_policy_blocked_expire_failed", { sessionId, err: errText(e) });
128
+ return;
129
+ }
130
+ blockedWarned.delete(cardToken);
131
+ if (won)
132
+ deps.metrics?.inc("deny_sweep_policy_blocked_expired_total");
133
+ deps.logger?.warn?.("deny_sweep_policy_blocked_expired", { sessionId, won, ...blockedScalars(body) });
134
+ };
78
135
  let parkedSkipped = 0;
79
136
  const replaySkipped = [];
137
+ const seenCards = new Set();
80
138
  for (const { sessionId } of expired) {
81
- if (await isParkedOwned(sessionId)) {
139
+ const { token: cardToken, parked, rev: cardRev } = await cardOf(sessionId);
140
+ if (cardToken !== undefined)
141
+ seenCards.add(cardToken);
142
+ if (parked) {
82
143
  parkedSkipped += 1;
83
144
  continue;
84
145
  }
@@ -87,9 +148,26 @@ export function createApprovalSweeps(ctx) {
87
148
  replaySkipped.push({ sessionId, kind: unservable.kind });
88
149
  continue;
89
150
  }
90
- await resumeCheckpoint(sessionId, "deny", "approval SLA expired — auto-denied", { decidedBy: "sla_timeout" }).then((r) => { if (r.status >= 400)
91
- deps.logger?.warn?.("deny_sweep_resume_blocked", { sessionId, status: r.status, ...blockedScalars(r.body) }); }, (e) => deps.logger?.warn?.("deny_sweep_resume_failed", { sessionId, err: redactHead(e instanceof Error ? e.message : String(e), 2000) }));
151
+ let out;
152
+ try {
153
+ out = await resumeCheckpoint(sessionId, "deny", "approval SLA expired — auto-denied", { decidedBy: "sla_timeout" });
154
+ }
155
+ catch (e) {
156
+ deps.logger?.warn?.("deny_sweep_resume_failed", { sessionId, err: errText(e) });
157
+ continue;
158
+ }
159
+ if (out.status < 400) {
160
+ if (cardToken !== undefined)
161
+ blockedWarned.delete(cardToken);
162
+ continue;
163
+ }
164
+ noteResumeBlocked(cardToken, sessionId, out.status, out.body);
165
+ if (isResumeBlockedByPolicy(out) && cardToken !== undefined && cardRev !== undefined)
166
+ await expirePolicyBlockedCard(cardToken, cardRev, sessionId, out.body);
92
167
  }
168
+ for (const token of [...blockedWarned.keys()])
169
+ if (!seenCards.has(token))
170
+ blockedWarned.delete(token);
93
171
  if (parkedSkipped > 0)
94
172
  deps.logger?.info?.("deny_sweep_parked_skipped", { count: parkedSkipped });
95
173
  if (replaySkipped.length > 0) {
@@ -103,10 +181,10 @@ export function createApprovalSweeps(ctx) {
103
181
  async function redeemParkedAsk(req) {
104
182
  const cs = deps.checkpointStore;
105
183
  if (!cs) {
106
- return { status: 404, body: { error: "approval not found", errorCode: "not_found.approval" } };
184
+ return { status: 404, body: refusalBody({ errorCode: "not_found.approval", message: "approval not found" }) };
107
185
  }
108
186
  if (!hasServiceAuth(deps.config) && !deps.config.allowUnauthedWrites) {
109
- return { status: 503, body: { error: "this worker requires a service auth token (set SERVICE_AUTH_TOKEN) before accepting task submissions", errorCode: "auth.service_token_required" } };
187
+ return { status: 503, body: refusalBody({ errorCode: "auth.service_token_required", message: "this worker requires a service auth token (set SERVICE_AUTH_TOKEN) before accepting task submissions" }) };
110
188
  }
111
189
  const refusal = admissionRefusalOf(readinessOf(deps), deps.servingLease?.(), "hitl-answer");
112
190
  if (refusal !== undefined)
@@ -128,17 +206,17 @@ export function createApprovalSweeps(ctx) {
128
206
  catch (e) {
129
207
  if (!(await mayDiscloseRowError(cs, req.gateToken, { principal: req.principal, explicitOperator: false }))) {
130
208
  deps.logger?.warn?.("parked_late_decision_unreadable_row_withheld", { askId: req.askId });
131
- return { status: 404, body: { error: "approval not found", errorCode: "not_found.approval" } };
209
+ return { status: 404, body: refusalBody({ errorCode: "not_found.approval", message: "approval not found" }) };
132
210
  }
133
- return { status: 409, body: { error: e instanceof Error ? e.message : String(e), errorCode: "conflict.checkpoint_unreadable" } };
211
+ return { status: 409, body: refusalBody({ errorCode: "conflict.checkpoint_unreadable", message: e instanceof Error ? e.message : String(e) }) };
134
212
  }
135
213
  if (!cp) {
136
- return { status: 404, body: { error: "approval not found", errorCode: "not_found.approval" } };
214
+ return { status: 404, body: refusalBody({ errorCode: "not_found.approval", message: "approval not found" }) };
137
215
  }
138
216
  const cpPrincipal = decodeCheckpointScope(cp.scope);
139
217
  if (cpPrincipal !== undefined && cpPrincipal !== req.principal) {
140
218
  deps.logger?.warn?.("parked_late_decision_scope_mismatch", { askId: req.askId });
141
- return { status: 404, body: { error: "approval not found", errorCode: "not_found.approval" } };
219
+ return { status: 404, body: refusalBody({ errorCode: "not_found.approval", message: "approval not found" }) };
142
220
  }
143
221
  const binding = {
144
222
  checkpointToken: req.gateToken,
@@ -0,0 +1,77 @@
1
+ /**
2
+ * **调用方信任档** —— 一份请求里「不经人答就生效」的规则表按谁的档准入:全仓唯一一张表({@link callerTrust})、唯一一只准入判({@link requestTrustRefusal})。
3
+ *
4
+ * ## 律
5
+ * 契约(settings-schema `SAFETY_MERGE_SPEC.permissions` 的成员阶梯)按**层的信任档**准入每个成员:`allow` 放宽免问面(`loosen`),要 `global`;`deny` / `ask` 只收紧,
6
+ * 文件层最低档 `local` 就收。wire 上没有层 —— 提交体是合并后的扁平结果,层只在合并端(cli 本地)存在;自报一个层 / 作者位不可验(引擎侧已拒立这种位)。所以本服务
7
+ * 的「层」= **这次请求验过的凭据**:档只由部署形 + 身份来源 + 登录令牌的 scope 角色推,调用方说什么都不改档。
8
+ *
9
+ * · 单用户 turnkey(`requirePrincipal !== true`,本仓 posture 判别式同一只)⇒ `global`:一台机一位超管;
10
+ * · 多租 · 部署的 service 凭据 ⇒ `global`:部署自己的凭据是运维档(契约给「启动方自己的行为」—— `SETTINGS_SOURCE_CONTRACT.flagSettings` —— 的档),持它的前端为自己转发的内容负责;
11
+ * 出示的 Bearer 就是 service 凭据时,哪怕它同时也被鉴权桥验成登录令牌,也按 service 凭据读(与凭据门派 `source` 同序:`dispatch.ts` 先认 service 凭据);
12
+ * · 多租 · 中心登录令牌,scope 角色 ≥ 契约 `domainWriteRole("governance")` ⇒ `global`:能写 scope 治理域(autonomy / commandPolicy / approvalRequire,全组织的免问面)
13
+ * 的角色,放宽自己这一 run 是它的子集;门槛读契约,不手抄角色词;
14
+ * · 多租 · 其余(登录令牌角色低于它 / 不带 / 认不出;直连门 principal 令牌只证身份不证角色;没有验过的凭据)⇒ `project`:契约给非运维档作者的仓控来源的档,
15
+ * 收紧成员照收、放宽成员不收 —— 没有可验的角色就落到这里(fail-closed)。
16
+ *
17
+ * **判的是哪些表**:请求体上不经人答就生效的规则表 —— `settings.permissions` 的每个成员桶(逐 `membersOf("permissions")`),以及请求**按名点用**(`userInvokedSkills`)的
18
+ * 自带技能的两只清单(引擎 `seedSkillGrants`:人点的名就是表态,不出 `Skill` 卡 ⇒ `allowedTools` 是 `allow` 成员的孪生、`disallowedTools` 是 `deny` 的孪生,键 → 成员一张表
19
+ * {@link SKILL_LIST_MEMBER})。没点用的自带技能不判:它的清单要经 `Skill` 卡上的人点头才生效 —— 那正是契约给低于门槛的放宽指定的同意出口。
20
+ * 准入只经契约导出:桶非空且 `!isAtLeast(档, memberAdmission(…).minTrust)` ⇒ 不准入;不按方向开特例(契约的层准入同样先判 floor)。
21
+ * 不准入 ⇒ 受理口 400,体与条目问题同形(`entry-problems.ts`:`field` + `detail.problems` + `total`),原因词 = 契约 `LAYER_ADMISSION_VERDICTS` 的 `below_trust_floor`,
22
+ * 另带 `detail.callerTrust`(这次请求的档)。响亮拒而不是静默丢:契约要求低于门槛的放宽不得静默吞,出路是同意(答卡)或运维的 allow 表。
23
+ *
24
+ * 读者(都读同一次求值,不各算一份):提交受理口(`admission.ts` `prepareSpec`,三提交面共用)与能力位 `settings.permissions.callerTrust`(`routes/capabilities.ts`)。
25
+ * 续跑腿不读本档:存储体在自己的受理口按当时的档准入过。
26
+ */
27
+ import type { IncomingMessage } from "node:http";
28
+ import { type MinTrust, type SafetyMergeMember, type UserRole } from "@sema-agent/settings-schema";
29
+ import type { SkillSpec } from "@sema-agent/core";
30
+ import type { ServiceConfig } from "../config-types.js";
31
+ import { type EntryProblem } from "../entry-problems.js";
32
+ import type { ParsedTaskSettings } from "../task-settings.js";
33
+ /**
34
+ * 档是**怎么**推出来的(闭集;拒句按它说出路)。加一个词 ⇒ {@link basisClause} 的穷举 switch 编译红。
35
+ * · `single_user` —— 单用户 turnkey;
36
+ * · `service_credential` —— 多租 · 部署的 service 凭据;
37
+ * · `sign_in_role` —— 多租 · 登录令牌带契约阶梯里的角色(够不够档看 `trust`);
38
+ * · `sign_in_role_unrecognized` —— 多租 · 登录令牌不带角色,或角色不在契约阶梯里;
39
+ * · `identity_without_role` —— 多租 · 直连门 principal 令牌(只证身份);
40
+ * · `unverified` —— 多租 · 没有验过的凭据。
41
+ */
42
+ export type CallerTrustBasis = "single_user" | "service_credential" | "sign_in_role" | "sign_in_role_unrecognized" | "identity_without_role" | "unverified";
43
+ /** 一次求值的读数。`role` 只在 `basis === "sign_in_role"` 时在场(契约阶梯里的词)。 */
44
+ export interface CallerTrust {
45
+ readonly trust: MinTrust;
46
+ readonly basis: CallerTrustBasis;
47
+ readonly role?: UserRole;
48
+ }
49
+ /** 档表(唯一一张)。规则全文见文件头。 */
50
+ export declare function callerTrust(req: IncomingMessage, config: ServiceConfig): CallerTrust;
51
+ /** 请求 `settings.permissions` 的成员桶 —— 按**契约的成员型**取:契约加成员而本仓的请求桶没有它 ⇒ 这里编译红(本仓必须先决定那只桶怎么上 wire)。 */
52
+ type RequestPermissionMembers = Pick<NonNullable<ParsedTaskSettings["permissions"]>, SafetyMergeMember<"permissions">>;
53
+ /** 准入判的输入:解析后的请求桶(`parseTaskSettings` 的读数 = `applyTaskSettings` 投进引擎的那一份)+ 请求自带技能 + 按名点用的技能名(两者受理门已判过形)。 */
54
+ export interface RequestRuleTables {
55
+ readonly permissions: RequestPermissionMembers | undefined;
56
+ readonly skills: readonly Pick<SkillSpec, "name" | "allowedTools" | "disallowedTools">[] | undefined;
57
+ readonly userInvokedSkills: readonly string[] | undefined;
58
+ }
59
+ /** 受理口拒体:句子 + 机读位(原样进 `sendError` 的 facts)。 */
60
+ export interface RequestTrustRefusal {
61
+ readonly message: string;
62
+ readonly facts: {
63
+ readonly field: string;
64
+ readonly detail: {
65
+ readonly problems: readonly EntryProblem[];
66
+ readonly total: number;
67
+ readonly callerTrust: MinTrust;
68
+ };
69
+ };
70
+ }
71
+ /**
72
+ * 请求里不经人答就生效的规则表的成员级准入(唯一一只判)。全部准入 ⇒ `undefined`;否则句子说扫描序里**第一张**不准入的表(坐标、档、floor、出路),
73
+ * 机读位把这一遍判下来的**全部**条目一次列全。空表什么也不改,不算。
74
+ */
75
+ export declare function requestTrustRefusal(tables: RequestRuleTables, reading: CallerTrust): RequestTrustRefusal | undefined;
76
+ export {};
77
+ //# sourceMappingURL=caller-trust.d.ts.map
@@ -0,0 +1,143 @@
1
+ import { domainWriteRole, isAtLeast, isRole, memberAdmission, membersOf, roleAtLeast, USER_ROLES, } from "@sema-agent/settings-schema";
2
+ import { entryProblem, entryProblemsFacts } from "../entry-problems.js";
3
+ import { ssoVerifiedRole } from "../security.js";
4
+ import { systemFor, verifiedIdentitySource } from "./principal-gate.js";
5
+ export function callerTrust(req, config) {
6
+ if (config.requirePrincipal !== true)
7
+ return { trust: "global", basis: "single_user" };
8
+ const source = verifiedIdentitySource(req, config);
9
+ switch (source) {
10
+ case "service_token":
11
+ return { trust: "global", basis: "service_credential" };
12
+ case "sso": {
13
+ if (systemFor(req, config) !== undefined)
14
+ return { trust: "global", basis: "service_credential" };
15
+ const role = ssoVerifiedRole(req);
16
+ if (role === undefined || !isRole(role))
17
+ return { trust: "project", basis: "sign_in_role_unrecognized" };
18
+ return { trust: roleAtLeast(role, domainWriteRole("governance")) ? "global" : "project", basis: "sign_in_role", role };
19
+ }
20
+ case "direct_door_jwt":
21
+ return { trust: "project", basis: "identity_without_role" };
22
+ case undefined:
23
+ return { trust: "project", basis: "unverified" };
24
+ default: {
25
+ const unknownSource = source;
26
+ throw new Error(`callerTrust: identity source ${String(unknownSource)} has no trust row`);
27
+ }
28
+ }
29
+ }
30
+ const TRUST_REFUSAL_CODE = "request.field_invalid";
31
+ const BELOW_TRUST_FLOOR = "below_trust_floor";
32
+ const SKILL_LIST_MEMBER = { allowedTools: "allow", disallowedTools: "deny" };
33
+ function effectiveRuleTables(t) {
34
+ const out = [];
35
+ if (t.permissions !== undefined) {
36
+ for (const member of membersOf("permissions")) {
37
+ const entries = t.permissions[member];
38
+ if (entries !== undefined)
39
+ out.push({ member, field: `settings.permissions.${member}`, entries, source: "settings" });
40
+ }
41
+ }
42
+ if (t.skills !== undefined && t.userInvokedSkills !== undefined) {
43
+ const named = new Set();
44
+ for (const name of t.userInvokedSkills) {
45
+ if (named.has(name))
46
+ continue;
47
+ named.add(name);
48
+ const at = t.skills.findIndex((skill) => skill.name === name);
49
+ const skill = t.skills[at];
50
+ if (skill === undefined)
51
+ continue;
52
+ for (const key of ["allowedTools", "disallowedTools"]) {
53
+ const entries = skill[key];
54
+ if (entries !== undefined)
55
+ out.push({ member: SKILL_LIST_MEMBER[key], field: `skills[${at}].${key}`, entries, source: "invoked_skill" });
56
+ }
57
+ }
58
+ }
59
+ return out;
60
+ }
61
+ export function requestTrustRefusal(tables, reading) {
62
+ const problems = [];
63
+ let first;
64
+ for (const table of effectiveRuleTables(tables)) {
65
+ if (table.entries.length === 0)
66
+ continue;
67
+ const admission = memberAdmission("permissions", table.member);
68
+ if (isAtLeast(reading.trust, admission.minTrust))
69
+ continue;
70
+ first ??= { table, minTrust: admission.minTrust, loosens: directionLoosens(admission.direction) };
71
+ for (const entry of table.entries)
72
+ problems.push(entryProblem(TRUST_REFUSAL_CODE, table.field, entry, BELOW_TRUST_FLOOR));
73
+ }
74
+ if (first === undefined)
75
+ return undefined;
76
+ const facts = entryProblemsFacts(problems);
77
+ return {
78
+ message: `${first.table.field} needs trust "${first.minTrust}" (${whatItDoes(first.table.source, first.loosens)}) and this request is admitted at "${reading.trust}": ${basisClause(reading)}. Below that trust these rules are not applied — ${outletOf(first.table.source, first.loosens)}.`,
79
+ facts: { field: facts.field, detail: { ...facts.detail, callerTrust: reading.trust } },
80
+ };
81
+ }
82
+ function whatItDoes(source, loosens) {
83
+ const effect = loosens ? "lets matching calls run without a person being asked" : "changes which calls are asked or refused";
84
+ switch (source) {
85
+ case "settings":
86
+ return `it ${effect}`;
87
+ case "invoked_skill":
88
+ return `the request invokes this skill by name, so the list applies with no approval card and ${effect}`;
89
+ default: {
90
+ const unknownSource = source;
91
+ throw new Error(`requestTrustRefusal: rule table source ${String(unknownSource)} unknown`);
92
+ }
93
+ }
94
+ }
95
+ function outletOf(source, loosens) {
96
+ if (!loosens)
97
+ return "remove them, or ask the operator to set them deployment-wide";
98
+ switch (source) {
99
+ case "settings":
100
+ return "remove them and answer the approval questions as they come, or ask the operator to put them in APPROVAL_GRANT";
101
+ case "invoked_skill":
102
+ return "drop the skill from userInvokedSkills (the model can still activate it behind its approval card), remove the list, or ask the operator to put the rules in APPROVAL_GRANT";
103
+ default: {
104
+ const unknownSource = source;
105
+ throw new Error(`requestTrustRefusal: rule table source ${String(unknownSource)} unknown`);
106
+ }
107
+ }
108
+ }
109
+ function directionLoosens(direction) {
110
+ switch (direction) {
111
+ case "loosen":
112
+ return true;
113
+ case "tighten":
114
+ return false;
115
+ default: {
116
+ const unknownDirection = direction;
117
+ throw new Error(`requestTrustRefusal: member direction ${String(unknownDirection)} unknown`);
118
+ }
119
+ }
120
+ }
121
+ function basisClause(reading) {
122
+ const governanceRole = domainWriteRole("governance");
123
+ const reach = `the deployment's service credential, or a registry sign-in token whose role in its active scope is "${governanceRole}" or higher (the role that may write the scope's governance), is admitted at "global"`;
124
+ switch (reading.basis) {
125
+ case "single_user":
126
+ return `this single-user deployment admits every caller at "global"`;
127
+ case "service_credential":
128
+ return `the deployment's service credential is admitted at "global"`;
129
+ case "sign_in_role":
130
+ return `the registry sign-in token's role in its active scope is "${reading.role ?? ""}" — ${reach}; a scope admin can raise the role`;
131
+ case "sign_in_role_unrecognized":
132
+ return `the registry sign-in token carries no role this deployment recognizes (${USER_ROLES.join(" < ")}) — ${reach}`;
133
+ case "identity_without_role":
134
+ return `a direct-door principal token proves who the caller is, not a role — ${reach}`;
135
+ case "unverified":
136
+ return `the request carries no credential this deployment verifies — ${reach}`;
137
+ default: {
138
+ const unknownBasis = reading.basis;
139
+ throw new Error(`requestTrustRefusal: trust basis ${String(unknownBasis)} unknown`);
140
+ }
141
+ }
142
+ }
143
+ //# sourceMappingURL=caller-trust.js.map
@@ -48,6 +48,7 @@ import type { PermissionMode } from "@sema-agent/core";
48
48
  import type { CheckpointCtx } from "./route-ctx.js";
49
49
  import type { TaskRequestBody } from "./wire-types.js";
50
50
  import type { InertToolListEntry } from "../rule-entry-list.js";
51
+ import { type Refusal } from "./refusal-body.js";
51
52
  /** 读法记号的闭集(一词 = 当前读法):这一行体里的 `settings.permissions.allow` 是按「交给引擎的 allow 层」写下、也该按它读的
52
53
  * (与能力位 `settings.permissions.allowLayer` 同一个说法)。 */
53
54
  export declare const PERMISSIONS_ALLOW_READINGS: readonly ["allow_layer"];
@@ -98,18 +99,11 @@ export declare function withPermissionModeRewritten(ctx: CheckpointCtx, body: Ta
98
99
  * 记号缺席或认不得 ⇒ 不是「按当前读法写下」的证据,与 allow 记号同一条纪律。 */
99
100
  export declare function permissionModeReadingStated(ctx: CheckpointCtx): boolean;
100
101
  /**
101
- * 第三问的拒答复 —— 码与落点同 allow 记号那一问(`checkpoint.unsupported_version`,409,`retriable:true` = 那张卡仍 pending,**不是**「原样重试会成功」)。
102
+ * 第三问的拒答复 —— 码与落点同 allow 记号那一问(`checkpoint.unsupported_version`,409;卡仍 pending 时体上的 `retriable:true` 由 {@link resumeRefusalWithCard} 追加,本铸点不带)。
102
103
  * 句子说原因(更早的版本在每次续跑重钳运维的 AUTONOMY、没把它记进任务;本版只在提交时记一次 ⇒ 续跑会按任务提交时的原词跑)与两条出路。
103
- * 🔴 形是给冻结门看的:`status: <三位数>, body: { error: "<整句双引号字面>", errorCode: "<码>"`,中间只许有空白。
104
+ * 🔴 形是给冻结门看的:`status: <三位数>, body: refusalBody({ errorCode: "<码>", message: "<整句双引号字面>"`,中间只许有空白。
104
105
  */
105
- export declare function permissionModeReadingRefusal(): {
106
- status: number;
107
- body: {
108
- error: string;
109
- errorCode: string;
110
- retriable: true;
111
- };
112
- };
106
+ export declare function permissionModeReadingRefusal(): ResumeRefusalAnswer;
113
107
  /**
114
108
  * 本行能否被按当前读法重放:体里 `allow` 在生效而行上的记号不是当前这一个词 ⇒ **不能**(`true` = 拒)。
115
109
  * 记号缺席、是旧词(`"statement"`)或认不得(手改 / 将来的写者)⇒ 同样拒:只有当前这个词是「按当前读法写下」的证据。
@@ -118,20 +112,13 @@ export declare function allowListReadingUnstated(ctx: CheckpointCtx): boolean;
118
112
  /** 被拒的行是哪一代写的(只在 {@link allowListReadingUnstated} 为真时有意义):记号是 `"statement"` ⇒ 表态时代;其余(缺席 / 认不得)⇒ 名单时代。 */
119
113
  export declare function allowListReadingEraOf(ctx: CheckpointCtx): AllowListReadingEra;
120
114
  /**
121
- * 拒的答复 —— 码与落点照「退役 mode-seed 行」的先例(`checkpoint.unsupported_version`,409,`retriable:true` = 那张卡仍 pending;**不是**「原样重试会成功」)。
115
+ * 拒的答复 —— 码与落点照「退役 mode-seed 行」的先例(`checkpoint.unsupported_version`,409;卡仍 pending 时的 `retriable:true` 由 {@link resumeRefusalWithCard} 追加,本铸点不带)。
122
116
  * 拒在认领之前,所以没有 `taskId`(行没抢到就不造键)。句子按这一行是哪一代写的分两句(闭集穷举,加一代 ⇒ 编译红):说原因(这条任务停在哪种读法上、
123
117
  * 照当前读法续跑会放宽什么)与出路(作为新任务重提,仍停驻的先取消)。
124
118
  *
125
- * 🔴 形是给冻结门看的(`api-error-text-freeze` 的 resume 家族收集器):`status: <三位数>, body: { error: "<整句双引号字面>", errorCode: "<码>"`,中间只许有空白。
119
+ * 🔴 形是给冻结门看的(`api-error-text-freeze` 的 resume 家族收集器):`status: <三位数>, body: refusalBody({ errorCode: "<码>", message: "<整句双引号字面>"`,中间只许有空白。
126
120
  */
127
- export declare function allowListReadingRefusal(era: AllowListReadingEra): {
128
- status: number;
129
- body: {
130
- error: string;
131
- errorCode: string;
132
- retriable: true;
133
- };
134
- };
121
+ export declare function allowListReadingRefusal(era: AllowListReadingEra): ResumeRefusalAnswer;
135
122
  /**
136
123
  * 一条停驻行的持久化体在本版上**不能**重放时,是哪一条规则拒的(闭集;加一条 ⇒ {@link storedBodyReplayAnswer} 的 switch 编译红)。
137
124
  * 答 `checkpoint.unsupported_version` 的两臂随带这一行的写者版本(续跑上下文的 `writerVersion`,缺席 = 本版之前写下的行)—— 那一码的两版本键由它铸({@link buildCheckpointVersionKeys})。
@@ -168,11 +155,36 @@ export interface ResumeRefusalAnswer {
168
155
  } & Record<string, unknown>;
169
156
  }
170
157
  /**
171
- * 「续跑被一条准入策略挡住」的**唯一**铸点:`resolveSpec` 在重放存量体时抛出的 `HttpError`(400 族)折成 409 `resume_blocked_by_policy`,
172
- * `blockedBy` = 那条 400 的码(属主 `http/send.ts` `httpErrorCode`),`extra` 原样随体。{@link storedBodyReplayAnswer} 的工具名清单那一臂与
158
+ * 「续跑被一条准入策略挡住」的**唯一**铸点:`resolveSpec` 在重放存量体时抛出的 `HttpError`(400 族)折成 409 `resume_blocked_by_policy`。
159
+ * 入参是内层那只拒的 {@link Refusal}(`HttpError` 经 `http/send.ts` 的 `httpErrorRefusal` 读 —— 拆 `HttpError` 的唯一一处,码的属主 `httpErrorCode`):
160
+ * `blockedBy` = 内层的码,句子 = 前缀 + 内层的句子,内层的机读事实原样随体。{@link storedBodyReplayAnswer} 的工具名清单那一臂与
173
161
  * `resume-legs.ts` 的折叠口都调它 —— 句子与码只在这里写一次(冻结门 `api-error-text-freeze` 的模板骨架表锚这一处)。
162
+ *
163
+ * 🔴 **句尾点名出口**:这一拒不消费卡(卡仍 pending、run 行留停驻),被挡在一张 deny 不掉的卡前面的调用方需要知道怎么收场 ——
164
+ * `POST /v1/runs/:id/cancel` 对停驻的 run 直接结算(CAS 过期该卡再终局 run 行,不跑模型轮)。句子写「若仍停驻」而不是随卡有无换话:有卡 / 无卡(终态 run 的 steer 在铸唤醒卡之前拒)
165
+ * 两种处境除 `retriable` 外逐字同体(同判同答),与另两类存量体拒(allow 读法 / 模式词读法)句子里的出口是同一个端点、同一种写法。
166
+ *
167
+ * 本铸点**不带** `retriable`:那是调用点的事实(有没有一张待批卡仍在等),由 {@link resumeRefusalWithCard} 一处追加 —— 续跑入口(卡仍 pending、run 行留 `suspended`)
168
+ * 带 `retriable:true`,终态 run 的 steer 在铸唤醒卡之前拒(没有卡)不带。键集 = `errorCode` · `error` · `blockedBy` · (`field` · `reason` · 其余 `extra`,有才在)
169
+ * · (`retriable`,卡在才在)。
170
+ */
171
+ export declare function resumeBlockedByPolicyAnswer(inner: Refusal): ResumeRefusalAnswer;
172
+ /**
173
+ * 一次续跑的答复是不是 {@link resumeBlockedByPolicyAnswer} 铸的那一只(409 `resume_blocked_by_policy`)—— SLA 拒扫腿据此区分「同一份字节在本版永远被拒」与别的 ≥400
174
+ * (后者可能是瞬时的,照旧逐拍重试)。码的写端与读端住在同一个模块,读端不在别处第二次手拼这个字面。
174
175
  */
175
- export declare function resumeBlockedByPolicyAnswer(message: string, blockedBy: string, extra?: Record<string, unknown> | undefined): ResumeRefusalAnswer;
176
+ export declare function isResumeBlockedByPolicy(answer: {
177
+ readonly status: number;
178
+ readonly body: unknown;
179
+ }): boolean;
180
+ /**
181
+ * 🔴 **三类续跑拒体上 `retriable` 的唯一写点**(本服务重放存量体前的拒、准入策略折叠、引擎拒的续跑):卡仍 pending(`cardPending`)⇒ 体尾追加 `retriable: true`;
182
+ * 否则体原样(键缺席)。这三类拒上规则一条:`retriable` 在场 ⇔ 有一张待批卡仍在等、run 行留 `suspended`(**不是**「原样重试会成功」—— 契约附录 A.1 注那一个意思)。
183
+ * 门型对不上的早拒(`gate_not_resumable` 一族)不经这里、不带它。三个调用点各交自己的事实:
184
+ * {@link storedBodyReplayAnswer}(调用方的 `cardPending`)、`resume-legs.ts` 的准入策略折叠口(续跑入口,恒有卡)与 `checkpointRefusalAnswer`(引擎拒的处置读口答 `retriable`)。
185
+ * 排在体尾:拒绝带来的附带键不得抹掉它。纯函数。
186
+ */
187
+ export declare function resumeRefusalWithCard(answer: ResumeRefusalAnswer, cardPending: boolean): ResumeRefusalAnswer;
176
188
  /**
177
189
  * `stored-body-replay.ts` `storedBodyReplayRefusal` 的**日志字段**(三处问点同一形,各自只再加坐标键 `sessionId` / `taskId`):`kind` 判别,allow 臂带 `era`、技能臂带 `layer`,`note` 一句出路。
178
190
  * 事件名三个(问点各一:`resume_refused_stored_body` / `steer_wake_park_refused_stored_body` / `deny_sweep_stored_body_skipped`),字段形只有这一只。
@@ -189,6 +201,11 @@ export declare function storedBodyReplayLogFields(refusal: StoredBodyReplayRefus
189
201
  * `stored-body-replay.ts` `storedBodyReplayRefusal` 的答复:每条规则一只既有铸点(allow 记号 ⇒ {@link allowListReadingRefusal};模式词记号 ⇒ {@link permissionModeReadingRefusal};
190
202
  * 这两只答 `checkpoint.unsupported_version`,体按那一码的键律补两版本键,`readerVersion` = 调用方传的本进程服务版本;工具名清单 ⇒ {@link resumeBlockedByPolicyAnswer},与提交腿的 400
191
203
  * (该层的拒码:`request.field_invalid` / `config.agent.unknown_tool` / `config.tool_face_control`)同码同句 —— 体上只有这一个问题时;存量体同时还踩中 `resolveSpec` 更早的拒〔三桶超帽 / 托管姿态〕时,提交侧答更早那条、续跑侧答本句,两边都是拒,指路不同)。
204
+ *
205
+ * 🔴 `cardPending` —— **调用方交出的事实**:这一次拒的时候,有没有一张待批卡仍在等。`retriable:true` 说的恰是「卡仍 pending」,所以它只在卡在时在场(经
206
+ * {@link resumeRefusalWithCard} 一处写):续跑入口(`/decide` · `/resume` · `/wake` · plan_review · workflow 决定的新一跑,五个问点里除下面这一个之外全部)传 `true`;
207
+ * 终态 run 的 `POST /v1/runs/:id/steer` 在**铸唤醒卡之前**就拒,没有卡也没铸卡 ⇒ 传 `false`,体上不带 `retriable`(三条臂同一条律;其余键两种处境逐字相同 —— 同判同答)。
208
+ * 没有默认值:每个调用点必须说出这件事实。
192
209
  */
193
- export declare function storedBodyReplayAnswer(refusal: StoredBodyReplayRefusal, readerVersion: string): ResumeRefusalAnswer;
210
+ export declare function storedBodyReplayAnswer(refusal: StoredBodyReplayRefusal, readerVersion: string, cardPending: boolean): ResumeRefusalAnswer;
194
211
  //# sourceMappingURL=checkpoint-ctx.d.ts.map
@@ -1,3 +1,4 @@
1
+ import { refusalBody } from "./refusal-body.js";
1
2
  export const PERMISSIONS_ALLOW_READINGS = ["allow_layer"];
2
3
  export const PERMISSION_MODE_READINGS = ["entry_word"];
3
4
  export const ALLOW_LIST_READING_ERAS = ["list", "statement"];
@@ -31,11 +32,10 @@ export function permissionModeReadingStated(ctx) {
31
32
  export function permissionModeReadingRefusal() {
32
33
  return {
33
34
  status: 409,
34
- body: {
35
- error: "this task was suspended by an earlier server version that re-applied this deployment's AUTONOMY on every resume instead of recording it in the task; this version records the operator's plan floor once, when a task is submitted, so continuing would run this task under the permission mode it was submitted with rather than the one it ran under. Nothing was decided and nothing was resumed, and retrying will be refused the same way: submit the work again as a new task, and if this task is still suspended cancel it first (POST /v1/runs/:id/cancel); to let it finish with read-only hands instead, set AUTONOMY=read-only until it does.",
35
+ body: refusalBody({
36
36
  errorCode: "checkpoint.unsupported_version",
37
- retriable: true,
38
- },
37
+ message: "this task was suspended by an earlier server version that re-applied this deployment's AUTONOMY on every resume instead of recording it in the task; this version records the operator's plan floor once, when a task is submitted, so continuing would run this task under the permission mode it was submitted with rather than the one it ran under. Nothing was decided and nothing was resumed, and retrying will be refused the same way: submit the work again as a new task, and if this task is still suspended cancel it first (POST /v1/runs/:id/cancel); to let it finish with read-only hands instead, set AUTONOMY=read-only until it does.",
38
+ }),
39
39
  };
40
40
  }
41
41
  export function allowListReadingUnstated(ctx) {
@@ -53,20 +53,18 @@ export function allowListReadingRefusal(era) {
53
53
  case "list":
54
54
  return {
55
55
  status: 409,
56
- body: {
57
- error: "this task was suspended by an earlier server version that did not record how it read settings.permissions.allow (7.114.0 and earlier read it as a whitelist: every tool not on the list was refused); this version hands that list to the engine's allow layer, where each entry is a standing yes for the calls it covers, so continuing would give the task more tools than it was submitted with. Nothing was decided and nothing was resumed, and retrying will be refused the same way: submit the work again as a new task, and if this task is still suspended cancel it first (POST /v1/runs/:id/cancel). To allow only certain tools, use the session rules' toolAllow (PUT /v1/sessions/:id/policy) or the request's excludeTools.",
56
+ body: refusalBody({
58
57
  errorCode: "checkpoint.unsupported_version",
59
- retriable: true,
60
- },
58
+ message: "this task was suspended by an earlier server version that did not record how it read settings.permissions.allow (7.114.0 and earlier read it as a whitelist: every tool not on the list was refused); this version hands that list to the engine's allow layer, where each entry is a standing yes for the calls it covers, so continuing would give the task more tools than it was submitted with. Nothing was decided and nothing was resumed, and retrying will be refused the same way: submit the work again as a new task, and if this task is still suspended cancel it first (POST /v1/runs/:id/cancel). To allow only certain tools, use the session rules' toolAllow (PUT /v1/sessions/:id/policy) or the request's excludeTools.",
59
+ }),
61
60
  };
62
61
  case "statement":
63
62
  return {
64
63
  status: 409,
65
- body: {
66
- error: "this task was suspended by an earlier server version (7.115.0 to 7.116.x) that read settings.permissions.allow as a statement that the named tools are allowed, which answered only the question nobody else had answered and never cleared an ordinary question such as a file write or a shell command; this version hands that list to the engine's allow layer, where an entry also clears those ordinary questions, so continuing would run calls without asking that the task was submitted to ask about. Nothing was decided and nothing was resumed, and retrying will be refused the same way: submit the work again as a new task, and if this task is still suspended cancel it first (POST /v1/runs/:id/cancel).",
64
+ body: refusalBody({
67
65
  errorCode: "checkpoint.unsupported_version",
68
- retriable: true,
69
- },
66
+ message: "this task was suspended by an earlier server version (7.115.0 to 7.116.x) that read settings.permissions.allow as a statement that the named tools are allowed, which answered only the question nobody else had answered and never cleared an ordinary question such as a file write or a shell command; this version hands that list to the engine's allow layer, where an entry also clears those ordinary questions, so continuing would run calls without asking that the task was submitted to ask about. Nothing was decided and nothing was resumed, and retrying will be refused the same way: submit the work again as a new task, and if this task is still suspended cancel it first (POST /v1/runs/:id/cancel).",
67
+ }),
70
68
  };
71
69
  default: {
72
70
  const unhandled = era;
@@ -77,12 +75,18 @@ export function allowListReadingRefusal(era) {
77
75
  export function buildCheckpointVersionKeys(writerVersion, readerVersion) {
78
76
  return writerVersion !== undefined ? { writerVersion, readerVersion } : {};
79
77
  }
80
- export function resumeBlockedByPolicyAnswer(message, blockedBy, extra) {
78
+ export function resumeBlockedByPolicyAnswer(inner) {
81
79
  return {
82
80
  status: 409,
83
- body: { error: `resume blocked by an admission policy change: ${message}`, errorCode: "resume_blocked_by_policy", blockedBy, ...(extra ?? {}) },
81
+ body: refusalBody({ errorCode: "resume_blocked_by_policy", message: `resume blocked by an admission policy change: ${inner.message} — nothing was resumed; if the task is still suspended on its approval, cancel it (POST /v1/runs/:id/cancel) to end it without another model turn`, facts: { blockedBy: inner.errorCode, ...inner.facts } }),
84
82
  };
85
83
  }
84
+ export function isResumeBlockedByPolicy(answer) {
85
+ return answer.status === 409 && typeof answer.body === "object" && answer.body !== null && answer.body.errorCode === "resume_blocked_by_policy";
86
+ }
87
+ export function resumeRefusalWithCard(answer, cardPending) {
88
+ return cardPending ? { status: answer.status, body: { ...answer.body, retriable: true } } : answer;
89
+ }
86
90
  export function storedBodyReplayLogFields(refusal) {
87
91
  switch (refusal.kind) {
88
92
  case "allow_list_reading":
@@ -97,14 +101,17 @@ export function storedBodyReplayLogFields(refusal) {
97
101
  }
98
102
  }
99
103
  }
100
- export function storedBodyReplayAnswer(refusal, readerVersion) {
104
+ export function storedBodyReplayAnswer(refusal, readerVersion, cardPending) {
105
+ return resumeRefusalWithCard(storedBodyReplayArmAnswer(refusal, readerVersion), cardPending);
106
+ }
107
+ function storedBodyReplayArmAnswer(refusal, readerVersion) {
101
108
  switch (refusal.kind) {
102
109
  case "allow_list_reading": {
103
110
  const answer = allowListReadingRefusal(refusal.era);
104
111
  return { status: answer.status, body: { ...answer.body, ...buildCheckpointVersionKeys(refusal.writerVersion, readerVersion) } };
105
112
  }
106
113
  case "inert_tool_list":
107
- return resumeBlockedByPolicyAnswer(refusal.entry.message, refusal.entry.code, refusal.entry.extra !== undefined ? { ...refusal.entry.extra } : undefined);
114
+ return resumeBlockedByPolicyAnswer(refusal.entry.extra === undefined ? { errorCode: refusal.entry.code, message: refusal.entry.message } : { errorCode: refusal.entry.code, message: refusal.entry.message, facts: refusal.entry.extra });
108
115
  case "permission_mode_reading": {
109
116
  const answer = permissionModeReadingRefusal();
110
117
  return { status: answer.status, body: { ...answer.body, ...buildCheckpointVersionKeys(refusal.writerVersion, readerVersion) } };