@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
@@ -24,10 +24,19 @@ export class SessionIncarnationMissingError extends Error {
24
24
  this.name = "SessionIncarnationMissingError";
25
25
  }
26
26
  }
27
- export function incarnationFromCell(sessionId, cell) {
28
- if (typeof cell !== "string" || cell === "")
29
- throw new SessionIncarnationMissingError(sessionId);
30
- return cell;
27
+ export function incarnationFromCell(sessionId, cell, empty = "refuse") {
28
+ if (typeof cell === "string" && cell !== "")
29
+ return cell;
30
+ switch (empty) {
31
+ case "refuse":
32
+ throw new SessionIncarnationMissingError(sessionId);
33
+ case "absent":
34
+ return undefined;
35
+ default: {
36
+ const unknownReading = empty;
37
+ throw new Error(`incarnationFromCell: no reading ${JSON.stringify(unknownReading)}`);
38
+ }
39
+ }
31
40
  }
32
41
  export function sessionFaceFromRow(sessionId, owner, incarnation) {
33
42
  return { owner, incarnation: incarnationFromCell(sessionId, incarnation) };
@@ -40,11 +49,9 @@ export function sessionFaceReadOf(store) {
40
49
  const read = store?.sessionFaceOf;
41
50
  return typeof read === "function" ? read.bind(store) : undefined;
42
51
  }
43
- export function carriedIncarnation(prior, owner) {
44
- if (prior !== undefined && (prior.owner ?? null) === owner && typeof prior.incarnation === "string" && prior.incarnation !== "") {
45
- return prior.incarnation;
46
- }
47
- return mintSessionIncarnation();
52
+ export function carriedIncarnation(sessionId, prior, owner) {
53
+ const held = prior !== undefined && (prior.owner ?? null) === owner ? incarnationFromCell(sessionId, prior.incarnation, "absent") : undefined;
54
+ return held ?? mintSessionIncarnation();
48
55
  }
49
56
  export const SESSION_META_INCARNATION_COLUMN = {
50
57
  name: "incarnation",
@@ -0,0 +1,33 @@
1
+ /**
2
+ * **会话标题帧 `session_titled`** —— 标题器把标题写进会话行**之后**,在**这条 run 的活流**上自铸的一帧(契约 §4a-ttl)。
3
+ *
4
+ * ## 为什么有这一帧
5
+ * 标题器是 fire-and-forget:run 被引擎受理之后才起、在 run 跑的同时生成,写成时那条 run 的流往往还开着。此前写成只落行
6
+ * (`setTitleIfNull`)+ 一行运维日志 —— wire 上零通知,端上(桌面 / web 座位)只能在首轮之后有界轮询读会话行。
7
+ * 这一帧把「标题写成了」交给已经在 tail 这条流的人,轮询可以删。
8
+ *
9
+ * ## 律(一条)
10
+ * **只活不存**:会话行是标题的唯一真源,本帧只是「行刚刚变了」的活通知 —— 不落账本(`GET /v1/runs/:id/events` 回放读不出它)、
11
+ * 不进任何重放面;冷启动 / 多窗口 / 断线重连读会话行(`GET /v1/sessions` 的列表行 `title`;`/v1/sessions/:id/head` 只带 `leafId`,不是标题的读面)。因此:
12
+ * · 读者 = **这条 run 的流读者**,与会话行的读权同一(流是提交这条 run 的人开的,会话行归同一个人);
13
+ * · 只有持活流的腿才收得到(今天 = `POST /v1/tasks/stream`);同步 JSON 腿 / durable 后台腿没有活流 ⇒ 这一帧结构上不存在,读行;
14
+ * · 流已经走到终帧(`done`)或连接已断 ⇒ 丢弃(终帧是流的最后一帧);
15
+ * · `PATCH /v1/sessions/:id` 的改名 / 置顶不经标题器 ⇒ 不发(调用方自知);用户清空标题后下一次提交由标题器重填,那一次重填照发(例外:本进程里此前为这个会话生成失败 / 回空过 —— 标题器不再为它重试,直到进程重启)。
16
+ *
17
+ * ## 谁铸
18
+ * 唯一铸点 = {@link buildSessionTitledFrame},唯一调用方 = `session-titler.ts`(落行成功的那一支,实参 = 落进行里的**同一个**标题 ——
19
+ * 已脱敏、已清洗;帧上的标题与行上的标题是一个值,不从模型原文另铸)。键集登记在 `trace/self-minted-wire.ts` 的 `sessionTitledFrameKey`
20
+ * (成员集 `satisfies Record<keyof SessionTitledFrame, …>`:加一个键而登记没跟 ⇒ tsc 红)。
21
+ *
22
+ * 帧上没有 `eventId` ⇒ SSE 不发 `id:` 行(契约 §0.6「无锚不发行」):它不是引擎的内容帧,没有续流位置可言。
23
+ */
24
+ /** 标题帧的形 —— 键集就是这个接口的键(登记表按 `keyof` 绑定)。 */
25
+ export interface SessionTitledFrame {
26
+ readonly type: "session_titled";
27
+ readonly sessionId: string;
28
+ /** 落进会话行的那个标题(已过标题器的脱敏与清洗,≤ `TITLE_MAX_CHARS` 个字符)。 */
29
+ readonly title: string;
30
+ }
31
+ /** 唯一铸点:纯数据,无行为。 */
32
+ export declare function buildSessionTitledFrame(sessionId: string, title: string): SessionTitledFrame;
33
+ //# sourceMappingURL=session-titled-frame.d.ts.map
@@ -0,0 +1,4 @@
1
+ export function buildSessionTitledFrame(sessionId, title) {
2
+ return { type: "session_titled", sessionId, title };
3
+ }
4
+ //# sourceMappingURL=session-titled-frame.js.map
@@ -13,6 +13,11 @@
13
13
  * cheap-model one-liner via the deployment's hookLlm face (summarize role → MODEL_CHEAP_ID when configured, else the
14
14
  * main model; bounded + timed out).
15
15
  *
16
+ * WRITE-AFTER NOTICE: the title that lands is announced to the run that triggered it — `maybeTitle`'s `onTitled` hands the
17
+ * seat (`run-acceptance.ts`) the one `session_titled` frame (`session-titled-frame.ts`, contract §4a-ttl) built from the
18
+ * SAME string the row now holds; the seat forwards it to the live stream when the leg has one. Live-only: the row is the
19
+ * truth, nothing else stores the frame.
20
+ *
16
21
  * FAILURE POSTURE: everything is best-effort — a generation/store failure logs and leaves title null (the
17
22
  * list falls back to objectivePreview). The fail-open tag it leaves names the CAUSE FAMILY (one tag, one family):
18
23
  * the llm face's failure CODE picks it (`failOpenTagFor`), never the error's wording. An in-process pending set dedupes concurrent submits on the same
@@ -20,6 +25,7 @@
20
25
  * call at worst, and exactly one title lands).
21
26
  */
22
27
  import type { HookLlmFailureCode } from "./hooks/hook-runner.js";
28
+ import { type SessionTitledFrame } from "./session-titled-frame.js";
23
29
  export interface SessionTitlerDeps {
24
30
  /** Secret scrub applied to the RAW llm text before sanitize/persist (workflow audit 2026-07-13: the
25
31
  * objective may carry a pasted secret and the model can echo it into the title — titles are persisted,
@@ -58,7 +64,9 @@ export interface SessionTitlerDeps {
58
64
  export interface SessionTitler {
59
65
  /** Fire-and-forget: maybe generate + persist a title for this session. Never throws, never blocks the caller. */
60
66
  /** `model`([ref]②)= 本 turn 真实驱动的模型——带上则标题 hook 同链路,不再裸落 env 缺省。 */
61
- maybeTitle(sessionId: string, objective: string, model?: string): void;
67
+ /** `onTitled` = 这一次调用**自己**把标题写成之后(`setTitleIfNull` 落行)交出的活通知(`session_titled` 帧,契约 §4a-ttl):只在落行的那一支调用恰一次 ——
68
+ * 已有标题 / 竞态输了 / 模型失败 / 空标题 / 这个会话已有一次在飞的调用,都不调。回调同步执行、**不许抛**;抛了也不影响已落行的标题(见下 `frame_failed`)。 */
69
+ maybeTitle(sessionId: string, objective: string, model?: string, onTitled?: (frame: SessionTitledFrame) => void): void;
62
70
  }
63
71
  export declare const TITLE_MAX_CHARS = 80;
64
72
  /** Single line, control chars stripped, hard cap; surrounding quotes (a common LLM tic) trimmed. */
@@ -1,7 +1,8 @@
1
- import { CONTROL_AND_BIDI_STRIP_RE } from "./text-bidi.js";
1
+ import { stripControlAndBidi } from "@sema-agent/settings-schema";
2
2
  import { recordFailOpen } from "./observability/fail-open.js";
3
3
  import { redactSecrets } from "./trace/redact.js";
4
4
  import { userAuthoredText } from "./user-authored-text.js";
5
+ import { buildSessionTitledFrame } from "./session-titled-frame.js";
5
6
  export const TITLE_MAX_CHARS = 80;
6
7
  const OBJECTIVE_SNIPPET_CHARS = 600;
7
8
  const LLM_TIMEOUT_MS = 15_000;
@@ -10,16 +11,26 @@ const FAIL_CAUSE_KEY_CHARS = 80;
10
11
  const SEEN_CAP = 10_000;
11
12
  function failOpenTagFor(code) {
12
13
  switch (code) {
14
+ case "model_unresolved":
15
+ return "server.session-titler.model-unresolved";
16
+ case "route_refused":
17
+ return "server.session-titler.route-refused";
18
+ case "credential_custody_failed":
19
+ return "server.session-titler.credential-custody-failed";
13
20
  case "redirect_refused":
14
21
  return "server.session-titler.redirect-refused";
22
+ case "bad_response":
23
+ return "server.session-titler.bad-response";
15
24
  case "no_content":
16
- case "hard_timeout":
17
- case undefined:
25
+ return "server.session-titler.no-content";
26
+ case "unreachable":
18
27
  return "server.session-titler.gateway-unreachable";
28
+ case undefined:
29
+ return "server.session-titler.unclassified";
19
30
  }
20
31
  }
21
32
  export function sanitizeTitle(raw) {
22
- const oneLine = raw.replace(/[\r\n]+/g, " ").replace(CONTROL_AND_BIDI_STRIP_RE, "").trim();
33
+ const oneLine = stripControlAndBidi(raw.replace(/[\r\n]+/g, " ")).trim();
23
34
  const unquoted = oneLine.replace(/^["'「『]+/, "").replace(/["'」』]+$/, "").trim();
24
35
  return unquoted.length > TITLE_MAX_CHARS ? `${unquoted.slice(0, TITLE_MAX_CHARS - 1)}…` : unquoted;
25
36
  }
@@ -35,8 +46,9 @@ export function buildTitlePrompt(objective) {
35
46
  }
36
47
  export function createSessionTitler(deps) {
37
48
  const seen = new Set();
49
+ const redactedError = (error) => redactSecrets(error);
38
50
  const logFailure = (sessionId, error, code) => {
39
- const safe = redactSecrets(error);
51
+ const safe = redactedError(error);
40
52
  deps.logger?.debug?.("session_title_failed", { sessionId, error: safe.slice(0, 200) });
41
53
  recordFailOpen(failOpenTagFor(code), safe.slice(0, FAIL_CAUSE_KEY_CHARS));
42
54
  };
@@ -45,7 +57,7 @@ export function createSessionTitler(deps) {
45
57
  .then((state) => ({ state, unreadable: false }))
46
58
  .catch(() => ({ state: continueWord, unreadable: true }));
47
59
  return {
48
- maybeTitle(sessionId, objective, model) {
60
+ maybeTitle(sessionId, objective, model, onTitled) {
49
61
  if (!sessionId || !userAuthoredText(objective))
50
62
  return;
51
63
  if (seen.has(sessionId))
@@ -94,6 +106,15 @@ export function createSessionTitler(deps) {
94
106
  seen.delete(sessionId);
95
107
  deps.metrics?.inc("session_title_total", { outcome: "set" });
96
108
  deps.logger?.info?.("session_titled", { sessionId, titleChars: title.length });
109
+ if (onTitled) {
110
+ try {
111
+ onTitled(buildSessionTitledFrame(sessionId, title));
112
+ }
113
+ catch (e) {
114
+ deps.metrics?.inc("session_title_total", { outcome: "frame_failed" });
115
+ deps.logger?.warn?.("session_titled_frame_failed", { sessionId, error: redactedError(String(e)).slice(0, 200) });
116
+ }
117
+ }
97
118
  })().catch((e) => {
98
119
  deps.metrics?.inc("session_title_total", { outcome: "error" });
99
120
  logFailure(sessionId, String(e));
@@ -4,6 +4,7 @@
4
4
  * body WITHOUT the HTTP-layer 400 validation, so a malformed value must fall back to a safe default, never throw.
5
5
  */
6
6
  import { type AgentDefinition, type TaskSpec } from "@sema-agent/core";
7
+ import { type LimitFacts, type LimitMeasure } from "./limit-refusal.js";
7
8
  /**
8
9
  * E12 — normalize `body.suggestNextPrompts` → `TaskSpec.suggestNextPrompts`. `true` = on with core defaults
9
10
  * (count 3, cheap role); an object tunes `count` (clamped 1..10) / `role` (a free string — core validates it against
@@ -51,25 +52,38 @@ export declare const MAX_TASK_AGENTS = 32;
51
52
  * `ruleEntryListShapeOk`):引擎直接 `for (const entry of list)` —— 一个裸字符串 `"Bash"` 会被逐字符迭代成 `B` / `a` / `s` / `h` 四条
52
53
  * (deny 侧 = 意图静默落空,安全轴上的放宽方向)。条目的**文法与名字**是引擎的读法:允侧读不出的条目(`*` / 写路径 / 域名 / 退役名 …)引擎在开跑时发
53
54
  * `permission.allowed_tool_not_granted`(受众 = 用户);拒侧读成空的条目(文法或名字层)在 `resolveSpec` 拒(提交 400 / 续跑 409,`rule-entry-list.ts` 的
54
- * `inertToolListEntryOf`,判据 = 引擎的条目读法;同一只函数也拒请求的工具名选择器清单里的近似名 / 退役名)。形对之后两道门再问 {@link skillToolListRefusal}(条数帽 ⇒ 400)。
55
- * 条数帽 = 条目表那一只(`rule-entry-list.ts` `allowLayerEntryCountIssue`,准备开销的界;与请求 allow 桶、运维表同一只),
56
- * 在 {@link skillToolListRefusal} 里判;无长度帽([ref])。
55
+ * `inertToolListEntryOf`,判据 = 引擎的条目读法;同一只函数也拒请求的工具名选择器清单里的近似名 / 退役名)。
56
+ * **条数帽**是全部工具名清单的同一只判(`rule-entry-list.ts` 的 `skillToolListsOverCap`;句子与机读位 `field` 点体内坐标 `skills[1].allowedTools` /
57
+ * `agents[0].skills[2].disallowedTools`):顶层 `validateUserSkills` 与子代 {@link validateTaskAgents} 两道门都逐条先形、后帽(与 7.131.0 的拒点与判序同);
58
+ * 拒点 `resolveSpec` 两腿同经的 `inertToolListEntryOf` 先过同一只判;无长度帽([ref])。
57
59
  */
58
60
  export declare const skillToolListOk: (v: unknown) => v is readonly string[];
59
61
  /**
60
- * 一条技能(形已过两道门的字符串数组判)的两只清单在受理口的拒因 —— 都过 ⇒ `undefined`。两处受理口同调:顶层 `skills[]`
61
- * (`http/admission.ts` 的 `validateUserSkills`)、子代 `agents[].skills[]`({@link validateTaskAgents})。一问:条数帽。退役名 / 对端段或工具段铸不出、为空 /
62
- * 读成空的条目是引擎的读法(见上):允侧交引擎通告,拒侧由 `resolveSpec` 拒(7.116.0–7.122.x 本仓在这里另拒工具段为空的协议名,core 7.48.0 #1400 起
63
- * 它是引擎判官的判词,随之退役)。
62
+ * 一条子代定义的裁决:`message` = 一句可 400 的英文(不带下标,调用方加);撞帽时另带 `limit`(`rel` = 相对这条定义的坐标 `allowTools[3]` / `name`),
63
+ * 句子是撞帽的头一句(`agent.allowTools[3] has 129 characters — at most 128 are accepted`:撞了哪一条帽、送来多少、帽多少),
64
+ * {@link validateTaskAgents} 把它铸成体内坐标的机读位(`field: "agents[0].allowTools[3]"`)。
64
65
  */
65
- export declare function skillToolListRefusal(skill: Record<string, unknown>): string | undefined;
66
+ export interface TaskAgentIssue {
67
+ readonly message: string;
68
+ readonly limit?: {
69
+ readonly rel: string;
70
+ readonly measure: LimitMeasure;
71
+ readonly count: number;
72
+ readonly cap: number;
73
+ };
74
+ }
75
+ /** 提交体 `agents` 的拒:句子(带下标)+ 撞帽时的机读位(`field` / `reason` / `count` / `cap`,`limit-refusal.ts` 一处铸)。 */
76
+ export interface TaskAgentsRefusal {
77
+ readonly message: string;
78
+ readonly facts?: LimitFacts;
79
+ }
66
80
  /** [ref] 单条 agent 定义的形状裁决:null=合法;否则一句可 400 的英文错误(不带索引,调用方自己加)。
67
81
  * 白名单外键 fail-loud —— 与 resilience/limits 的「容忍未知键」相反:agents 是能力定义,静默丢字段 =
68
82
  * 定义被悄悄削(一个丢掉的 isolation 就是放宽),比 400 更危险,故整条拒。`allowTools` / `denyTools` 本门只判形与条数(`toolList`),
69
83
  * **名字归引擎一只判**(core 7.49.0 #1623 / #1433 第二步起与根 run 的 `allowTools` / `excludeTools` 是同一只选择器,开跑前,三来源同判):core 7.51.0 #1736 起
70
84
  * 没有任何工具答应的名字(无人挂的名、大小写孪生 / 退役名 `bash` / `BASH`)**引擎不拒 run** —— 条目原样保留、经 onError(config)告知一次(带该写的拼法);
71
85
  * 其中**写错现名的**(`denyTools:["BASH"]` 想禁的照用 = 静默放行;`allowTools:["BASH"]` 想放的什么也没放 = 静默收窄)由 `resolveSpec` 前置拒:**限制侧**(`denyTools`)四类全拒(近似名 · 退役名 · 文法读不出 · `*`),
72
- * **放行侧**(`allowTools`)只拒近似名 —— 放行侧的退役名 / 内容形 / 文法读不出照 7.130.0 受理、交引擎既有通告(文法读不出的放行条目引擎在子代 prepare 整 run 拒 `config.agent.unknown_tool`,根 `allowTools` 同步腿 400 `config.tool_face_control`;`rule-entry-list.ts` `inertToolListEntryOf`:近似名提交 400 `config.agent.unknown_tool` 点名现名、续跑按方向分流;
86
+ * **放行侧**(`allowTools`)只拒近似名 —— 放行侧的内容形 / 没有后继的退役名 / 文法读不出照 7.130.0 受理、交引擎既有通告(有后继的退役名〔`bash` · `Task`〕与文法读不出的放行条目引擎在子代 prepare 整 run 拒 `config.agent.unknown_tool`,根 `allowTools` 拒 `config.tool_face_control`,同步腿两码同为 400〔`runs.ts` `PREPARE_REFUSAL_HTTP_STATUS`〕;`rule-entry-list.ts` `inertToolListEntryOf`:近似名提交 400 `config.agent.unknown_tool` 点名现名、续跑按方向分流;
73
87
  * 判官仍是引擎的条目读法,不是第二个判官);
74
88
  * **真未知名**(没有近似也没有退役对应:懒挂载的合法形)照旧只告运维、不拒。
75
89
  * 任何工具名都不可能有的拼法(`grammar`)与非字符串条目引擎照旧整 run 拒 `config.agent.unknown_tool` —— 主车道的委派工具带 extraTools 工厂,本仓在同一处
@@ -79,11 +93,11 @@ export declare function skillToolListRefusal(skill: Record<string, unknown>): st
79
93
  * 本门不做名字对照(拒侧的那一判在 `resolveSpec`,见上;本门只判形与条数)。
80
94
  * ⚠️ 键判断必须 Object.hasOwn:`in` 走原型链,JSON 里的 "toString"/"constructor"/"__proto__" 键会被
81
95
  * 误判为白名单字段,随后 SHAPES[k].ok 不是函数 ⇒ TypeError(fresh 500 / resume 砖;cross-review 复现)。 */
82
- export declare function taskAgentIssue(item: unknown): string | null;
96
+ export declare function taskAgentIssue(item: unknown): TaskAgentIssue | null;
83
97
  /** [ref] HTTP 门(fresh submit,server.ts prepareSpec):body.agents 在场必须是非空数组、每条过
84
98
  * {@link taskAgentIssue}、name 数组内唯一、条数 ≤ {@link MAX_TASK_AGENTS}。返回 400 错误串或 null。
85
99
  * RESUME 重放不过这道门 —— {@link taskAgentsFromBody} defensive(按条 DROP+warn,不砖 resume)。 */
86
- export declare function validateTaskAgents(v: unknown): string | null;
100
+ export declare function validateTaskAgents(v: unknown): TaskAgentsRefusal | null;
87
101
  /** [ref] body.agents → `TaskSpec.agents`(resolveSpec 的唯一装配点;main.ts 只 spread)。两层门:
88
102
  * - 🔒 TOB 租户门:多租户(requirePrincipal===true)暂不放行 —— [ref] 原文「TOB 面按租户 caps 门」,
89
103
  * 当前没有 per-tenant caps 面可挂,先 fail-closed 关多租(warn `task_agents_ignored`,capabilities
@@ -135,8 +149,6 @@ export declare function retainBackgroundProcessesFromBody(raw: unknown, requireP
135
149
  * DEFENSIVE(resume 重放不过 HTTP 400 门):非数组 ⇒ undefined;项非非空字符串 ⇒ 逐项 DROP;空数组 ⇒
136
150
  * undefined(不挂键=core 缺省,byte-compat)。HTTP 门另有 fail-loud 400(提交面邻居姿势)。 */
137
151
  export declare function toolNameListFromBody(raw: unknown): string[] | undefined;
138
- /** 引擎从哪一版起认 `TaskSpec.allowTools`(core 7.49.0 #1623,[ref])。 */
139
- export declare const ALLOW_TOOLS_MIN_ENGINE = "7.49.0";
140
152
  /**
141
153
  * S-1448(core 7.49.0 #1623 / [ref])—— body.allowTools → `TaskSpec.allowTools`:引擎的**可用性选择器**,原样透传。
142
154
  *
@@ -145,10 +157,10 @@ export declare const ALLOW_TOOLS_MIN_ENGINE = "7.49.0";
145
157
  * `config.tool_face_control`)、不与 allow 层 `allowedTools`(免问)混词。受理门只判 wire 形(与 `excludeTools` / `deferTools` 同一只门)。
146
158
  * 续跑重放同经此处:存量体逐字再投,坏形交引擎拒(收窄键丢了 = 放宽,所以不 DROP)。
147
159
  *
148
- * 装着的引擎不认该座(< {@link ALLOW_TOOLS_MIN_ENGINE})⇒ **响亮拒** 400 `request.field_invalid`(点名键、所需版本与装着的版本),
149
- * 不静默丢。`engineVersion` 缺省读装着的 core(`CORE_ENGINE_VERSION`);测试传假低版。
160
+ * **没有引擎版本臂**:core 精确钉在认这个座(7.49.0 起)的版本之上,「装着的引擎不认该座」在生产里不可达;「core 至少是哪一版」是依赖下限门
161
+ * 的事实(`test/core-dependency-floor.test.ts` + `test/helpers/core-floor.ts`),不是本函数运行期的比对(一个事实一只源)。
150
162
  */
151
- export declare function allowToolsSpecFragment(raw: unknown, engineVersion?: string): {
163
+ export declare function allowToolsSpecFragment(raw: unknown): {
152
164
  allowTools?: string[];
153
165
  };
154
166
  /** [ref]/[ref] — body.promptProfile → `TaskSpec.promptProfile`(core 1.328 R2 主件,CC LT(model_id)
@@ -1,9 +1,9 @@
1
1
  import { isThinkingLevel } from "@sema-agent/core";
2
2
  import { taskWallClockSec } from "./task-workflow.js";
3
- import { isAbsoluteHostPath } from "@sema-agent/settings-schema";
4
- import { CORE_ENGINE_VERSION } from "./prompts-domain-validate.js";
5
- import { createCodedHttpError } from "./security.js";
6
- import { allowLayerEntryCountIssue, ruleEntryListShapeOk } from "./rule-entry-list.js";
3
+ import { ABSOLUTE_HOST_PATH_MAX, isAbsoluteHostPath } from "@sema-agent/settings-schema";
4
+ import { ruleEntryListShapeOk, skillToolListsOverCap } from "./rule-entry-list.js";
5
+ import { describeLimit, limitFacts, limitRefusal } from "./limit-refusal.js";
6
+ import { quotedCallerText } from "./caller-text-echo.js";
7
7
  export function normalizeSuggestNextPrompts(v) {
8
8
  if (v === true)
9
9
  return true;
@@ -67,20 +67,19 @@ const boundedString = (max) => (v) => typeof v === "string" && v.length <= max;
67
67
  const toolList = (v) => Array.isArray(v) &&
68
68
  v.length <= MAX_AGENT_TOOLS &&
69
69
  v.every((x) => typeof x === "string" && x.length > 0 && x.length <= MAX_AGENT_TOOL_NAME_CHARS);
70
+ const charLimit = (max) => (v) => typeof v === "string" && v.length > max ? { sub: "", measure: "characters", count: v.length, cap: max } : undefined;
71
+ const toolListLimit = (v) => {
72
+ if (!Array.isArray(v))
73
+ return undefined;
74
+ if (v.length > MAX_AGENT_TOOLS)
75
+ return { sub: "", measure: "entries", count: v.length, cap: MAX_AGENT_TOOLS };
76
+ if (!v.every((x) => typeof x === "string" && x.length > 0))
77
+ return undefined;
78
+ const j = v.findIndex((x) => x.length > MAX_AGENT_TOOL_NAME_CHARS);
79
+ return j < 0 ? undefined : { sub: `[${j}]`, measure: "characters", count: v[j].length, cap: MAX_AGENT_TOOL_NAME_CHARS };
80
+ };
70
81
  const plainObject = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
71
82
  export const skillToolListOk = ruleEntryListShapeOk;
72
- const SKILL_TOOL_LISTS = ["allowedTools", "disallowedTools"];
73
- export function skillToolListRefusal(skill) {
74
- for (const key of SKILL_TOOL_LISTS) {
75
- const list = skill[key];
76
- if (!ruleEntryListShapeOk(list))
77
- continue;
78
- const over = allowLayerEntryCountIssue(`skill.${key}`, list);
79
- if (over !== undefined)
80
- return over.message;
81
- }
82
- return undefined;
83
- }
84
83
  const skillFilesOk = (v) => Array.isArray(v) &&
85
84
  v.every((f) => plainObject(f) && typeof f.path === "string" && f.path.length > 0 && typeof f.content === "string");
86
85
  const SKILL_FIELD_SHAPES = {
@@ -111,6 +110,23 @@ const skillOk = (s) => {
111
110
  }
112
111
  return true;
113
112
  };
113
+ const skillsLimit = (v) => {
114
+ if (!Array.isArray(v))
115
+ return undefined;
116
+ const j = v.findIndex((s) => !skillOk(s));
117
+ const s = j < 0 ? undefined : v[j];
118
+ if (!plainObject(s))
119
+ return undefined;
120
+ const content = s["content"];
121
+ const baseDir = s["baseDir"];
122
+ if (typeof content === "string" && content.length > MAX_AGENT_SKILL_CONTENT_CHARS) {
123
+ return { sub: `[${j}].content`, measure: "characters", count: content.length, cap: MAX_AGENT_SKILL_CONTENT_CHARS, keepShapeSentence: true };
124
+ }
125
+ if (typeof baseDir === "string" && baseDir.length > ABSOLUTE_HOST_PATH_MAX) {
126
+ return { sub: `[${j}].baseDir`, measure: "characters", count: baseDir.length, cap: ABSOLUTE_HOST_PATH_MAX, keepShapeSentence: true };
127
+ }
128
+ return undefined;
129
+ };
114
130
  const memoryOk = (v) => {
115
131
  if (!plainObject(v))
116
132
  return false;
@@ -132,14 +148,16 @@ const TASK_AGENT_FIELD_SHAPES = {
132
148
  name: {
133
149
  desc: `a non-empty string of at most ${MAX_AGENT_NAME_CHARS} characters`,
134
150
  ok: (v) => typeof v === "string" && v.length > 0 && v.length <= MAX_AGENT_NAME_CHARS,
151
+ limit: charLimit(MAX_AGENT_NAME_CHARS),
135
152
  },
136
- whenToUse: { desc: `a string of at most ${MAX_AGENT_TEXT_CHARS} characters`, ok: boundedString(MAX_AGENT_TEXT_CHARS) },
137
- whenToUseLean: { desc: `a string of at most ${MAX_AGENT_TEXT_CHARS} characters`, ok: boundedString(MAX_AGENT_TEXT_CHARS) },
138
- allowTools: { desc: `an array of at most ${MAX_AGENT_TOOLS} non-empty strings of at most ${MAX_AGENT_TOOL_NAME_CHARS} characters each`, ok: toolList },
139
- denyTools: { desc: `an array of at most ${MAX_AGENT_TOOLS} non-empty strings of at most ${MAX_AGENT_TOOL_NAME_CHARS} characters each`, ok: toolList },
153
+ whenToUse: { desc: `a string of at most ${MAX_AGENT_TEXT_CHARS} characters`, ok: boundedString(MAX_AGENT_TEXT_CHARS), limit: charLimit(MAX_AGENT_TEXT_CHARS) },
154
+ whenToUseLean: { desc: `a string of at most ${MAX_AGENT_TEXT_CHARS} characters`, ok: boundedString(MAX_AGENT_TEXT_CHARS), limit: charLimit(MAX_AGENT_TEXT_CHARS) },
155
+ allowTools: { desc: `an array of at most ${MAX_AGENT_TOOLS} non-empty strings of at most ${MAX_AGENT_TOOL_NAME_CHARS} characters each`, ok: toolList, limit: toolListLimit },
156
+ denyTools: { desc: `an array of at most ${MAX_AGENT_TOOLS} non-empty strings of at most ${MAX_AGENT_TOOL_NAME_CHARS} characters each`, ok: toolList, limit: toolListLimit },
140
157
  skills: {
141
158
  desc: "an array of { name, description, content } skill objects (optional allowedTools/disallowedTools/files/baseDir; allowedTools/disallowedTools are arrays of strings; files entries need { path, content }; baseDir must be an absolute path with no \"..\" segment) — no count cap; the engine renders the listing within its own byte budget",
142
159
  ok: (v) => Array.isArray(v) && v.every(skillOk),
160
+ limit: skillsLimit,
143
161
  },
144
162
  background: { desc: "a boolean", ok: (v) => typeof v === "boolean" },
145
163
  isolation: { desc: '"worktree"', ok: (v) => v === "worktree" },
@@ -149,57 +167,65 @@ const TASK_AGENT_FIELD_SHAPES = {
149
167
  (plainObject(v) && typeof v.id === "string" && v.id.length > 0),
150
168
  },
151
169
  thinking: { desc: "a thinking level (off/minimal/low/medium/high/xhigh/max)", ok: (v) => isThinkingLevel(v) },
152
- systemPrompt: { desc: `a string of at most ${MAX_AGENT_SYSTEM_PROMPT_CHARS} characters`, ok: boundedString(MAX_AGENT_SYSTEM_PROMPT_CHARS) },
170
+ systemPrompt: { desc: `a string of at most ${MAX_AGENT_SYSTEM_PROMPT_CHARS} characters`, ok: boundedString(MAX_AGENT_SYSTEM_PROMPT_CHARS), limit: charLimit(MAX_AGENT_SYSTEM_PROMPT_CHARS) },
153
171
  maxTurns: {
154
172
  desc: `a positive integer of at most ${MAX_AGENT_MAX_TURNS}`,
155
173
  ok: (v) => typeof v === "number" && Number.isInteger(v) && v >= 1 && v <= MAX_AGENT_MAX_TURNS,
156
174
  },
157
175
  memory: { desc: "a memory spec object ({ scopes?, writeScope?, enabled?, scopeContract? })", ok: memoryOk },
158
- observer: { desc: `a string of at most ${MAX_AGENT_TEXT_CHARS} characters`, ok: boundedString(MAX_AGENT_TEXT_CHARS) },
159
- observerMessage: { desc: `a string of at most ${MAX_AGENT_TEXT_CHARS} characters`, ok: boundedString(MAX_AGENT_TEXT_CHARS) },
176
+ observer: { desc: `a string of at most ${MAX_AGENT_TEXT_CHARS} characters`, ok: boundedString(MAX_AGENT_TEXT_CHARS), limit: charLimit(MAX_AGENT_TEXT_CHARS) },
177
+ observerMessage: { desc: `a string of at most ${MAX_AGENT_TEXT_CHARS} characters`, ok: boundedString(MAX_AGENT_TEXT_CHARS), limit: charLimit(MAX_AGENT_TEXT_CHARS) },
160
178
  };
161
179
  export function taskAgentIssue(item) {
162
180
  if (item === null || typeof item !== "object" || Array.isArray(item))
163
- return "each agent must be an object";
181
+ return { message: "each agent must be an object" };
164
182
  const rec = item;
165
183
  for (const k of Object.keys(rec)) {
166
184
  if (k === "permissionMode")
167
- return 'agent "permissionMode" is not accepted (deliberately excluded from the per-task agent contract)';
185
+ return { message: 'agent "permissionMode" is not accepted (deliberately excluded from the per-task agent contract)' };
168
186
  if (!Object.hasOwn(TASK_AGENT_FIELD_SHAPES, k))
169
- return `unknown agent key "${k}"`;
187
+ return { message: `unknown agent key ${quotedCallerText(k)}` };
170
188
  }
171
189
  if (rec.name === undefined)
172
- return "agent.name is required";
190
+ return { message: "agent.name is required" };
173
191
  for (const [k, v] of Object.entries(rec)) {
174
192
  if (v === undefined)
175
193
  continue;
176
194
  const shape = TASK_AGENT_FIELD_SHAPES[k];
177
- if (!shape.ok(v))
178
- return `agent.${k} must be ${shape.desc}`;
195
+ if (shape.ok(v))
196
+ continue;
197
+ const hit = shape.limit?.(v);
198
+ if (hit === undefined)
199
+ return { message: `agent.${k} must be ${shape.desc}` };
200
+ const rel = `${k}${hit.sub}`;
201
+ const limit = { rel, measure: hit.measure, count: hit.count, cap: hit.cap };
202
+ return hit.keepShapeSentence === true ? { message: `agent.${k} must be ${shape.desc}`, limit } : { message: describeLimit(`agent.${rel}`, hit.measure, hit.count, hit.cap), limit };
179
203
  }
180
204
  return null;
181
205
  }
182
206
  export function validateTaskAgents(v) {
183
207
  if (!Array.isArray(v) || v.length === 0)
184
- return "agents must be a non-empty array of agent definitions";
208
+ return { message: "agents must be a non-empty array of agent definitions" };
185
209
  if (v.length > MAX_TASK_AGENTS)
186
- return `at most ${MAX_TASK_AGENTS} agents per request`;
210
+ return limitRefusal("agents", "entries", v.length, MAX_TASK_AGENTS);
187
211
  const names = new Set();
188
212
  for (let i = 0; i < v.length; i++) {
189
213
  const issue = taskAgentIssue(v[i]);
190
- if (issue)
191
- return `agents[${i}]: ${issue}`;
214
+ if (issue) {
215
+ const message = `agents[${i}]: ${issue.message}`;
216
+ return issue.limit === undefined ? { message } : { message, facts: limitFacts(`agents[${i}].${issue.limit.rel}`, issue.limit.measure, issue.limit.count, issue.limit.cap) };
217
+ }
192
218
  const skills = v[i].skills;
193
219
  if (Array.isArray(skills)) {
194
220
  for (let j = 0; j < skills.length; j++) {
195
- const refusal = skillToolListRefusal(skills[j]);
196
- if (refusal !== undefined)
197
- return `agents[${i}]: skills[${j}]: ${refusal}`;
221
+ const over = skillToolListsOverCap(skills[j], `agents[${i}].skills[${j}]`, "agent");
222
+ if (over !== undefined)
223
+ return { message: over.message, ...(over.extra !== undefined ? { facts: over.extra } : {}) };
198
224
  }
199
225
  }
200
226
  const name = v[i].name;
201
227
  if (names.has(name))
202
- return `agents[${i}]: duplicate agent name "${name}"`;
228
+ return { message: `agents[${i}]: duplicate agent name ${quotedCallerText(name)}` };
203
229
  names.add(name);
204
230
  }
205
231
  return null;
@@ -224,7 +250,7 @@ export function taskAgentsFromBody(raw, requirePrincipal, warn) {
224
250
  }
225
251
  const issue = taskAgentIssue(raw[i]);
226
252
  if (issue) {
227
- warn("task_agent_dropped", { index: i, reason: issue });
253
+ warn("task_agent_dropped", { index: i, reason: issue.message });
228
254
  continue;
229
255
  }
230
256
  const rec = raw[i];
@@ -272,22 +298,8 @@ export function toolNameListFromBody(raw) {
272
298
  const names = raw.filter((v) => typeof v === "string" && v.length > 0);
273
299
  return names.length > 0 ? names : undefined;
274
300
  }
275
- export const ALLOW_TOOLS_MIN_ENGINE = "7.49.0";
276
- function engineAtLeast(version, floor) {
277
- const parse = (v) => v.split(/[-+]/, 1)[0].split(".").map((n) => Number.parseInt(n, 10) || 0);
278
- const [a, b] = [parse(version), parse(floor)];
279
- for (let i = 0; i < 3; i++)
280
- if ((a[i] ?? 0) !== (b[i] ?? 0))
281
- return (a[i] ?? 0) > (b[i] ?? 0);
282
- return true;
283
- }
284
- export function allowToolsSpecFragment(raw, engineVersion = CORE_ENGINE_VERSION) {
285
- if (raw === undefined)
286
- return {};
287
- if (!engineAtLeast(engineVersion, ALLOW_TOOLS_MIN_ENGINE)) {
288
- throw createCodedHttpError(400, "request.field_invalid", `allowTools needs engine ${ALLOW_TOOLS_MIN_ENGINE} or later; this server runs engine ${engineVersion}, which would drop the list and leave every tool available — send the request without allowTools, or upgrade the server`);
289
- }
290
- return { allowTools: raw };
301
+ export function allowToolsSpecFragment(raw) {
302
+ return raw === undefined ? {} : { allowTools: raw };
291
303
  }
292
304
  export function promptProfileFromBody(raw) {
293
305
  return raw === "simple" || raw === "classic" ? raw : undefined;
@@ -24,9 +24,34 @@
24
24
  * 不在这里 —— 在 `sql-driver.ts` 的连接初始化里(TiDB 乐观模式设不成悲观 / 隔离级复核不符 ⇒ 响亮抛)。
25
25
  * 本模块在 boot 期借一条连接**触发**那次初始化,于是那句拒绝落在启动期而不是第一次业务写上。
26
26
  */
27
- import { type SqlEngineFacts } from "./plugins/sql-driver.js";
27
+ import { type SqlEngineFacts, type SqlEngineReading } from "./plugins/sql-driver.js";
28
+ import type { StoreBackend } from "./plugins/store-backend.js";
28
29
  import type { Pool as MySqlPool } from "mysql2/promise";
29
30
  import type { Pool as PgPool } from "pg";
31
+ /**
32
+ * 一只店后端交出的 SQL 池(至多一只:`mysqlPool()` 只在 MySQL 协议后端上有值,`pgPool()` 只在 PG 后端上;local 后端 / 没有后端 ⇒ 两个都 `undefined`)。
33
+ * **「SQL 后端在场」只有这一个谓词**:boot 期据它建立引擎读口({@link establishSqlEnginePosture}),`createHttpServer` 据它判「读口必填」——
34
+ * 两处读同一只函数,所以本服务自己的装配(有池 ⇒ 有读口)恒满足那道起服门,嵌入方少给读口则被它拒。
35
+ */
36
+ export declare function sqlPoolsOf(backend: Pick<StoreBackend, "mysqlPool" | "pgPool"> | undefined): {
37
+ mysqlPool: MySqlPool | undefined;
38
+ pgPool: PgPool | undefined;
39
+ };
40
+ /**
41
+ * `ServiceDeps.sqlEngine` 座的**值形**判:`{ dialect: "tidb" | "pg", facts }`,`facts` 是 `null`(池上连接初始化还没成功)或一份引擎事实 —— 判到墙判官 `sqlWallsOf` 读的那几位
42
+ * (`maxRowBytes` / `maxPacketBytes` 是 `null` 或数,`wallSources` 两位是出处词)。一个函数(7.131.x 的事实读口 `() => facts` 只改了键名)、缺 `facts` 的对象、错方言词都不是它。
43
+ * `facts` 是活读(getter):这里读一次,判的是装配这一刻看得到的那一份。
44
+ */
45
+ export declare function isSqlEngineReading(v: unknown): v is SqlEngineReading;
46
+ /** 引擎读口座的装配问题(闭集;{@link sqlEngineSeatIssue} 的产物):`required` = SQL 后端在场而座缺席;`bad_shape` = 座在场但形不对。 */
47
+ export type SqlEngineSeatIssue = "required" | "bad_shape";
48
+ /**
49
+ * 🔴 **引擎读口座的装配判官**(`createHttpServer` 起服时调;两臂一只函数):
50
+ * · 座在场 ⇒ 判值形({@link isSqlEngineReading}),不对 ⇒ `bad_shape`;
51
+ * · 座缺席 ⇒ 看后端交没交出 SQL 池({@link sqlPoolsOf},与 boot 期建立读口同一个谓词):交了 ⇒ `required`(席缺席只表示「没有 SQL 后端」,不能被判官读成「没有墙」);没交 ⇒ 过。
52
+ * 都是 fail-closed:墙门只认这一席,席坏了或漏了,代价是每份超出库墙的体照样受理或每次提交 500,不是起服时一句话。
53
+ */
54
+ export declare function sqlEngineSeatIssue(backend: Pick<StoreBackend, "mysqlPool" | "pgPool"> | undefined, sqlEngine: unknown): SqlEngineSeatIssue | undefined;
30
55
  /** 消费端窄投影(`GET /v1/capabilities` 的 `store.sql` 位;7.106.0 前是顶层 `sql`,S-866 ①)。`null` = 驱动此刻给不出事实 ⇒ `store.sql` 缺席。 */
31
56
  export interface SqlEngineCapability {
32
57
  engine: SqlEngineFacts["engine"];
@@ -34,8 +59,10 @@ export interface SqlEngineCapability {
34
59
  txnMode: SqlEngineFacts["txnMode"];
35
60
  }
36
61
  /**
37
- * Boot 期建立引擎事实:借一条池连接(初始化随之跑),再原样归还。返回一个 **live getter** —— 事实由
38
- * 驱动持有,重连后它会被下一次初始化刷新,快照会说谎。
62
+ * Boot 期建立引擎事实:借一条池连接(初始化随之跑),再原样归还。返回本池的**引擎读口**(驱动本身:方言 + 活的 `facts`)—— 事实由
63
+ * 驱动持有,重连后它会被下一次初始化刷新,快照会说谎;方言与事实同出这一只,写入要装进的墙(`sqlWallsOf`)只读它。读到的是**最近一次初始化的那条连接**的事实:隔离级 / 事务模式每条连接
64
+ * 同钉同验,所以就是池的事实;包墙 `maxPacketBytes` 是会话值、随连接不同,这里只是那一条连接的读数(池见过的最新读数 —— 只在有连接初始化时才更新,DBA 调了全局值之后、下一条连接初始化之前它仍是旧值;
65
+ * 运维读面与提交受理口的提前一跑读它),终判读将要执行写入的那条连接自己的读数(`sql-driver.ts` `connectJudged`)。
39
66
  *
40
67
  * 抛出 = 拒启:连接初始化拒绝了这个后端(TiDB 乐观模式设不成悲观、隔离级复核不符、服务器太旧读不出
41
68
  * `@@transaction_isolation`)。这条错**刻意不吞** —— 本仓所有 `FOR UPDATE` 判据都以它为前提。
@@ -43,7 +70,7 @@ export interface SqlEngineCapability {
43
70
  export declare function establishSqlEnginePosture(pools: {
44
71
  mysqlPool?: MySqlPool | undefined;
45
72
  pgPool?: PgPool | undefined;
46
- }): Promise<(() => SqlEngineFacts | null) | undefined>;
73
+ }): Promise<SqlEngineReading | undefined>;
47
74
  /** operator 面 → 消费端面的窄投影(`version` 是运维料,刻意不进能力位:它只对排障有意义)。 */
48
75
  export declare function projectSqlEngineCapability(facts: SqlEngineFacts | null | undefined): SqlEngineCapability | null;
49
76
  //# sourceMappingURL=sql-engine-posture.d.ts.map
@@ -1,11 +1,46 @@
1
1
  import { mysqlDriver, pgDriver } from "./plugins/sql-driver.js";
2
+ export function sqlPoolsOf(backend) {
3
+ return { mysqlPool: backend?.mysqlPool?.(), pgPool: backend?.pgPool?.() };
4
+ }
5
+ const DIALECT_WORDS = { tidb: true, pg: true };
6
+ const WALL_SOURCE_WORDS = { reported: true, assumed: true };
7
+ const isWallBytes = (v) => v === null || (typeof v === "number" && Number.isFinite(v) && v >= 0);
8
+ const isWallSourceWord = (v) => typeof v === "string" && Object.hasOwn(WALL_SOURCE_WORDS, v);
9
+ export function isSqlEngineReading(v) {
10
+ if (typeof v !== "object" || v === null)
11
+ return false;
12
+ const r = v;
13
+ if (typeof r.dialect !== "string" || !Object.hasOwn(DIALECT_WORDS, r.dialect))
14
+ return false;
15
+ if (!("facts" in v))
16
+ return false;
17
+ const facts = v.facts;
18
+ if (facts === null)
19
+ return true;
20
+ if (typeof facts !== "object")
21
+ return false;
22
+ const f = facts;
23
+ if (!isWallBytes(f.maxRowBytes) || !isWallBytes(f.maxPacketBytes))
24
+ return false;
25
+ const sources = f.wallSources;
26
+ if (typeof sources !== "object" || sources === null)
27
+ return false;
28
+ const src = sources;
29
+ return isWallSourceWord(src.maxRowBytes) && isWallSourceWord(src.maxPacketBytes);
30
+ }
31
+ export function sqlEngineSeatIssue(backend, sqlEngine) {
32
+ if (sqlEngine !== undefined)
33
+ return isSqlEngineReading(sqlEngine) ? undefined : "bad_shape";
34
+ const { mysqlPool, pgPool } = sqlPoolsOf(backend);
35
+ return mysqlPool !== undefined || pgPool !== undefined ? "required" : undefined;
36
+ }
2
37
  export async function establishSqlEnginePosture(pools) {
3
38
  const driver = pools.mysqlPool ? mysqlDriver(pools.mysqlPool) : pools.pgPool ? pgDriver(pools.pgPool) : undefined;
4
39
  if (driver === undefined)
5
40
  return undefined;
6
41
  const conn = await driver.connect();
7
42
  conn.release();
8
- return () => driver.facts;
43
+ return driver;
9
44
  }
10
45
  export function projectSqlEngineCapability(facts) {
11
46
  return facts == null ? null : { engine: facts.engine, isolation: facts.isolation, txnMode: facts.txnMode };