@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,52 +1,85 @@
1
1
  import { APPROVAL_REACH, MCP_IMAGE_MAX_BASE64, isApprovalReach, isPermissionMode, isThinkingLevel, expandTiers } from "@sema-agent/core";
2
2
  import { isAtMentionable, matchCatalogModel, refusedCatalogEntry, selectableCatalog } from "../model-select.js";
3
- import { modelUnavailableMessage } from "../model-entry-refusal.js";
3
+ import { echoModelRef, modelUnavailableMessage } from "../model-entry-refusal.js";
4
4
  import { HttpError, sessionIdShapeIssue } from "../security.js";
5
5
  import { MAX_SETTINGS_OUTPUT_STYLE_CHARS, MAX_SETTINGS_ENV_VARS, MAX_SETTINGS_ENV_KEY_CHARS, MAX_SETTINGS_ENV_VALUE_CHARS, PERMISSION_MODE_WORDS, parseTaskSettings, settingsPermissionBucketIssue, skillListingBudgetFractionOk, skillListingMaxDescOk, stampEntryPermissionMode, taskHooksHonored, taskSettingsKeyIssue } from "../task-settings.js";
6
+ import { tightenOnlySeatIssue } from "../tighten-only-seats.js";
6
7
  import { buildEntryModeClampNotice } from "../entry-mode-clamp-notice.js";
7
8
  import { autonomyModeFloor } from "../runtime-governance.js";
8
9
  import { taskBodyKeyIssue } from "../request-key-closure.js";
9
- import { FILE_HISTORY_DISABLED_NO_RESTORE, fileHistoryRestoreConflict, inheritEnvFieldIssue, singleMemberOffFieldIssue } from "../request-value-closure.js";
10
+ import { FILE_HISTORY_DISABLED_NO_RESTORE, fileHistoryRestoreConflict, fileHistoryRestoreKeysInBody, inheritEnvFieldIssue, singleMemberOffFieldIssue } from "../request-value-closure.js";
10
11
  import * as facts from "../capability-facts.js";
11
- import { buildToolMatcherRefusal, parseHooksConfig, toolMatcherIssue } from "../hooks/hook-runner.js";
12
+ import { buildHooksRefusal, parseHooksConfig, hooksMatcherIssue } from "../hooks/hook-runner.js";
12
13
  import { judgeRequestWebSearch } from "../plugins/web-search.js";
13
- import { normalizeApproachNotice, skillToolListOk, skillToolListRefusal, unknownTaskAgentModelRef, validateTaskAgents } from "../spec-fields.js";
14
+ import { normalizeApproachNotice, skillToolListOk, unknownTaskAgentModelRef, validateTaskAgents } from "../spec-fields.js";
15
+ import { allowSelectorWarningsOf, skillToolListsOverCap } from "../rule-entry-list.js";
16
+ import { limitFacts, limitRefusal } from "../limit-refusal.js";
17
+ import { fieldConflictFacts } from "../field-conflict.js";
18
+ import { echoCallerText, quotedCallerText } from "../caller-text-echo.js";
14
19
  import { MAX_ADDITIONAL_DIRS } from "../task-cwd.js";
15
20
  import { verifyRoundsFromBody } from "./verify-rounds.js";
16
21
  import { skillCarriesRetiredManifest } from "./retired-skill-manifest.js";
17
22
  import { resolveDevicePlacementIntent } from "./device-placement.js";
23
+ import { callerTrust, requestTrustRefusal } from "./caller-trust.js";
18
24
  import { createRunAcceptance } from "../run-acceptance.js";
19
25
  import { sendError, sendHttpError } from "./send.js";
26
+ import { refuseSubmitBody } from "./request-guards.js";
27
+ import { sqlWallsOf } from "../plugins/sql-driver.js";
20
28
  import { ABSOLUTE_HOST_PATH_MAX, isAbsoluteHostPath, WEB_ADMIN_ENV } from "@sema-agent/settings-schema";
21
29
  const APPROVAL_REACH_WORDS = APPROVAL_REACH.map((word) => JSON.stringify(word)).join(" / ");
22
30
  export const MAX_SKILL_CONTENT_CHARS = 1_048_576;
23
31
  export const MAX_SYSTEM_PROMPT_CHARS = 16_384;
24
32
  export const MAX_OUTPUT_SCHEMA_CHARS = 32_768;
33
+ const MAX_JOB_ID_CHARS = 64;
34
+ const MAX_CLIENT_TIMEZONE_CHARS = 64;
35
+ const MAX_CLIENT_USER_EMAIL_CHARS = 256;
36
+ const MAX_SANDBOX_IMAGE_PROFILE_CHARS = 128;
37
+ const MAX_RESUME_AT_CHARS = 64;
38
+ const overCharsFacts = (field, v, cap) => (typeof v === "string" && v.length > cap ? limitFacts(field, "characters", v.length, cap) : undefined);
39
+ const multiAttemptFields = (body) => {
40
+ const out = [];
41
+ if (body.verify === true)
42
+ out.push("verify");
43
+ if (body.cascade === true)
44
+ out.push("cascade");
45
+ return out;
46
+ };
25
47
  export function validateUserSkills(skills) {
26
48
  if (skills === undefined)
27
49
  return null;
28
50
  if (!Array.isArray(skills))
29
- return "skills must be an array of { name, description, content }";
30
- for (const s of skills) {
31
- if (s === null || typeof s !== "object")
32
- return "each skill must be an object { name, description, content }";
33
- if (typeof s["name"] !== "string" || s["name"].length === 0)
34
- return "skill.name must be a non-empty string";
35
- if (typeof s["description"] !== "string")
36
- return "skill.description must be a string";
37
- if (typeof s["content"] !== "string" || s["content"].length === 0 || s["content"].length > MAX_SKILL_CONTENT_CHARS)
38
- return `skill.content must be a non-empty string of at most ${MAX_SKILL_CONTENT_CHARS} characters (the engine rejects skills over this size outright at load time)`;
39
- if (s["baseDir"] !== undefined && !isAbsoluteHostPath(s["baseDir"]))
40
- return `skill.baseDir must be an absolute path string of at most ${ABSOLUTE_HOST_PATH_MAX} characters with no ".." segment and no NUL byte (it is not resolved or read here — the engine only substitutes it into the skill's own text)`;
41
- if (skillCarriesRetiredManifest(s))
42
- return SKILL_MANIFEST_RETIRED;
43
- for (const key of ["allowedTools", "disallowedTools"]) {
44
- if (s[key] !== undefined && !skillToolListOk(s[key]))
45
- return `skill.${key} must be an array of strings (permission-rule spellings: a tool name, mcp__<server> / mcp__<server>__*, Bash(<prefix>:*), Read(//<dir>/**))`;
46
- }
47
- const listRefusal = skillToolListRefusal(s);
48
- if (listRefusal !== undefined)
49
- return listRefusal;
51
+ return { message: "skills must be an array of { name, description, content }" };
52
+ for (let k = 0; k < skills.length; k++) {
53
+ const shape = userSkillShapeIssue(skills[k], k);
54
+ if (shape !== null)
55
+ return shape;
56
+ const over = skillToolListsOverCap(skills[k], `skills[${k}]`, "top");
57
+ if (over !== undefined)
58
+ return { message: over.message, ...(over.extra !== undefined ? { facts: over.extra } : {}) };
59
+ }
60
+ return null;
61
+ }
62
+ function userSkillShapeIssue(item, index) {
63
+ if (item === null || typeof item !== "object")
64
+ return { message: "each skill must be an object { name, description, content }" };
65
+ const s = item;
66
+ if (typeof s["name"] !== "string" || s["name"].length === 0)
67
+ return { message: "skill.name must be a non-empty string" };
68
+ if (typeof s["description"] !== "string")
69
+ return { message: "skill.description must be a string" };
70
+ if (typeof s["content"] !== "string" || s["content"].length === 0 || s["content"].length > MAX_SKILL_CONTENT_CHARS) {
71
+ const facts = overCharsFacts(`skills[${index}].content`, s["content"], MAX_SKILL_CONTENT_CHARS);
72
+ return { message: `skill.content must be a non-empty string of at most ${MAX_SKILL_CONTENT_CHARS} characters (the engine rejects skills over this size outright at load time)`, ...(facts === undefined ? {} : { facts }) };
73
+ }
74
+ if (s["baseDir"] !== undefined && !isAbsoluteHostPath(s["baseDir"])) {
75
+ const facts = overCharsFacts(`skills[${index}].baseDir`, s["baseDir"], ABSOLUTE_HOST_PATH_MAX);
76
+ return { message: `skill.baseDir must be an absolute path string of at most ${ABSOLUTE_HOST_PATH_MAX} characters with no ".." segment and no NUL byte (it is not resolved or read here — the engine only substitutes it into the skill's own text)`, ...(facts === undefined ? {} : { facts }) };
77
+ }
78
+ if (skillCarriesRetiredManifest(s))
79
+ return { message: SKILL_MANIFEST_RETIRED };
80
+ for (const key of ["allowedTools", "disallowedTools"]) {
81
+ if (s[key] !== undefined && !skillToolListOk(s[key]))
82
+ return { message: `skill.${key} must be an array of strings (permission-rule spellings: a tool name, mcp__<server> / mcp__<server>__*, Bash(<prefix>:*), Read(//<dir>/**))` };
50
83
  }
51
84
  return null;
52
85
  }
@@ -60,15 +93,68 @@ function refuseUnavailableModel(res, config, field, ref) {
60
93
  const hit = refusedCatalogEntry(ref, config.modelRefusals);
61
94
  if (hit === undefined)
62
95
  return false;
63
- const message = modelUnavailableMessage(field, ref.slice(0, 120), hit.name, hit.refusal);
96
+ const message = modelUnavailableMessage(field, ref, hit.name, hit.refusal);
64
97
  sendError(res, 400, "request.model_unavailable", message);
65
98
  return true;
66
99
  }
100
+ const kindOf = (v) => (v === null ? "null" : Array.isArray(v) ? "an array" : typeof v === "object" ? "an object" : `a ${typeof v}`);
101
+ function hostPathListRefusal(field, raw) {
102
+ if (!Array.isArray(raw))
103
+ return { message: `${field} must be an array of absolute host paths` };
104
+ if (raw.length > MAX_ADDITIONAL_DIRS)
105
+ return limitRefusal(field, "entries", raw.length, MAX_ADDITIONAL_DIRS);
106
+ const index = raw.findIndex((d) => !isAbsoluteHostPath(d));
107
+ if (index < 0)
108
+ return undefined;
109
+ const bad = raw[index];
110
+ return { message: `${field}[${index}] must be a non-empty absolute host path (no '..' segments) — got ${typeof bad === "string" ? quotedCallerText(bad) : kindOf(bad)}`, facts: { field, reason: "bad_entry", index } };
111
+ }
67
112
  const modelIdOf = (model) => (typeof model === "string" ? model : model?.id);
68
113
  export function createAdmission(ctx) {
69
114
  const { deps, readJson, runnerFor } = ctx;
70
115
  async function prepareSpec(req, res, bodyIn, onTypedFailure, legFacts) {
71
116
  const body = bodyIn ?? (await readJson(req));
117
+ {
118
+ const refusal = refuseSubmitBody(sqlWallsOf(deps.sqlEngine), body);
119
+ if (refusal !== null) {
120
+ const facts = { ...limitFacts("body", "bytes", refusal.bytes, refusal.limitBytes), wallSource: refusal.wallSource };
121
+ switch (refusal.wallSource) {
122
+ case "reported":
123
+ switch (refusal.by) {
124
+ case "row":
125
+ sendError(res, 413, "request.payload_too_large", `task body is ${refusal.bytes} bytes, over this deployment's ${refusal.limitBytes}-byte limit: the database stores each submitted task in one row and holds at most ${refusal.wallBytes} bytes per row — shrink the inline images / userAttachments, or ask the operator to raise the database's single-row limit (TiDB performance.txn-entry-size-limit)`, facts);
126
+ break;
127
+ case "packet":
128
+ sendError(res, 413, "request.payload_too_large", `task body is ${refusal.bytes} bytes as sent to the database (JSON text with SQL string escaping), over this deployment's ${refusal.limitBytes}-byte limit: the database takes each submitted task in one statement and accepts at most ${refusal.wallBytes} bytes per statement — shrink the inline images / userAttachments, or ask the operator to raise the database's max_allowed_packet`, facts);
129
+ break;
130
+ default: {
131
+ const unhandled = refusal.by;
132
+ throw new Error(`submit body refusal without an HTTP answer: ${String(unhandled)}`);
133
+ }
134
+ }
135
+ break;
136
+ case "assumed":
137
+ switch (refusal.by) {
138
+ case "row":
139
+ sendError(res, 413, "request.payload_too_large", `task body is ${refusal.bytes} bytes, over this deployment's ${refusal.limitBytes}-byte limit: the database's single-row limit was not read (engine facts not read yet, or the limit could not be read); refusing conservatively at ${refusal.wallBytes} bytes per row (the smallest documented single-row limit among the supported engines) — retry shortly; if it persists, ask the operator to let the service's database account read the engine's row-size limit`, facts);
140
+ break;
141
+ case "packet":
142
+ sendError(res, 413, "request.payload_too_large", `task body is ${refusal.bytes} bytes as sent to the database (JSON text with SQL string escaping), over this deployment's ${refusal.limitBytes}-byte limit: the database's statement limit was not read (engine facts not read yet, or max_allowed_packet could not be read); refusing conservatively at ${refusal.wallBytes} bytes per statement (smallest documented max_allowed_packet default) — retry shortly; if it persists, ask the operator to check that the service's database account can read max_allowed_packet`, facts);
143
+ break;
144
+ default: {
145
+ const unhandled = refusal.by;
146
+ throw new Error(`submit body refusal without an HTTP answer: ${String(unhandled)}`);
147
+ }
148
+ }
149
+ break;
150
+ default: {
151
+ const unhandled = refusal.wallSource;
152
+ throw new Error(`submit body refusal without an HTTP answer: ${String(unhandled)}`);
153
+ }
154
+ }
155
+ return null;
156
+ }
157
+ }
72
158
  if (!body || typeof body.objective !== "string") {
73
159
  sendError(res, 400, "request.field_invalid", "missing 'objective' string");
74
160
  return null;
@@ -84,8 +170,8 @@ export function createAdmission(ctx) {
84
170
  return null;
85
171
  }
86
172
  }
87
- if (body.jobId !== undefined && (typeof body.jobId !== "string" || body.jobId.length === 0 || body.jobId.length > 64)) {
88
- sendError(res, 400, "request.field_invalid", "jobId must be a non-empty string of at most 64 characters");
173
+ if (body.jobId !== undefined && (typeof body.jobId !== "string" || body.jobId.length === 0 || body.jobId.length > MAX_JOB_ID_CHARS)) {
174
+ sendError(res, 400, "request.field_invalid", "jobId must be a non-empty string of at most 64 characters", overCharsFacts("jobId", body.jobId, MAX_JOB_ID_CHARS));
89
175
  return null;
90
176
  }
91
177
  {
@@ -96,7 +182,7 @@ export function createAdmission(ctx) {
96
182
  }
97
183
  }
98
184
  if (typeof body.systemPrompt === "string" && body.systemPrompt.length > MAX_SYSTEM_PROMPT_CHARS) {
99
- sendError(res, 400, "request.field_invalid", `systemPrompt must be at most ${MAX_SYSTEM_PROMPT_CHARS} characters`);
185
+ sendError(res, 400, "request.field_invalid", `systemPrompt must be at most ${MAX_SYSTEM_PROMPT_CHARS} characters`, limitFacts("systemPrompt", "characters", body.systemPrompt.length, MAX_SYSTEM_PROMPT_CHARS));
100
186
  return null;
101
187
  }
102
188
  if (body.appendSystemPrompt !== undefined) {
@@ -105,7 +191,7 @@ export function createAdmission(ctx) {
105
191
  return null;
106
192
  }
107
193
  if (body.appendSystemPrompt.length > MAX_SYSTEM_PROMPT_CHARS) {
108
- sendError(res, 400, "request.field_invalid", `appendSystemPrompt must be at most ${MAX_SYSTEM_PROMPT_CHARS} characters`);
194
+ sendError(res, 400, "request.field_invalid", `appendSystemPrompt must be at most ${MAX_SYSTEM_PROMPT_CHARS} characters`, limitFacts("appendSystemPrompt", "characters", body.appendSystemPrompt.length, MAX_SYSTEM_PROMPT_CHARS));
109
195
  return null;
110
196
  }
111
197
  }
@@ -113,35 +199,13 @@ export function createAdmission(ctx) {
113
199
  sendError(res, 400, "request.field_invalid", "cwd must be a non-empty absolute host path");
114
200
  return null;
115
201
  }
116
- const addDirsRaw = body.additionalDirectories;
117
- if (addDirsRaw !== undefined) {
118
- if (!Array.isArray(addDirsRaw)) {
119
- sendError(res, 400, "request.field_invalid", "additionalDirectories must be an array of absolute host paths");
120
- return null;
121
- }
122
- if (addDirsRaw.length > MAX_ADDITIONAL_DIRS) {
123
- sendError(res, 400, "request.field_invalid", `additionalDirectories must have at most ${MAX_ADDITIONAL_DIRS} entries`);
124
- return null;
125
- }
126
- const bad = addDirsRaw.find((d) => !isAbsoluteHostPath(d));
127
- if (bad !== undefined) {
128
- sendError(res, 400, "request.field_invalid", "each additionalDirectories entry must be a non-empty absolute host path (no '..' segments)");
129
- return null;
130
- }
131
- }
132
- const addReadDirsRaw = body.additionalReadDirectories;
133
- if (addReadDirsRaw !== undefined) {
134
- if (!Array.isArray(addReadDirsRaw)) {
135
- sendError(res, 400, "request.field_invalid", "additionalReadDirectories must be an array of absolute host paths");
136
- return null;
137
- }
138
- if (addReadDirsRaw.length > MAX_ADDITIONAL_DIRS) {
139
- sendError(res, 400, "request.field_invalid", `additionalReadDirectories must have at most ${MAX_ADDITIONAL_DIRS} entries`);
140
- return null;
141
- }
142
- const badRead = addReadDirsRaw.find((d) => !isAbsoluteHostPath(d));
143
- if (badRead !== undefined) {
144
- sendError(res, 400, "request.field_invalid", "each additionalReadDirectories entry must be a non-empty absolute host path (no '..' segments)");
202
+ for (const field of ["additionalDirectories", "additionalReadDirectories"]) {
203
+ const raw = body[field];
204
+ if (raw === undefined)
205
+ continue;
206
+ const refusal = hostPathListRefusal(field, raw);
207
+ if (refusal !== undefined) {
208
+ sendError(res, 400, "request.field_invalid", refusal.message, refusal.facts);
145
209
  return null;
146
210
  }
147
211
  }
@@ -160,14 +224,12 @@ export function createAdmission(ctx) {
160
224
  }
161
225
  }
162
226
  if (typeof st.outputStyle === "string" && st.outputStyle.length > MAX_SETTINGS_OUTPUT_STYLE_CHARS) {
163
- sendError(res, 400, "request.field_invalid", `settings.outputStyle must be at most ${MAX_SETTINGS_OUTPUT_STYLE_CHARS} characters`);
227
+ sendError(res, 400, "request.field_invalid", `settings.outputStyle must be at most ${MAX_SETTINGS_OUTPUT_STYLE_CHARS} characters`, limitFacts("settings.outputStyle", "characters", st.outputStyle.length, MAX_SETTINGS_OUTPUT_STYLE_CHARS));
164
228
  return null;
165
229
  }
166
- if (typeof st.outputStyle === "string" &&
167
- st.outputStyle.length > 0 &&
168
- typeof body.appendSystemPrompt === "string" &&
169
- body.appendSystemPrompt.length + 2 + st.outputStyle.length > MAX_SYSTEM_PROMPT_CHARS) {
170
- sendError(res, 400, "request.field_conflict", `appendSystemPrompt + settings.outputStyle fold into one system-prompt block — combined they must be at most ${MAX_SYSTEM_PROMPT_CHARS} characters (including the 2-char joiner)`);
230
+ const foldedChars = typeof st.outputStyle === "string" && st.outputStyle.length > 0 && typeof body.appendSystemPrompt === "string" ? body.appendSystemPrompt.length + 2 + st.outputStyle.length : 0;
231
+ if (foldedChars > MAX_SYSTEM_PROMPT_CHARS) {
232
+ sendError(res, 400, "request.field_conflict", `appendSystemPrompt + settings.outputStyle fold into one system-prompt block — combined they must be at most ${MAX_SYSTEM_PROMPT_CHARS} characters (including the 2-char joiner)`, fieldConflictFacts("system_prompt_fold", ["appendSystemPrompt", "settings.outputStyle"], { count: foldedChars, cap: MAX_SYSTEM_PROMPT_CHARS }));
171
233
  return null;
172
234
  }
173
235
  const perms = st.permissions;
@@ -182,6 +244,13 @@ export function createAdmission(ctx) {
182
244
  return null;
183
245
  }
184
246
  }
247
+ {
248
+ const seatIssue = tightenOnlySeatIssue(st);
249
+ if (seatIssue) {
250
+ sendError(res, 400, "request.field_invalid", seatIssue.message, seatIssue.fields);
251
+ return null;
252
+ }
253
+ }
185
254
  const envRaw = st.env;
186
255
  if (envRaw !== undefined && envRaw !== null) {
187
256
  if (typeof envRaw !== "object" || Array.isArray(envRaw)) {
@@ -190,12 +259,16 @@ export function createAdmission(ctx) {
190
259
  }
191
260
  const entries = Object.entries(envRaw);
192
261
  if (entries.length > MAX_SETTINGS_ENV_VARS) {
193
- sendError(res, 400, "request.field_invalid", `settings.env must have at most ${MAX_SETTINGS_ENV_VARS} variables`);
262
+ sendError(res, 400, "request.field_invalid", `settings.env must have at most ${MAX_SETTINGS_ENV_VARS} variables`, limitFacts("settings.env", "entries", entries.length, MAX_SETTINGS_ENV_VARS));
194
263
  return null;
195
264
  }
196
265
  for (const [k, val] of entries) {
197
- if (k.length > MAX_SETTINGS_ENV_KEY_CHARS || (typeof val === "string" && val.length > MAX_SETTINGS_ENV_VALUE_CHARS)) {
198
- sendError(res, 400, "request.field_invalid", `settings.env keys must be ≤${MAX_SETTINGS_ENV_KEY_CHARS} chars and values ≤${MAX_SETTINGS_ENV_VALUE_CHARS} chars`);
266
+ const keyOver = k.length > MAX_SETTINGS_ENV_KEY_CHARS;
267
+ const valueOver = typeof val === "string" && val.length > MAX_SETTINGS_ENV_VALUE_CHARS;
268
+ if (keyOver || valueOver) {
269
+ const field = `settings.env.${echoCallerText(k, { maxChars: MAX_SETTINGS_ENV_KEY_CHARS })}`;
270
+ const facts = keyOver ? limitFacts(field, "characters", k.length, MAX_SETTINGS_ENV_KEY_CHARS) : limitFacts(field, "characters", val.length, MAX_SETTINGS_ENV_VALUE_CHARS);
271
+ sendError(res, 400, "request.field_invalid", `settings.env keys must be ≤${MAX_SETTINGS_ENV_KEY_CHARS} chars and values ≤${MAX_SETTINGS_ENV_VALUE_CHARS} chars`, facts);
199
272
  return null;
200
273
  }
201
274
  }
@@ -215,12 +288,13 @@ export function createAdmission(ctx) {
215
288
  if (st.hooks !== undefined && st.hooks !== null) {
216
289
  const hooksParsed = parseHooksConfig(st.hooks);
217
290
  if (!hooksParsed.config) {
218
- sendError(res, 400, "request.field_invalid", hooksParsed.error ?? "settings.hooks: invalid shape");
291
+ const refusal = buildHooksRefusal(hooksParsed.issue);
292
+ sendError(res, 400, "request.field_invalid", refusal.message, { field: refusal.field, detail: refusal.detail });
219
293
  return null;
220
294
  }
221
- const toolMatcher = toolMatcherIssue(hooksParsed.config, taskHooksHonored(deps.config) ? "regex" : "literal");
295
+ const toolMatcher = hooksMatcherIssue(hooksParsed.config, taskHooksHonored(deps.config) ? "regex" : "literal");
222
296
  if (toolMatcher !== undefined) {
223
- const refusal = buildToolMatcherRefusal(toolMatcher);
297
+ const refusal = buildHooksRefusal(toolMatcher);
224
298
  sendError(res, 400, "request.field_invalid", refusal.message, { field: refusal.field, detail: refusal.detail });
225
299
  return null;
226
300
  }
@@ -235,18 +309,19 @@ export function createAdmission(ctx) {
235
309
  }
236
310
  const skillsErr = validateUserSkills(body.skills);
237
311
  if (skillsErr) {
238
- sendError(res, 400, "request.field_invalid", skillsErr);
312
+ sendError(res, 400, "request.field_invalid", skillsErr.message, skillsErr.facts);
239
313
  return null;
240
314
  }
241
315
  if (Array.isArray(body.images)) {
242
316
  if (body.images.length > MAX_IMAGES_PER_REQUEST) {
243
- sendError(res, 413, "request.payload_too_large", `at most ${MAX_IMAGES_PER_REQUEST} images per request`);
317
+ sendError(res, 413, "request.payload_too_large", `at most ${MAX_IMAGES_PER_REQUEST} images per request`, limitFacts("images", "entries", body.images.length, MAX_IMAGES_PER_REQUEST));
244
318
  return null;
245
319
  }
246
- for (const img of body.images) {
320
+ for (const [i, img] of body.images.entries()) {
247
321
  const data = img.data;
248
- if (typeof data === "string" && Buffer.byteLength(data, "utf8") > MAX_IMAGE_BASE64_BYTES) {
249
- sendError(res, 413, "request.payload_too_large", `each inline image must be at most ${MAX_IMAGE_BASE64_BYTES} base64 bytes (the engine's inline-image limit — the model API's 5 MB image cap)`);
322
+ const dataBytes = typeof data === "string" ? Buffer.byteLength(data, "utf8") : 0;
323
+ if (dataBytes > MAX_IMAGE_BASE64_BYTES) {
324
+ sendError(res, 413, "request.payload_too_large", `each inline image must be at most ${MAX_IMAGE_BASE64_BYTES} base64 bytes (the engine's inline-image limit — the model API's 5 MB image cap)`, limitFacts(`images[${i}].data`, "bytes", dataBytes, MAX_IMAGE_BASE64_BYTES));
250
325
  return null;
251
326
  }
252
327
  }
@@ -257,17 +332,17 @@ export function createAdmission(ctx) {
257
332
  sendError(res, 400, "request.field_invalid", "clientContext must be an object");
258
333
  return null;
259
334
  }
260
- if (cc.timeZone !== undefined && (typeof cc.timeZone !== "string" || cc.timeZone.length > 64)) {
261
- sendError(res, 400, "request.field_invalid", "clientContext.timeZone must be a string of at most 64 characters");
335
+ if (cc.timeZone !== undefined && (typeof cc.timeZone !== "string" || cc.timeZone.length > MAX_CLIENT_TIMEZONE_CHARS)) {
336
+ sendError(res, 400, "request.field_invalid", "clientContext.timeZone must be a string of at most 64 characters", overCharsFacts("clientContext.timeZone", cc.timeZone, MAX_CLIENT_TIMEZONE_CHARS));
262
337
  return null;
263
338
  }
264
- if (cc.userEmail !== undefined && (typeof cc.userEmail !== "string" || cc.userEmail.length > 256)) {
265
- sendError(res, 400, "request.field_invalid", "clientContext.userEmail must be a string of at most 256 characters");
339
+ if (cc.userEmail !== undefined && (typeof cc.userEmail !== "string" || cc.userEmail.length > MAX_CLIENT_USER_EMAIL_CHARS)) {
340
+ sendError(res, 400, "request.field_invalid", "clientContext.userEmail must be a string of at most 256 characters", overCharsFacts("clientContext.userEmail", cc.userEmail, MAX_CLIENT_USER_EMAIL_CHARS));
266
341
  return null;
267
342
  }
268
343
  }
269
- if (body.sandboxImageProfile !== undefined && (typeof body.sandboxImageProfile !== "string" || body.sandboxImageProfile.length === 0 || body.sandboxImageProfile.length > 128)) {
270
- sendError(res, 400, "request.field_invalid", "sandboxImageProfile must be a non-empty string of at most 128 characters");
344
+ if (body.sandboxImageProfile !== undefined && (typeof body.sandboxImageProfile !== "string" || body.sandboxImageProfile.length === 0 || body.sandboxImageProfile.length > MAX_SANDBOX_IMAGE_PROFILE_CHARS)) {
345
+ sendError(res, 400, "request.field_invalid", "sandboxImageProfile must be a non-empty string of at most 128 characters", overCharsFacts("sandboxImageProfile", body.sandboxImageProfile, MAX_SANDBOX_IMAGE_PROFILE_CHARS));
271
346
  return null;
272
347
  }
273
348
  if (body.capabilitiesNeeded !== undefined && (!Array.isArray(body.capabilitiesNeeded) || body.capabilitiesNeeded.some((c) => typeof c !== "string"))) {
@@ -275,11 +350,11 @@ export function createAdmission(ctx) {
275
350
  return null;
276
351
  }
277
352
  if (Array.isArray(body.capabilitiesNeeded) && body.capabilitiesNeeded.length > 0 && (typeof body.sandboxImageProfile !== "string" || body.sandboxImageProfile.length === 0)) {
278
- sendError(res, 400, "request.field_conflict", "capabilitiesNeeded requires sandboxImageProfile (it constrains the selected image)");
353
+ sendError(res, 400, "request.field_conflict", "capabilitiesNeeded requires sandboxImageProfile (it constrains the selected image)", fieldConflictFacts("image_profile", ["capabilitiesNeeded", "sandboxImageProfile"]));
279
354
  return null;
280
355
  }
281
356
  if (typeof body.sandboxImageProfile === "string" && body.sandboxImageProfile.length > 0 && (body.cascade === true || body.verify === true)) {
282
- sendError(res, 400, "request.field_conflict", "sandboxImageProfile is not supported together with cascade/verify in v1 (the per-task image would not bind to the cascade rungs / verifier sub-run)");
357
+ sendError(res, 400, "request.field_conflict", "sandboxImageProfile is not supported together with cascade/verify in v1 (the per-task image would not bind to the cascade rungs / verifier sub-run)", fieldConflictFacts("cascade_verify", ["sandboxImageProfile", ...multiAttemptFields(body)]));
283
358
  return null;
284
359
  }
285
360
  if (body.outputSchema !== undefined) {
@@ -287,8 +362,9 @@ export function createAdmission(ctx) {
287
362
  sendError(res, 400, "request.field_invalid", "outputSchema must be a JSON Schema object");
288
363
  return null;
289
364
  }
290
- if (JSON.stringify(body.outputSchema).length > MAX_OUTPUT_SCHEMA_CHARS) {
291
- sendError(res, 400, "request.field_invalid", `outputSchema must serialize to at most ${MAX_OUTPUT_SCHEMA_CHARS} characters`);
365
+ const schemaChars = JSON.stringify(body.outputSchema).length;
366
+ if (schemaChars > MAX_OUTPUT_SCHEMA_CHARS) {
367
+ sendError(res, 400, "request.field_invalid", `outputSchema must serialize to at most ${MAX_OUTPUT_SCHEMA_CHARS} characters`, limitFacts("outputSchema", "characters", schemaChars, MAX_OUTPUT_SCHEMA_CHARS));
292
368
  return null;
293
369
  }
294
370
  }
@@ -297,12 +373,12 @@ export function createAdmission(ctx) {
297
373
  return null;
298
374
  }
299
375
  if (body.resumeAt !== undefined) {
300
- if (typeof body.resumeAt !== "string" || body.resumeAt.length === 0 || body.resumeAt.length > 64) {
301
- sendError(res, 400, "request.field_invalid", "resumeAt must be a non-empty message eventId string (≤64 chars)");
376
+ if (typeof body.resumeAt !== "string" || body.resumeAt.length === 0 || body.resumeAt.length > MAX_RESUME_AT_CHARS) {
377
+ sendError(res, 400, "request.field_invalid", "resumeAt must be a non-empty message eventId string (≤64 chars)", overCharsFacts("resumeAt", body.resumeAt, MAX_RESUME_AT_CHARS));
302
378
  return null;
303
379
  }
304
380
  if (body.verify === true || body.cascade === true) {
305
- sendError(res, 400, "request.field_conflict", "resumeAt is not supported with verify or cascade (those start a fresh/replaced session)");
381
+ sendError(res, 400, "request.field_conflict", "resumeAt is not supported with verify or cascade (those start a fresh/replaced session)", fieldConflictFacts("cascade_verify", ["resumeAt", ...multiAttemptFields(body)]));
306
382
  return null;
307
383
  }
308
384
  }
@@ -312,7 +388,7 @@ export function createAdmission(ctx) {
312
388
  return null;
313
389
  }
314
390
  if (body.resumeAt === undefined) {
315
- sendError(res, 400, "request.field_conflict", "resumeAtMode requires resumeAt (it qualifies the rewind target)");
391
+ sendError(res, 400, "request.field_conflict", "resumeAtMode requires resumeAt (it qualifies the rewind target)", fieldConflictFacts("resume_anchor", ["resumeAtMode", "resumeAt"]));
316
392
  return null;
317
393
  }
318
394
  }
@@ -363,7 +439,7 @@ export function createAdmission(ctx) {
363
439
  }
364
440
  }
365
441
  if (fileHistoryRestoreConflict(body)) {
366
- sendError(res, 400, "request.field_conflict", FILE_HISTORY_DISABLED_NO_RESTORE);
442
+ sendError(res, 400, "request.field_conflict", FILE_HISTORY_DISABLED_NO_RESTORE, fieldConflictFacts("file_history_restore", ["fileHistory", ...fileHistoryRestoreKeysInBody(body)]));
367
443
  return null;
368
444
  }
369
445
  if (body.requireExistingSession !== undefined && typeof body.requireExistingSession !== "boolean") {
@@ -461,7 +537,7 @@ export function createAdmission(ctx) {
461
537
  if (body.agents !== undefined) {
462
538
  const agentsErr = validateTaskAgents(body.agents);
463
539
  if (agentsErr) {
464
- sendError(res, 400, "request.field_invalid", agentsErr);
540
+ sendError(res, 400, "request.field_invalid", agentsErr.message, agentsErr.facts);
465
541
  return null;
466
542
  }
467
543
  const agentsBare = deps.config.models ?? {};
@@ -470,7 +546,7 @@ export function createAdmission(ctx) {
470
546
  if (um !== undefined && refuseUnavailableModel(res, deps.config, `agents[${um.index}].model`, um.ref))
471
547
  return null;
472
548
  if (um !== undefined) {
473
- sendError(res, 400, "request.unknown_reference", `unknown agents[${um.index}].model "${um.ref.slice(0, 120)}" — not in the configured catalog (a catalog name or tier word)`, { available: mentionableNames(deps.config, agentsCatalog) });
549
+ sendError(res, 400, "request.unknown_reference", `unknown agents[${um.index}].model "${echoModelRef(um.ref)}" — not in the configured catalog (a catalog name or tier word)`, { available: mentionableNames(deps.config, agentsCatalog) });
474
550
  return null;
475
551
  }
476
552
  }
@@ -497,9 +573,12 @@ export function createAdmission(ctx) {
497
573
  return null;
498
574
  }
499
575
  }
500
- if (body.disableSkills === true && ((body.skills?.length ?? 0) > 0 || (body.agents ?? []).some((a) => (a.skills?.length ?? 0) > 0))) {
501
- sendError(res, 400, "request.field_conflict", "disableSkills: true means this run installs no skill at all (not the deployment's, not the request's), so it cannot come with a non-empty skills or agents[].skills — send one or the other");
502
- return null;
576
+ if (body.disableSkills === true) {
577
+ const skillSeats = [...((body.skills?.length ?? 0) > 0 ? ["skills"] : []), ...(body.agents ?? []).flatMap((a, i) => ((a.skills?.length ?? 0) > 0 ? [`agents[${i}].skills`] : []))];
578
+ if (skillSeats.length > 0) {
579
+ sendError(res, 400, "request.field_conflict", "disableSkills: true means this run installs no skill at all (not the deployment's, not the request's), so it cannot come with a non-empty skills or agents[].skills — send one or the other", fieldConflictFacts("skills_disabled", ["disableSkills", ...skillSeats]));
580
+ return null;
581
+ }
503
582
  }
504
583
  {
505
584
  const v = body.userInvokedSkills;
@@ -564,7 +643,7 @@ export function createAdmission(ctx) {
564
643
  if (matchCatalogModel(body.model, catalog, deps.config.modelRefusals) === undefined) {
565
644
  if (refuseUnavailableModel(res, deps.config, "model", body.model))
566
645
  return null;
567
- sendError(res, 400, "request.unknown_reference", `unknown model "${body.model.slice(0, 120)}" — not in the configured catalog (name, tier word, or id)`, { available: mentionableNames(deps.config, catalog) });
646
+ sendError(res, 400, "request.unknown_reference", `unknown model "${echoModelRef(body.model)}" — not in the configured catalog (name, tier word, or id)`, { available: mentionableNames(deps.config, catalog) });
568
647
  return null;
569
648
  }
570
649
  }
@@ -578,7 +657,7 @@ export function createAdmission(ctx) {
578
657
  if (matchCatalogModel(body.compactionModel, catalog, deps.config.modelRefusals) === undefined) {
579
658
  if (refuseUnavailableModel(res, deps.config, "compactionModel", body.compactionModel))
580
659
  return null;
581
- sendError(res, 400, "request.unknown_reference", `unknown compactionModel "${body.compactionModel.slice(0, 120)}" — not in the configured catalog (name, tier word, or id)`, { available: mentionableNames(deps.config, catalog) });
660
+ sendError(res, 400, "request.unknown_reference", `unknown compactionModel "${echoModelRef(body.compactionModel)}" — not in the configured catalog (name, tier word, or id)`, { available: mentionableNames(deps.config, catalog) });
582
661
  return null;
583
662
  }
584
663
  }
@@ -619,17 +698,24 @@ export function createAdmission(ctx) {
619
698
  const verify = verifyRoundsFromBody(body);
620
699
  const cascade = body.cascade === true;
621
700
  if (cascade && verify) {
622
- sendError(res, 400, "request.field_conflict", "verify and cascade are mutually exclusive (verify = adversarial gate; cascade = cheap→strong ladder)");
701
+ sendError(res, 400, "request.field_conflict", "verify and cascade are mutually exclusive (verify = adversarial gate; cascade = cheap→strong ladder)", fieldConflictFacts("cascade_verify", ["verify", "cascade"]));
623
702
  return null;
624
703
  }
625
704
  if (body.suggestNextPrompts && (verify || cascade)) {
626
- sendError(res, 400, "request.field_conflict", "suggestNextPrompts is not supported with verify or cascade (those return a result, not a streamed run)");
705
+ sendError(res, 400, "request.field_conflict", "suggestNextPrompts is not supported with verify or cascade (those return a result, not a streamed run)", fieldConflictFacts("cascade_verify", ["suggestNextPrompts", ...multiAttemptFields(body)]));
627
706
  return null;
628
707
  }
629
708
  if (cascade && deps.config.cascadeLadder.length === 0) {
630
709
  sendError(res, 400, "request.precondition_unmet", "cascade requested but no ladder configured — set MODEL_CASCADE_LADDER (catalog model names, cheapest→strongest)");
631
710
  return null;
632
711
  }
712
+ {
713
+ const refusal = requestTrustRefusal({ permissions: parseTaskSettings(body.settings).settings?.permissions, skills: body.skills, userInvokedSkills: body.userInvokedSkills }, callerTrust(req, deps.config));
714
+ if (refusal !== undefined) {
715
+ sendError(res, 400, "request.field_invalid", refusal.message, refusal.facts);
716
+ return null;
717
+ }
718
+ }
633
719
  const { body: admitted, entry: entryMode } = stampEntryPermissionMode(body, autonomyModeFloor(deps.config.autonomy));
634
720
  try {
635
721
  const auth = deps.authorize ? await deps.authorize({ req, body: admitted }) : undefined;
@@ -647,7 +733,8 @@ export function createAdmission(ctx) {
647
733
  const acceptance = createRunAcceptance({ sessionTitler: deps.sessionTitler }, { ...(spec.sessionId ? { sessionId: spec.sessionId } : {}), objective: spec.objective, ...(model !== undefined ? { model } : {}) });
648
734
  const clampNotice = buildEntryModeClampNotice(entryMode, spec.sessionId);
649
735
  const pendingNotices = clampNotice !== undefined ? [clampNotice, ...engineNotices] : engineNotices;
650
- return { spec, runner: runnerFor(spec), auth, verify, cascade, jobId: admitted.jobId, body: admitted, acceptance, ...(bindingIntent === undefined ? {} : { bindingIntent }), ...(pendingNotices.length > 0 ? { engineNotices: pendingNotices } : {}) };
736
+ const warnings = allowSelectorWarningsOf(admitted, spec.tools ?? []);
737
+ return { spec, runner: runnerFor(spec), auth, verify, cascade, jobId: admitted.jobId, body: admitted, acceptance, ...(bindingIntent === undefined ? {} : { bindingIntent }), ...(pendingNotices.length > 0 ? { engineNotices: pendingNotices } : {}), ...(warnings.length > 0 ? { warnings } : {}) };
651
738
  }
652
739
  catch (err) {
653
740
  if (err instanceof HttpError) {