@sema-agent/server 7.136.0 → 7.138.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 (327) hide show
  1. package/MIGRATION.md +501 -139
  2. package/README.md +1 -0
  3. package/README.zh-CN.md +1 -0
  4. package/USAGE.md +149 -34
  5. package/deploy/sema-up/README.md +14 -0
  6. package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +7 -1
  7. package/deploy/sema-up/stack/sema-stack-cluster.yaml +7 -1
  8. package/dist/approval-card.d.ts +21 -14
  9. package/dist/approval-card.js +1 -0
  10. package/dist/approval-content-kind.d.ts +6 -0
  11. package/dist/approval-content-kind.js +7 -0
  12. package/dist/approval-gate-currency.d.ts +48 -6
  13. package/dist/approval-gate-currency.js +16 -9
  14. package/dist/approval-hmac.d.ts +13 -1
  15. package/dist/approval-hmac.js +1 -1
  16. package/dist/approval.js +3 -3
  17. package/dist/audit.js +1 -0
  18. package/dist/auth-bridge.js +2 -2
  19. package/dist/background-agent-name.d.ts +5 -0
  20. package/dist/background-agent-name.js +5 -0
  21. package/dist/boot/budget-tracing.d.ts +1 -12
  22. package/dist/boot/deployment-mods.d.ts +46 -16
  23. package/dist/boot/deployment-mods.js +82 -6
  24. package/dist/boot/execution-env.d.ts +24 -1
  25. package/dist/boot/execution-env.js +69 -6
  26. package/dist/boot/governance-seams.d.ts +10 -17
  27. package/dist/boot/governance-seams.js +5 -17
  28. package/dist/boot/leader.d.ts +3 -0
  29. package/dist/boot/leader.js +1 -0
  30. package/dist/boot/org-delivery.js +15 -2
  31. package/dist/boot/reapers.d.ts +3 -0
  32. package/dist/boot/reapers.js +15 -1
  33. package/dist/boot/resolve-spec.d.ts +7 -0
  34. package/dist/boot/resolve-spec.js +36 -26
  35. package/dist/boot/retention-lane.d.ts +11 -5
  36. package/dist/boot/retention-lane.js +2 -2
  37. package/dist/boot/runner-deps.d.ts +7 -3
  38. package/dist/boot/runner-deps.js +1 -0
  39. package/dist/boot/stage-03-store-backend.d.ts +1 -1
  40. package/dist/boot/stage-04-stores.d.ts +2 -13
  41. package/dist/boot/stage-05-execution-env.d.ts +6 -13
  42. package/dist/boot/stage-05-execution-env.js +17 -5
  43. package/dist/boot/stage-06-runners.d.ts +6 -13
  44. package/dist/boot/stage-06-runners.js +10 -3
  45. package/dist/boot/stage-07-capability-layer.d.ts +7 -13
  46. package/dist/boot/stage-07-capability-layer.js +3 -3
  47. package/dist/boot/stage-08-reapers.d.ts +7 -13
  48. package/dist/boot/stage-08-reapers.js +2 -1
  49. package/dist/boot/stage-09-leader.d.ts +7 -13
  50. package/dist/boot/stage-09-leader.js +2 -2
  51. package/dist/boot/stage-10-http-server.d.ts +7 -13
  52. package/dist/boot/stage-10-http-server.js +6 -3
  53. package/dist/boot/stores.d.ts +1 -1
  54. package/dist/boot/web-admin.d.ts +5 -2
  55. package/dist/boot/web-admin.js +3 -3
  56. package/dist/brain.js +5 -5
  57. package/dist/broker/broker.d.ts +89 -0
  58. package/dist/broker/broker.js +287 -0
  59. package/dist/broker/constants.d.ts +39 -0
  60. package/dist/broker/constants.js +15 -0
  61. package/dist/broker/http1.d.ts +111 -0
  62. package/dist/broker/http1.js +256 -0
  63. package/dist/broker/lease-book.d.ts +87 -0
  64. package/dist/broker/lease-book.js +142 -0
  65. package/dist/broker/lease-file.d.ts +60 -0
  66. package/dist/broker/lease-file.js +127 -0
  67. package/dist/broker/main.d.ts +2 -0
  68. package/dist/broker/main.js +20 -0
  69. package/dist/budget.d.ts +17 -15
  70. package/dist/budget.js +2 -2
  71. package/dist/capabilities/composite-members.d.ts +2 -1
  72. package/dist/capabilities/composite-members.js +2 -1
  73. package/dist/capabilities/engine-capabilities.js +1 -0
  74. package/dist/capabilities/mcp-probe.d.ts +36 -11
  75. package/dist/capabilities/mcp-probe.js +44 -5
  76. package/dist/capabilities/scenarios.d.ts +23 -8
  77. package/dist/capabilities/scenarios.js +13 -8
  78. package/dist/capabilities/skills.d.ts +28 -5
  79. package/dist/capabilities/skills.js +8 -0
  80. package/dist/capability-facts.d.ts +6 -0
  81. package/dist/capability-facts.js +5 -0
  82. package/dist/center-credential-renewer.js +5 -1
  83. package/dist/checkpoint-ctx-seal-m28.d.ts +3 -10
  84. package/dist/checkpoint-ctx-seal-m28.js +1 -1
  85. package/dist/checkpoint-identity.d.ts +13 -6
  86. package/dist/config-catalog.js +16 -7
  87. package/dist/config-types.d.ts +24 -7
  88. package/dist/config.d.ts +1 -1
  89. package/dist/config.js +42 -13
  90. package/dist/deployment-governance.d.ts +2 -2
  91. package/dist/deployment-governance.js +7 -9
  92. package/dist/deployment-shape.d.ts +6 -6
  93. package/dist/device-ws-protocol.d.ts +1 -0
  94. package/dist/device-ws-protocol.js +2 -1
  95. package/dist/file-history-disclosure.d.ts +4 -2
  96. package/dist/file-history-disclosure.js +2 -0
  97. package/dist/gate-settlement.d.ts +71 -0
  98. package/dist/gate-settlement.js +40 -0
  99. package/dist/hooks/classic-stations.d.ts +12 -54
  100. package/dist/hooks/classic-stations.js +1 -0
  101. package/dist/hooks/command-spawn.d.ts +2 -2
  102. package/dist/hooks/hook-runner.js +14 -14
  103. package/dist/http/admission.js +14 -9
  104. package/dist/http/approval-sweeps.js +4 -3
  105. package/dist/http/caller-trust.d.ts +2 -1
  106. package/dist/http/caller-trust.js +1 -3
  107. package/dist/http/checkpoint-ctx.d.ts +48 -7
  108. package/dist/http/checkpoint-ctx.js +40 -0
  109. package/dist/http/dispatch.d.ts +4 -0
  110. package/dist/http/dispatch.js +18 -10
  111. package/dist/http/durable-run-leg.d.ts +5 -1
  112. package/dist/http/durable-run-leg.js +5 -3
  113. package/dist/http/health-self-report.d.ts +2 -2
  114. package/dist/http/memory-compliance-failure-reply.js +3 -0
  115. package/dist/http/principal-gate.d.ts +15 -10
  116. package/dist/http/principal-gate.js +48 -9
  117. package/dist/http/resume-legs.d.ts +7 -31
  118. package/dist/http/resume-legs.js +185 -126
  119. package/dist/http/route-ctx.d.ts +38 -53
  120. package/dist/http/route-ctx.js +2 -5
  121. package/dist/http/routes/a2a-serve.js +10 -4
  122. package/dist/http/routes/agents-roster.d.ts +1 -1
  123. package/dist/http/routes/agents-roster.js +5 -1
  124. package/dist/http/routes/approvals-assistant.js +24 -10
  125. package/dist/http/routes/capabilities.js +23 -11
  126. package/dist/http/routes/mcp-reconnect.d.ts +3 -2
  127. package/dist/http/routes/mcp-reconnect.js +7 -7
  128. package/dist/http/routes/memory-consolidation.d.ts +1 -1
  129. package/dist/http/routes/memory-origin.d.ts +1 -1
  130. package/dist/http/routes/rules.js +3 -3
  131. package/dist/http/routes/runs.js +13 -8
  132. package/dist/http/routes/session-sync.js +42 -6
  133. package/dist/http/routes/sessions.js +6 -3
  134. package/dist/http/routes/side-query.js +2 -3
  135. package/dist/http/routes/tasks.js +794 -780
  136. package/dist/http/server.d.ts +35 -25
  137. package/dist/http/stored-body-replay.d.ts +3 -3
  138. package/dist/http/stored-body-replay.js +6 -1
  139. package/dist/http/wire-types.d.ts +66 -33
  140. package/dist/identity-source.d.ts +65 -0
  141. package/dist/identity-source.js +45 -0
  142. package/dist/index.d.ts +2 -0
  143. package/dist/index.js +1 -0
  144. package/dist/leader/wire.d.ts +7 -0
  145. package/dist/leader/wire.js +5 -4
  146. package/dist/mcp-assertion-header.d.ts +51 -40
  147. package/dist/mcp-assertion-header.js +10 -11
  148. package/dist/mcp-authorization-face.d.ts +27 -0
  149. package/dist/mcp-authorization-face.js +15 -0
  150. package/dist/memory-operator-faces.d.ts +13 -4
  151. package/dist/memory-operator-faces.js +1 -17
  152. package/dist/memory-store-refusal.d.ts +3 -3
  153. package/dist/memory-sync-client.js +72 -57
  154. package/dist/memory-sync.d.ts +1 -1
  155. package/dist/model-entry-refusal.d.ts +2 -0
  156. package/dist/model-entry-refusal.js +11 -0
  157. package/dist/model-route-gap.d.ts +6 -22
  158. package/dist/model-route-gap.js +7 -5
  159. package/dist/model-select.d.ts +6 -17
  160. package/dist/model-select.js +0 -3
  161. package/dist/mods-declaration.d.ts +110 -0
  162. package/dist/mods-declaration.js +109 -0
  163. package/dist/namespaced-rule-name.d.ts +1 -1
  164. package/dist/observability/err-text.d.ts +5 -0
  165. package/dist/observability/err-text.js +9 -0
  166. package/dist/observability/fail-open.d.ts +17 -1
  167. package/dist/observability/fail-open.js +17 -1
  168. package/dist/observability/metrics.js +1 -1
  169. package/dist/observability/run-terminal.js +1 -0
  170. package/dist/observability/secret-env-scrub.d.ts +1 -1
  171. package/dist/observability/secret-env-scrub.js +1 -1
  172. package/dist/operator-ask.d.ts +2 -2
  173. package/dist/org-delivery-gate.js +1 -1
  174. package/dist/org-memory-admission.d.ts +2 -2
  175. package/dist/org-memory-admission.js +39 -2
  176. package/dist/parked-decide.d.ts +15 -2
  177. package/dist/parked-decide.js +17 -10
  178. package/dist/peer-directory.js +2 -0
  179. package/dist/peer-seat.d.ts +150 -0
  180. package/dist/peer-seat.js +239 -0
  181. package/dist/permission-rule-list.d.ts +2 -2
  182. package/dist/permission-rule-vocab.d.ts +7 -7
  183. package/dist/permission-rule-vocab.js +3 -3
  184. package/dist/plain-string-record.d.ts +38 -0
  185. package/dist/plain-string-record.js +38 -0
  186. package/dist/plugins/background-agent-store-sql.js +6 -3
  187. package/dist/plugins/caching-session-store.d.ts +5 -0
  188. package/dist/plugins/caching-session-store.js +6 -0
  189. package/dist/plugins/checkpoint-store-sql.d.ts +34 -29
  190. package/dist/plugins/checkpoint-store-sql.js +14 -14
  191. package/dist/plugins/file-history-store-sql.js +10 -16
  192. package/dist/plugins/file-run-store.js +8 -2
  193. package/dist/plugins/k8s-exec-protocol.d.ts +69 -13
  194. package/dist/plugins/k8s-exec-protocol.js +116 -28
  195. package/dist/plugins/k8s-pod-delete-failure.d.ts +25 -0
  196. package/dist/plugins/k8s-pod-delete-failure.js +17 -0
  197. package/dist/plugins/k8s-pod-reaper.d.ts +106 -0
  198. package/dist/plugins/k8s-pod-reaper.js +122 -0
  199. package/dist/plugins/local-checkpoint-store.d.ts +4 -17
  200. package/dist/plugins/local-checkpoint-store.js +3 -4
  201. package/dist/plugins/local-session-store.d.ts +66 -27
  202. package/dist/plugins/local-session-store.js +60 -28
  203. package/dist/plugins/mailbox-store-sql.d.ts +11 -3
  204. package/dist/plugins/mailbox-store-sql.js +103 -15
  205. package/dist/plugins/memory-run-store.js +2 -0
  206. package/dist/plugins/memory-sync-store-pg.d.ts +16 -5
  207. package/dist/plugins/memory-sync-store-tidb.d.ts +3 -3
  208. package/dist/plugins/one-time-migrations.d.ts +34 -12
  209. package/dist/plugins/one-time-migrations.js +51 -9
  210. package/dist/plugins/permission-rule-store-file.js +2 -2
  211. package/dist/plugins/permission-rule-store-sql.d.ts +17 -17
  212. package/dist/plugins/permission-rule-store-sql.js +37 -30
  213. package/dist/plugins/pg-pool.js +4 -0
  214. package/dist/plugins/pg-session-storage.d.ts +10 -2
  215. package/dist/plugins/pg-session-storage.js +20 -7
  216. package/dist/plugins/remote-env-adb.d.ts +6 -1
  217. package/dist/plugins/remote-env-adb.js +2 -1
  218. package/dist/plugins/remote-env-device.d.ts +6 -1
  219. package/dist/plugins/remote-env-device.js +5 -1
  220. package/dist/plugins/remote-env-e2b.d.ts +5 -0
  221. package/dist/plugins/remote-env-e2b.js +2 -1
  222. package/dist/plugins/remote-env-file-error.d.ts +8 -1
  223. package/dist/plugins/remote-env-file-error.js +7 -1
  224. package/dist/plugins/remote-env-host.d.ts +10 -2
  225. package/dist/plugins/remote-env-host.js +8 -2
  226. package/dist/plugins/remote-env-k8s.d.ts +140 -11
  227. package/dist/plugins/remote-env-k8s.js +277 -15
  228. package/dist/plugins/remote-env-local-docker.d.ts +5 -0
  229. package/dist/plugins/remote-env-local-docker.js +2 -1
  230. package/dist/plugins/remote-env-ssh.d.ts +6 -1
  231. package/dist/plugins/remote-env-ssh.js +2 -1
  232. package/dist/plugins/retention-store-sql.d.ts +14 -2
  233. package/dist/plugins/retention-store-sql.js +6 -0
  234. package/dist/plugins/run-store-sql.js +10 -4
  235. package/dist/plugins/session-fork.d.ts +10 -13
  236. package/dist/plugins/session-fork.js +5 -25
  237. package/dist/plugins/session-ownership.d.ts +24 -3
  238. package/dist/plugins/session-ownership.js +24 -5
  239. package/dist/plugins/session-workspace-cell.d.ts +17 -0
  240. package/dist/plugins/session-workspace-cell.js +38 -0
  241. package/dist/plugins/sql-errors.d.ts +23 -2
  242. package/dist/plugins/sql-errors.js +15 -0
  243. package/dist/plugins/store-backend.js +7 -7
  244. package/dist/plugins/store-contracts.d.ts +10 -1
  245. package/dist/plugins/store-fault.d.ts +2 -2
  246. package/dist/plugins/store-fault.js +4 -2
  247. package/dist/plugins/tidb-pool.js +13 -0
  248. package/dist/plugins/tidb-session-store.d.ts +17 -2
  249. package/dist/plugins/tidb-session-store.js +18 -7
  250. package/dist/plugins/tool-result-store-sql.d.ts +13 -6
  251. package/dist/plugins/tool-result-store-sql.js +8 -7
  252. package/dist/plugins/worktree-isolation.d.ts +3 -2
  253. package/dist/plugins/worktree-isolation.js +1 -7
  254. package/dist/project-identity.d.ts +1 -14
  255. package/dist/project-identity.js +0 -4
  256. package/dist/request-key-closure.js +1 -1
  257. package/dist/request-value-closure.d.ts +31 -2
  258. package/dist/request-value-closure.js +7 -1
  259. package/dist/rule-entry-list.d.ts +3 -2
  260. package/dist/rule-entry-list.js +2 -2
  261. package/dist/rules-consent.js +12 -7
  262. package/dist/run-local.d.ts +2 -2
  263. package/dist/run-local.js +12 -6
  264. package/dist/runs.d.ts +7 -1
  265. package/dist/runs.js +8 -2
  266. package/dist/runtime-governance.d.ts +5 -5
  267. package/dist/sandbox-git-lease.d.ts +49 -0
  268. package/dist/sandbox-git-lease.js +60 -0
  269. package/dist/sandbox-git-plane.d.ts +84 -0
  270. package/dist/sandbox-git-plane.js +105 -0
  271. package/dist/security.d.ts +16 -4
  272. package/dist/security.js +8 -3
  273. package/dist/server-secret-env.d.ts +12 -3
  274. package/dist/server-secret-env.js +18 -2
  275. package/dist/session-error-wire.d.ts +14 -6
  276. package/dist/session-error-wire.js +2 -1
  277. package/dist/session-incarnation.d.ts +4 -5
  278. package/dist/session-incarnation.js +2 -2
  279. package/dist/session-policy-wire.d.ts +1 -1
  280. package/dist/session-policy-wire.js +2 -2
  281. package/dist/session-sync.d.ts +1 -1
  282. package/dist/session-workspace.d.ts +130 -0
  283. package/dist/session-workspace.js +83 -0
  284. package/dist/spec-fields.d.ts +44 -14
  285. package/dist/spec-fields.js +33 -12
  286. package/dist/standing-answer-grant.d.ts +2 -13
  287. package/dist/standing-answer-grant.js +0 -7
  288. package/dist/stored-request-prompt-profile-m30.d.ts +49 -0
  289. package/dist/stored-request-prompt-profile-m30.js +25 -0
  290. package/dist/task-a2a.d.ts +44 -14
  291. package/dist/task-a2a.js +46 -20
  292. package/dist/task-mcp.d.ts +34 -21
  293. package/dist/task-mcp.js +46 -22
  294. package/dist/task-settings.d.ts +2 -2
  295. package/dist/tool-approval.d.ts +43 -9
  296. package/dist/tool-approval.js +57 -15
  297. package/dist/tool-rule-names.d.ts +5 -0
  298. package/dist/trace/core-keyset-guard.d.ts +34 -19
  299. package/dist/trace/engine-notice-wire.d.ts +1 -1
  300. package/dist/trace/engine-notice-wire.js +4 -0
  301. package/dist/trace/exit-seat.d.ts +20 -1
  302. package/dist/trace/exit-seat.js +5 -2
  303. package/dist/trace/extension-call-face.d.ts +33 -0
  304. package/dist/trace/extension-call-face.js +39 -0
  305. package/dist/trace/ledger-sink.d.ts +4 -5
  306. package/dist/trace/ledger-sink.js +3 -7
  307. package/dist/trace/project.d.ts +62 -10
  308. package/dist/trace/project.js +49 -9
  309. package/dist/trace/redact.d.ts +18 -6
  310. package/dist/trace/redact.js +154 -60
  311. package/dist/trace/self-minted-wire.d.ts +500 -7
  312. package/dist/trace/self-minted-wire.js +182 -1
  313. package/dist/trace/wire-projection-faces.d.ts +7 -5
  314. package/dist/trace/wire-projection-faces.js +9 -4
  315. package/dist/user-authored-text.d.ts +2 -2
  316. package/dist/user-authored-text.js +16 -1
  317. package/dist/web-admin-client/apply-effective.js +0 -1
  318. package/dist/web-admin-client/center-request.d.ts +23 -4
  319. package/dist/web-admin-client/center-request.js +42 -8
  320. package/dist/web-admin-client/http-client.js +6 -6
  321. package/dist/web-admin-client/skills-mcp.d.ts +8 -4
  322. package/dist/web-admin-client/skills-mcp.js +31 -18
  323. package/dist/web-admin-client/types.d.ts +10 -5
  324. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +11 -5
  325. package/package.json +3 -3
  326. package/wire-changes/server@7.137.0.json +825 -0
  327. package/wire-changes/server@7.138.0.json +446 -0
@@ -1,12 +1,19 @@
1
1
  /**
2
- * http 传输的 `assertionHeader` —— 托管连接器「断言头」的**头名**(settings-schema ≥12.2.0 的 `McpTransport` http 形键)。
2
+ * 请求面一条 MCP 条目的形与它交给引擎之前的拆法({@link toMcpDraft}),以及 http 传输的 `assertionHeader` —— 托管连接器「断言头」的**头名**(settings-schema ≥12.2.0 的 `McpTransport` http 形键)。
3
3
  *
4
- * ## 一条律:一个键一种读法
4
+ * ## 请求面条目 → 草稿(一张按传输分臂的处置表)
5
+ * 请求面条目的形 = 契约包的请求传输形({@link RequestMcpServerSpec}:stdio 带 `env`、http 带 `headers` / `principalHeader` / `assertionHeader`),wire 上的形由它说。
6
+ * 交给引擎的声明不带件值:引擎的声明收据对带 `headers` / `env` 的声明整条拒,件由部署的对端座在发送时作答。所以每条条目按它那一臂的处置表
7
+ * ({@link MCP_STDIO_TRANSPORT_DISPOSITION} / {@link MCP_HTTP_TRANSPORT_DISPOSITION})拆成草稿:`env` / `headers` 进草稿的件,`assertionHeader` 承载不发送,其余进声明。
8
+ * 拆法只有 `plain-string-record.ts` 的 `splitDeclaration` 一只、键的去处只有表一处说;两张表各带三道编译格(请求臂加 / 减键、引擎臂加键、引擎臂删键都编译红)。
9
+ * 草稿只有胜出者(部署同名者赢,`task-mcp.ts` 的 `mergeRequestMcp`)才经对端座的唯一铸点(`peer-seat.ts` 的 `mintDeclaration`)登记,登记换来的引用放进声明的传输臂。
10
+ *
11
+ * ## `assertionHeader`:一条律,一个键一种读法
5
12
  * 两个面收下这个键,读法是同一个:
6
13
  * · **settings 面**(部署声明:中心下发 + 本地 `config.d`)—— 契约包在**解析期**受理它,并判它与 `principalHeader` 互斥
7
14
  * (同设 = 两个答案:「这台 http 服务器的请求上用哪个头送身份」);本仓这一面只承载,铸 spec 在 `resolveMcpServers`;
8
15
  * · **请求面**(任务提交体 `mcpServers[].transport`;探测口 `…/mcp/probe` 读同一张键表)—— 本仓在**受理期**兑现同一条规则:
9
- * 受理 = 字符串才收;互斥 = 同设即拒;投影 = 铸 spec 时不投(见下)。
16
+ * 受理 = 字符串才收;互斥 = 同设即拒;去处 = 处置表的 `withheld`(声明与件两边都不进)。
10
17
  * 同一条规则、两处执行者(契约包解析期 / 请求面受理期);判据 {@link mcpIdentityHeadersIssue} 与互斥拒句
11
18
  * {@link describeMcpIdentityHeadersConflict} 对契约包的原判官**逐字**对齐 —— 不是靠这句注释,而是
12
19
  * `test/task-mcp.test.ts` 的 [ref] 组把两边对拍(格子差分 + 拒句逐字相等),契约包改一个字那一组当场红。
@@ -18,38 +25,52 @@
18
25
  * 所以读器(契约包的 `readMcpIdentityHeaders`,`normalizeServer` 的 http 传输读两个身份头用它)的处置是**降级到升级前的读法**:`principalHeader` 胜(照挂,与升级前逐字相同),`assertionHeader` 不生效;
19
26
  * 不静默 —— 真挂上的这类条目由 {@link noteMcpAssertionHeaderIgnored} 说一行 warn(部署声明面没有这一格:配置不是被重放的存量任务,契约包解析期那一刀直接丢这一条)。
20
27
  *
21
- * ## 发送归引擎座(本版只承载,不发送)—— 「发不发」只有一只开关
22
- core 的 http 传输只有 `url` / `headers` / `principalHeader`,**没有**断言头座。所以本键承载到「铸 core 规格」为止:
23
- 请求面在 {@link toCoreMcpServerSpec} 剥掉它,settings 面的 `resolveMcpServers` 不投它;两处都用同一只
24
- {@link noteMcpAssertionHeaderNotSent} 说出一行 info(声明在、发送未接)—— 披露,不是兜底:server 照常挂载、不带断言头,
25
- 要求断言的托管连接器会拒这些调用,运维据这一行知道原因在哪。
26
- 「这台 server 发不发」是**一个事实**,只有一只开关 {@link MCP_ASSERTION_HEADER_SENT} 说它;读它的地方共五处,全经 {@link withholdsMcpAssertionHeader} 这一只谓词
27
- (能力位 `GET /v1/capabilities` 的 `mcpAssertionHeaderSent` 直读开关本人):请求面剥键、settings 面不投、一行 info、探测口整条拒、能力位。所以「位为真」与「还在说发送未接」
28
- 结构上不可能同时成立,消费方按位分支、位真时不再看到任何披露句;发送座到货的那天翻的就是这一行(与下面的退役门同批)。
29
-
30
- ## 退役(编译期自动逼,零人工记忆)
31
- * 引擎的 http 传输一旦长出同名座,{@link _CoreHasNoAssertionSeat} 当场编译红:届时删本文件里的 {@link RequestMcpServerSpec}
32
- * 扩展与 {@link toCoreMcpServerSpec} 的剥键、两处 info,把键直接投进引擎规格(发送由引擎座兑现)。
28
+ * ## 断言不发送 —— 「发不发」只有一处说
29
+ * 引擎的断言头是**固定的名**(引擎包根的 `MCP_ASSERTION_HEADER`),值由部署的对端座对 `assertion` 种类的引用作答;本部署没有断言来源,对端座对这一种恒拒
30
+ * (`peer-seat.ts` 的拒因 `kind_assertion`)。所以请求面写的这个头名**承载、不发送**:处置表那一格是 `withheld`,开关 {@link MCP_ASSERTION_HEADER_SENT} 从表那一格读出(恒假),
31
+ * 读它的地方全经 {@link withholdsMcpAssertionHeader} 这一只谓词(能力位 `GET /v1/capabilities` 的 `mcpAssertionHeaderSent` 直读开关本人):一行 info(请求面与 settings 面)、探测口整条拒、能力位;
32
+ * 两面铸声明时都不投这个键(请求面经处置表,settings 面不写它)。
33
+ * 声明在、发送未接 = 运维要知道的事实,不是兜底 —— server 照常挂载、不带断言头,要求断言的托管连接器会拒这些调用,运维据 {@link noteMcpAssertionHeaderNotSent} 那一行知道原因在哪。
34
+ * 退役门押在座上({@link _SeatRefusesAssertion}):对端座哪天开始对 `assertion` 作答,那一格当场编译红,届时重判这一格的去处(键本身随契约包删键一起退役)。
33
35
  */
34
36
  import type { McpServerSpec } from "@sema-agent/core";
35
- type CoreMcpTransport = McpServerSpec["transport"];
36
- type CoreStdioTransport = Extract<CoreMcpTransport, {
37
+ import type { RequestMcpTransport } from "@sema-agent/settings-schema";
38
+ import type { McpDraft } from "./peer-seat.js";
39
+ /** 请求面 stdio 传输的形(契约包):引擎的 stdio 传输去掉凭据引用位、加上 `env`(件)。 */
40
+ export type RequestStdioMcpTransport = Extract<RequestMcpTransport, {
37
41
  kind: "stdio";
38
42
  }>;
39
- type CoreHttpTransport = Extract<CoreMcpTransport, {
43
+ /** 请求面 http 传输的形(契约包):引擎的 http 传输去掉凭据引用位、加上 `headers`(件)与承载不发送的 `assertionHeader`。 */
44
+ export type RequestHttpMcpTransport = Extract<RequestMcpTransport, {
40
45
  kind: "http";
41
46
  }>;
42
- /** 请求面 http 传输的形:引擎的 http 传输 + 本仓承载的 `assertionHeader`(引擎无座,见头注)。 */
43
- export type RequestHttpMcpTransport = CoreHttpTransport & {
44
- assertionHeader?: string;
45
- };
46
47
  /**
47
48
  * 请求面一条 `mcpServers[]` 条目在 wire 上的形(= `TaskRequestBody.mcpServers` 的元素型,也是 `normalizeServer` 的产物):
48
- * 引擎的 {@link McpServerSpec} 加上 http 传输上的 `assertionHeader`。交给引擎之前一律经 {@link toCoreMcpServerSpec}。
49
+ * 引擎的 {@link McpServerSpec} 条目层 + 契约包的请求传输形。交给引擎之前一律经 {@link toMcpDraft} 拆成草稿。
49
50
  */
50
51
  export type RequestMcpServerSpec = Omit<McpServerSpec, "transport"> & {
51
- transport: CoreStdioTransport | RequestHttpMcpTransport;
52
+ transport: RequestMcpTransport;
53
+ };
54
+ /** stdio 臂的处置表(键序 = 键闭集序):`env` 是件,其余进声明。 */
55
+ export declare const MCP_STDIO_TRANSPORT_DISPOSITION: {
56
+ readonly args: "engine";
57
+ readonly command: "engine";
58
+ readonly env: "seat";
59
+ readonly kind: "engine";
52
60
  };
61
+ /** http 臂的处置表(键序 = 键闭集序):`headers` 是件,`assertionHeader` 承载不发送(见头注),其余进声明。 */
62
+ export declare const MCP_HTTP_TRANSPORT_DISPOSITION: {
63
+ readonly assertionHeader: "withheld";
64
+ readonly headers: "seat";
65
+ readonly kind: "engine";
66
+ readonly principalHeader: "engine";
67
+ readonly url: "engine";
68
+ };
69
+ /**
70
+ * 请求面条目 → 草稿:传输按它那一臂的处置表拆(`env` / `headers` 进件,`assertionHeader` 两边都不进,其余进声明);条目层的键原样进声明。件缺席或空 ⇒ 草稿不带件(登记时什么都不留)。
71
+ * 纯函数:不登记、不读部署状态;被扣下的 `assertionHeader` 由调用方另说一行 info。
72
+ */
73
+ export declare function toMcpDraft(spec: RequestMcpServerSpec): McpDraft;
53
74
  /** 一份原始 http 传输上两个身份头的问题类:`both_set` = 同设了 `principalHeader` 与 `assertionHeader`;`not_a_string` = `assertionHeader` 在场但不是字符串。 */
54
75
  export type McpIdentityHeadersIssue = "both_set" | "not_a_string";
55
76
  /**
@@ -64,27 +85,18 @@ export declare function describeMcpIdentityHeadersConflict(server: string): stri
64
85
  /** `assertionHeader` 值不是字符串的**原因句**(不带条目名与键路径:点名由请求面统一的拒形 `entryFieldRefusal` 负责;值的形状只说种类,不回显值本身:它是一个调用方写的头名位置,可能是任何东西)。 */
65
86
  export declare function describeMcpAssertionHeaderNotAString(value: unknown): string;
66
87
  /**
67
- * 引擎的 http 传输有没有断言头发送座 —— **全仓唯一的开关**。今天没有(core 的 http 传输无同名座,见头注与退役门)⇒ `false`:声明在、发送未接。
68
- * 翻真 = 这一行 + 删退役门 + 把 {@link RequestHttpMcpTransport} 并进引擎型;剥键、披露、探测口拒、settings 面投影、能力位 `mcpAssertionHeaderSent` 随它一起翻
69
- * (五处都读 {@link withholdsMcpAssertionHeader} / 本常量,没有第六处)。声明成 `boolean` 而不是字面 `false`:谓词里的真臂是活代码(单测传 `sent=true` 钉它),不是被收窄掉的死分支。
88
+ * 本部署发不发请求面声明的断言头 —— **全仓唯一的开关**,从 http 臂处置表的那一格读出(`withheld` ⇒ 假;依据见头注「断言不发送」与退役门)。
89
+ * 读它的地方全经 {@link withholdsMcpAssertionHeader} / 本常量(一行 info、探测口拒、能力位 `mcpAssertionHeaderSent`),所以表那一格与开关不可能脱钩。
90
+ * 声明成 `boolean` 而不是字面 `false`:谓词里的真臂是活代码(单测传 `sent=true` 钉它),不是被收窄掉的死分支。
70
91
  */
71
92
  export declare const MCP_ASSERTION_HEADER_SENT: boolean;
72
93
  /**
73
- * 这一份 `assertionHeader` 声明是不是「被扣下」的那一类(需要剥键、需要说一行 info、探测口要拒的那一类)—— 即**声明了,而发送座不在**。
74
- * 三处消费(剥键 / 披露 / 探测口拒)与 settings 面的投影共读这一只;`sent` 缺省读开关,单测传显式值钉另一臂。
94
+ * 这一份 `assertionHeader` 声明是不是「被扣下」的那一类(需要说一行 info、探测口要拒的那一类)—— 即**声明了,而本部署不发送**。
95
+ * 披露(请求面与 settings 面)/ 探测口拒共读这一只;`sent` 缺省读开关,单测传显式值钉另一臂。
75
96
  */
76
97
  export declare function withholdsMcpAssertionHeader(assertionHeader: unknown, sent?: boolean): boolean;
77
98
  /** {@link withholdsMcpAssertionHeader} 在请求面条目上的读法:只有 http 传输有这个键(stdio 形上它不存在)。 */
78
99
  export declare function specWithholdsMcpAssertionHeader(spec: RequestMcpServerSpec): boolean;
79
- /**
80
- * settings 面铸 spec 时「这个键投不投进引擎规格」:发送座在(`sent` 真)且声明了字符串 ⇒ 投,否则整键缺席。今天恒为空对象(开关假);
81
- * 开关翻真的那天 settings 面因此自动跟着投,不会出现「位说发了、部署声明面却没投」。
82
- */
83
- export declare function sentMcpAssertionHeaderMember(assertionHeader: unknown, sent?: boolean): {
84
- assertionHeader?: string;
85
- };
86
- /** 请求面条目 → 交给引擎的规格:被扣下的 `assertionHeader` 剥掉(引擎无座);其余逐字不动。被扣下的条目由调用方另说一行 info。 */
87
- export declare function toCoreMcpServerSpec(spec: RequestMcpServerSpec): McpServerSpec;
88
100
  /** `noteMcpAssertionHeaderNotSent` 的日志行名(运维 grep 用;请求面与 settings 面同一个名字)。 */
89
101
  export declare const MCP_ASSERTION_HEADER_NOT_SENT = "mcp_assertion_header_not_sent";
90
102
  /** `noteMcpAssertionHeaderIgnored` 的日志行名。 */
@@ -93,10 +105,9 @@ export declare const MCP_ASSERTION_HEADER_IGNORED = "mcp_assertion_header_ignore
93
105
  export declare function noteMcpAssertionHeaderIgnored(logger: {
94
106
  warn?(msg: string, meta?: unknown): void;
95
107
  } | undefined, server: string, reason: McpIdentityHeadersIssue): void;
96
- /** 说出「这台 server 声明了 `assertionHeader`,本版没有发送」—— 一台一行 info。两个铸 spec 点(请求面 `classifyHonored`、
108
+ /** 说出「这台 server 声明了 `assertionHeader`,本部署不发送」—— 一台一行 info。两个铸 spec 点(请求面 `classifyHonored`、
97
109
  * settings 面 `resolveMcpServers`)共用这一只,所以行名与措辞只有一份。 */
98
110
  export declare function noteMcpAssertionHeaderNotSent(logger: {
99
111
  info?(msg: string, meta?: unknown): void;
100
112
  } | undefined, server: string): void;
101
- export {};
102
113
  //# sourceMappingURL=mcp-assertion-header.d.ts.map
@@ -1,3 +1,11 @@
1
+ import { splitDeclaration } from "./plain-string-record.js";
2
+ export const MCP_STDIO_TRANSPORT_DISPOSITION = { args: "engine", command: "engine", env: "seat", kind: "engine" };
3
+ export const MCP_HTTP_TRANSPORT_DISPOSITION = { assertionHeader: "withheld", headers: "seat", kind: "engine", principalHeader: "engine", url: "engine" };
4
+ export function toMcpDraft(spec) {
5
+ const { transport, ...entry } = spec;
6
+ const split = transport.kind === "http" ? splitDeclaration(transport, MCP_HTTP_TRANSPORT_DISPOSITION) : splitDeclaration(transport, MCP_STDIO_TRANSPORT_DISPOSITION);
7
+ return { spec: { ...entry, transport: split.engine }, ...(split.pieces === undefined ? {} : { pieces: split.pieces }) };
8
+ }
1
9
  export function mcpIdentityHeadersIssue(transport) {
2
10
  if (transport.kind !== "http")
3
11
  return undefined;
@@ -14,22 +22,13 @@ export function describeMcpAssertionHeaderNotAString(value) {
14
22
  const kind = value === null ? "null" : Array.isArray(value) ? "an array" : `a ${typeof value}`;
15
23
  return `must be a string (the HTTP header NAME the connector assertion travels in) — got ${kind}; omit the key to send no assertion header`;
16
24
  }
17
- export const MCP_ASSERTION_HEADER_SENT = false;
25
+ export const MCP_ASSERTION_HEADER_SENT = MCP_HTTP_TRANSPORT_DISPOSITION.assertionHeader !== "withheld";
18
26
  export function withholdsMcpAssertionHeader(assertionHeader, sent = MCP_ASSERTION_HEADER_SENT) {
19
27
  return !sent && assertionHeader !== undefined;
20
28
  }
21
29
  export function specWithholdsMcpAssertionHeader(spec) {
22
30
  return spec.transport.kind === "http" && withholdsMcpAssertionHeader(spec.transport.assertionHeader);
23
31
  }
24
- export function sentMcpAssertionHeaderMember(assertionHeader, sent = MCP_ASSERTION_HEADER_SENT) {
25
- return sent && typeof assertionHeader === "string" ? { assertionHeader } : {};
26
- }
27
- export function toCoreMcpServerSpec(spec) {
28
- if (spec.transport.kind !== "http" || !withholdsMcpAssertionHeader(spec.transport.assertionHeader))
29
- return spec;
30
- const { assertionHeader: _declaredNotSent, ...transport } = spec.transport;
31
- return { ...spec, transport };
32
- }
33
32
  export const MCP_ASSERTION_HEADER_NOT_SENT = "mcp_assertion_header_not_sent";
34
33
  export const MCP_ASSERTION_HEADER_IGNORED = "mcp_assertion_header_ignored";
35
34
  export function noteMcpAssertionHeaderIgnored(logger, server, reason) {
@@ -44,7 +43,7 @@ export function noteMcpAssertionHeaderIgnored(logger, server, reason) {
44
43
  export function noteMcpAssertionHeaderNotSent(logger, server) {
45
44
  logger?.info?.(MCP_ASSERTION_HEADER_NOT_SENT, {
46
45
  server,
47
- note: "declaration KEPT but NOT SENT — the engine's http transport has no seat for an assertion header yet, so this server mounts WITHOUT one (a hosted connector that requires the assertion will refuse its calls); sending follows the engine seat",
46
+ note: "declaration KEPT but NOT SENT — the engine sends a connector assertion only under its own fixed header name, answered by the deployment's peer seat, and this deployment has no assertion source; this server mounts WITHOUT one (a hosted connector that requires the assertion will refuse its calls)",
48
47
  });
49
48
  }
50
49
  //# sourceMappingURL=mcp-assertion-header.js.map
@@ -0,0 +1,27 @@
1
+ /**
2
+ * MCP 授权事实(core 7.59.0 `McpAuthorization`:`{ reason, authorizeUrl?, resourceMetadataUrl? }`,与 `errorCode: "unauthorized"` 同行)的**出门投影** ——
3
+ * 本仓三张面(`wiring_manifest.mcp[]` 行、重拨回执的 `status`、`//mcp` 面板的 `servers[]`)同读这一只。
4
+ *
5
+ * 只投闭集词 `reason`(`rejected` = 端点答 401 且授权座的重问没给出能过的凭据 / `scope` = 403 `insufficient_scope` / `none` = 授权座答「未授权」):
6
+ * 判据直读引擎的 `MCP_AUTHORIZATION_REASONS`(不抄词表);词出闭集、非串、整只不是对象 ⇒ 整格缺席(最弱断言,不铸词)。
7
+ * 两只地址**不出门**:`authorizeUrl` 只来自部署的授权座,本部署今天没有授权座;`resourceMetadataUrl` 是远端在挑战头里自报的地址,不可信 —— 两只地址的去向
8
+ * (授权座 + 出口座)是授权记录面的设计,不在本投影里放行。用户面的「去授权」由会话通告 `mcp.authorization_required` 承载。
9
+ */
10
+ import { type McpAuthorizationReason } from "@sema-agent/core";
11
+ /** 授权记录的处置表(三面同读;`core-keyset-guard.ts` 读表 —— 门与投影一个写者):`reason` 认得才出门(闭集词;在场而认不得 ⇒ 丢并计一次),两只地址本面不出现。 */
12
+ export declare const MCP_AUTHORIZATION_DISPOSITIONS: {
13
+ readonly reason: {
14
+ readonly forward: (w: unknown) => w is McpAuthorizationReason;
15
+ };
16
+ readonly authorizeUrl: "strip";
17
+ readonly resourceMetadataUrl: "strip";
18
+ };
19
+ /** 处置表一格的放行谓词所窄化到的型(`forward: (w: unknown) => w is T` ⇒ `T`):表放行什么,出门值就是什么型。 */
20
+ type ForwardedAs<F> = F extends (w: unknown) => w is infer T ? T : never;
21
+ /** 本投影的产物 = 表里 `reason` 一格放行后的型。词的型只有表这一个写者,出口不再判第二遍。 */
22
+ export type McpAuthorizationFace = {
23
+ readonly reason: ForwardedAs<(typeof MCP_AUTHORIZATION_DISPOSITIONS)["reason"]["forward"]>;
24
+ };
25
+ export declare function projectMcpAuthorization(v: unknown): McpAuthorizationFace | undefined;
26
+ export {};
27
+ //# sourceMappingURL=mcp-authorization-face.d.ts.map
@@ -0,0 +1,15 @@
1
+ import { MCP_AUTHORIZATION_REASONS } from "@sema-agent/core";
2
+ import { projectByTable } from "./trace/projection-table.js";
3
+ const isAuthorizationReason = (w) => typeof w === "string" && MCP_AUTHORIZATION_REASONS.includes(w);
4
+ export const MCP_AUTHORIZATION_DISPOSITIONS = {
5
+ reason: { forward: isAuthorizationReason },
6
+ authorizeUrl: "strip",
7
+ resourceMetadataUrl: "strip",
8
+ };
9
+ export function projectMcpAuthorization(v) {
10
+ if (typeof v !== "object" || v === null || Array.isArray(v))
11
+ return undefined;
12
+ const { reason } = projectByTable("mcp.authorization", MCP_AUTHORIZATION_DISPOSITIONS, v, undefined);
13
+ return reason !== undefined ? { reason } : undefined;
14
+ }
15
+ //# sourceMappingURL=mcp-authorization-face.js.map
@@ -63,11 +63,20 @@ export interface MemoryComplianceFaces {
63
63
  * 抹除。入参 `unknown`:调用方递交的是未校验的对象,三选一选择子的整体判决归 core
64
64
  * (`erasureRequestInvalid` 是它的单一属主面)—— 在本层抄一遍就是第二真源。
65
65
  *
66
- * `opts.allowedScopes` = **授权信封座**(见 {@link erasureEnvelopeRefusal} 的头注)。
66
+ * ## 授权座只有一只:引擎的 `EraseMemoryEntriesInput.expectedScopes`
67
+ *
68
+ * 「这个调用方能删哪些 scope」由引擎判:在场 ⇒ 选择子自己的 scope(地点选择子,读店之前判)与**每个解析出的 id 的绑定 scope**
69
+ * 都得是集内成员,判在解析之后、店锁之内;违者整单拒 `config.memory_erasure_scope`,拒句不带数、不带 id、不带 scope(集外 id
70
+ * 与从没存在过的 id 同句,不是存在性神谕)。本层不另设信封:一只只读得到 `{ scope }` 选择子字面量的信封判不了 `ids` /
71
+ * `sessionId` 两腿、只能整拒,而且让「哪些 scope 能删」有两个答者。集随**入参**走(与 `requestId` / `select` 同一个对象),
72
+ * 本面没有第二个形参。
73
+ *
74
+ * 今天谁传集:operator 面原样递交调用方的体(调用方自己写的 `expectedScopes` = 它自己收窄自己);路由不替 operator 铸集 ——
75
+ * 本仓没有任何授权源能对一个 operator 说「你只能动这些 scope」(`routes/memory-policy.ts` 的 `gateMemoryScope`:operator 支在查
76
+ * 目录之前就 allow;`org-memory-admission.ts`:v1 不中央收窄 operator 声明的 scope)。拿 org 目录的 grant 集去凑一个集就是在本层
77
+ * 发明第二套授权语义,与 `gateMemoryScope` 对同一个身份给出相反答案。会话自助面的选择子由路径铸,不带集。
67
78
  */
68
- erase: (input: unknown, opts?: {
69
- allowedScopes?: readonly string[];
70
- }) => Promise<MemoryErasureAttestation>;
79
+ erase: (input: unknown) => Promise<MemoryErasureAttestation>;
71
80
  }
72
81
  /**
73
82
  * **选择子替身**的拦截谓词(codex 交叉复审 [critical],亲验复现后修 —— 复现器与结论逐条在
@@ -24,19 +24,6 @@ export function erasureInputSmugglesPrototypeKey(input) {
24
24
  }
25
25
  return false;
26
26
  }
27
- function erasureEnvelopeRefusal(input, allowedScopes) {
28
- if (allowedScopes === undefined)
29
- return undefined;
30
- const select = typeof input === "object" && input !== null ? input.select : undefined;
31
- const scope = typeof select === "object" && select !== null ? select.scope : undefined;
32
- if (typeof scope === "string" && allowedScopes.includes(scope))
33
- return undefined;
34
- const e = new Error(typeof scope === "string"
35
- ? `memory erasure refused: scope ${JSON.stringify(scope)} is outside this caller's erasure envelope`
36
- : "memory erasure refused: this request's selector is not scope-addressable, and an envelope that cannot judge a selector must not admit it");
37
- e.code = "memory.erasure_scope_forbidden";
38
- return e;
39
- }
40
27
  export function createMemoryComplianceFaces(store, opts) {
41
28
  if (!backendOwnsControlPlane(store.backend))
42
29
  return undefined;
@@ -48,15 +35,12 @@ export function createMemoryComplianceFaces(store, opts) {
48
35
  });
49
36
  return {
50
37
  provenanceOf: (entryId) => engine.provenanceOf(entryId),
51
- erase: (input, opts) => {
38
+ erase: (input) => {
52
39
  if (erasureInputSmugglesPrototypeKey(input)) {
53
40
  const e = new Error("memory erasure refused: the request carries a key that rewrites an object's prototype — such a key is not a selector, and core's selector dispatch would read it in preference to the declared one");
54
41
  e.code = "memory.erasure_selector_unsafe";
55
42
  return Promise.reject(e);
56
43
  }
57
- const refusal = erasureEnvelopeRefusal(input, opts?.allowedScopes);
58
- if (refusal !== undefined)
59
- return Promise.reject(refusal);
60
44
  return engine.eraseMemoryEntries(input);
61
45
  },
62
46
  };
@@ -23,11 +23,11 @@
23
23
  * 那几行的前缀是**条目路径**(模型可写)—— 本仓今天不读 warnings 车道(既有面,不是本批回归),也不在模型可写的文本上
24
24
  * 找码;这一半候 core 的结构化码位(登记在案,codex 一审 C3)。
25
25
  *
26
- * ## 不是这一族的三形(core 同表「different surface」,本仓**不**自拼码,如实走各自既有臂)
26
+ * ## 不是这一族的形(core 同表「different surface」,本仓**不**自拼码,如实走各自既有臂;今两形 + 一只已退的形)
27
27
  * · journal 重放目标目录成链 ⇒ `ControlPlaneCorruptError`(无 `.code`,KL-1094-b)⇒ 路由 typed 500 `internal.memory_control_plane_corrupt`
28
28
  * (core 7.44.0 起 scope home 非目录**不再**走这一类 —— 它有了自己的码,见上;`ControlPlaneCorruptError` 只剩真控制面损坏);
29
- * · 引擎原地写撞硬链(nlink>1)⇒ 文本 `has N names (a hard link)`、无码(KL-1094-g / [ref])⇒ 走该写点既有的失败车道(harvest
30
- * warnings / 挂载失败),抛出面够不着;
29
+ * · (已不存在的一形)引擎原地写撞硬链(nlink>1):≤ 引擎 7.55.x 是无码文本 `has N names (a hard link) … not written`、走该写点既有的失败车道;
30
+ * 引擎 7.56.0 起那只写给**这个名字**另建一个新文件(原子改名落位,其余名字保留原文件),拒绝与那句文本一并消失 —— 本仓从未读过那句文本,零码;
31
31
  * · 解析故障(`EACCES` / `ELOOP` / `ENOTDIR`)⇒ 以 errno 本身抛 ⇒ 路由未分类 500 + 运维 warn(`String(err)` 带 core 补救句)。
32
32
  *
33
33
  * ## 运维行也在这里铸(两受众同一只,{@link logStoreFormRefusal})
@@ -4,6 +4,12 @@ import { dirname, join } from "node:path";
4
4
  import { encodeScopeSegment, syncMemoryScope, } from "@sema-agent/core";
5
5
  import { replicationCovers } from "./memory-scope.js";
6
6
  import { parseProjectLayerKey } from "./project-layer-key.js";
7
+ const CURSOR_MISMATCH_CODE = "config.memory_sync_cursor_mismatch";
8
+ const CURSOR_PREDATES_STORE_NOTICE = "memory_sync_cursor_predates_store";
9
+ const CURSOR_PREDATES_STORE_OUTS = "this layer's sync baseline was written before sync cursors carried a store binding, so the layer does not sync until the operator picks one of two ways out: " +
10
+ "(1) run one sync round on the previous server version so deletions made since the last round reach the other side, then delete this file; " +
11
+ "(2) delete this file now to accept re-convergence from an empty baseline — entries changed on both sides are reported as conflicts, " +
12
+ "and entries deleted on one side since the last round come back from the other side";
7
13
  export const DEFAULT_MEMORY_SYNC_PEER = "central";
8
14
  export function createMemorySyncTransport(opts) {
9
15
  const base = opts.url.replace(/\/+$/, "");
@@ -25,32 +31,56 @@ export function createMemorySyncTransport(opts) {
25
31
  export function memorySyncCursorPath(memoryRoot, peer, scope) {
26
32
  return join(memoryRoot, "sync-cursors", encodeScopeSegment(peer), `${createHash("sha256").update(scope, "utf8").digest("hex").slice(0, 32)}.json`);
27
33
  }
28
- function legacyMemorySyncCursorPath(memoryRoot, peer) {
34
+ function perPeerCursorPath(memoryRoot, peer) {
29
35
  return join(memoryRoot, `sync-cursor-${encodeScopeSegment(peer)}.json`);
30
36
  }
31
- async function loadCursor(path, scope, peer, log) {
37
+ async function readCursorFile(path) {
32
38
  let raw;
33
39
  try {
34
40
  raw = await readFile(path, "utf8");
35
41
  }
36
42
  catch (err) {
37
- if (err.code !== "ENOENT")
38
- log.warn("memory_sync_cursor_read_failed", { path, err: String(err), note: "treating as first round" });
39
- return undefined;
43
+ return err.code === "ENOENT" ? { kind: "absent" } : { kind: "unreadable", err: String(err) };
40
44
  }
41
- let parsed;
42
45
  try {
43
- parsed = JSON.parse(raw);
46
+ const value = JSON.parse(raw);
47
+ return { kind: "parsed", value };
44
48
  }
45
49
  catch (err) {
46
- log.warn("memory_sync_cursor_corrupt", { path, err: String(err), note: "treating as first round" });
47
- return undefined;
50
+ return { kind: "corrupt", err: String(err) };
51
+ }
52
+ }
53
+ function predatesStoreBinding(parsed, scope, peer) {
54
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed))
55
+ return false;
56
+ const c = parsed;
57
+ return c["scope"] === scope && c["peer"] === peer && c["store"] === undefined;
58
+ }
59
+ async function loadLayerBaseline(path, perPeer, scope, peer, log) {
60
+ const read = await readCursorFile(path);
61
+ switch (read.kind) {
62
+ case "absent": {
63
+ if (perPeer === undefined)
64
+ return { kind: "none" };
65
+ const legacy = await readCursorFile(perPeer);
66
+ return legacy.kind === "parsed" && predatesStoreBinding(legacy.value, scope, peer) ? { kind: "predates-store", path: perPeer } : { kind: "none" };
67
+ }
68
+ case "unreadable":
69
+ log.warn("memory_sync_cursor_read_failed", { path, err: read.err, note: "treating as first round" });
70
+ return { kind: "none" };
71
+ case "corrupt":
72
+ log.warn("memory_sync_cursor_corrupt", { path, err: read.err, note: "treating as first round" });
73
+ return { kind: "none" };
74
+ case "parsed": {
75
+ if (predatesStoreBinding(read.value, scope, peer))
76
+ return { kind: "predates-store", path };
77
+ const cursor = cursorOf(read.value, scope, peer);
78
+ if (cursor !== undefined)
79
+ return { kind: "cursor", cursor };
80
+ log.warn("memory_sync_cursor_invalid", { path, scope, peer, note: "shape/identity mismatch — treating as first round" });
81
+ return { kind: "none" };
82
+ }
48
83
  }
49
- const cursor = cursorOf(parsed, scope, peer);
50
- if (cursor !== undefined)
51
- return cursor;
52
- log.warn("memory_sync_cursor_invalid", { path, scope, peer, note: "shape/identity mismatch — treating as first round" });
53
- return undefined;
54
84
  }
55
85
  function cursorOf(parsed, scope, peer) {
56
86
  if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
@@ -58,43 +88,18 @@ function cursorOf(parsed, scope, peer) {
58
88
  const baseRevsRaw = c["baseRevs"];
59
89
  if (c["scope"] === scope &&
60
90
  c["peer"] === peer &&
91
+ typeof c["store"] === "string" &&
61
92
  typeof c["updatedAtMs"] === "number" &&
62
93
  Number.isFinite(c["updatedAtMs"]) &&
63
94
  baseRevsRaw !== null &&
64
95
  typeof baseRevsRaw === "object" &&
65
96
  !Array.isArray(baseRevsRaw) &&
66
97
  Object.values(baseRevsRaw).every((v) => typeof v === "string" && v.length > 0)) {
67
- return { scope, peer, baseRevs: { ...baseRevsRaw }, updatedAtMs: c["updatedAtMs"] };
98
+ return { scope, peer, store: c["store"], baseRevs: { ...baseRevsRaw }, updatedAtMs: c["updatedAtMs"] };
68
99
  }
69
100
  }
70
101
  return undefined;
71
102
  }
72
- async function adoptLegacyCursor(memoryRoot, scope, peer, log) {
73
- const target = memorySyncCursorPath(memoryRoot, peer, scope);
74
- const legacy = legacyMemorySyncCursorPath(memoryRoot, peer);
75
- const facts = await Promise.all([readFile(target, "utf8").then(() => "present", (err) => (err.code === "ENOENT" ? "absent" : "present")), readFile(legacy, "utf8").then((text) => ({ text }), (err) => ({ err }))]);
76
- const [targetFact, legacyRead] = facts;
77
- if (targetFact === "present")
78
- return;
79
- if ("err" in legacyRead) {
80
- if (legacyRead.err.code !== "ENOENT")
81
- log.warn("memory_sync_cursor_read_failed", { path: legacy, err: String(legacyRead.err), note: "legacy cursor not adopted — this layer starts from its own cursor" });
82
- return;
83
- }
84
- let parsed;
85
- try {
86
- parsed = JSON.parse(legacyRead.text);
87
- }
88
- catch (err) {
89
- log.warn("memory_sync_cursor_corrupt", { path: legacy, err: String(err), note: "legacy cursor not adopted" });
90
- return;
91
- }
92
- if (cursorOf(parsed, scope, peer) === undefined)
93
- return;
94
- await mkdir(dirname(target), { recursive: true });
95
- await rename(legacy, target);
96
- log.info("memory_sync_cursor_adopted", { from: legacy, to: target, scope, peer });
97
- }
98
103
  async function saveCursor(path, cursor) {
99
104
  await mkdir(dirname(path), { recursive: true });
100
105
  const tmp = `${path}.tmp.${process.pid}.${randomBytes(4).toString("hex")}`;
@@ -110,7 +115,6 @@ export function createMemorySyncRunner(opts) {
110
115
  const peer = opts.peer ?? DEFAULT_MEMORY_SYNC_PEER;
111
116
  const coverage = { kind: "layers", layers: [opts.scope] };
112
117
  const tracked = new Set();
113
- let legacyCursorChecked = false;
114
118
  let enumerationWarned = false;
115
119
  const isCoveredProjectLayer = (scope) => scope !== opts.scope && parseProjectLayerKey(scope) !== undefined && replicationCovers(coverage, scope);
116
120
  const layersOfRound = () => {
@@ -124,21 +128,36 @@ export function createMemorySyncRunner(opts) {
124
128
  };
125
129
  const syncLayer = async (scope, reason) => {
126
130
  const cursorPath = memorySyncCursorPath(opts.memoryRoot, peer, scope);
127
- let cursor = await loadCursor(cursorPath, scope, peer, opts.log);
131
+ const baseline = await loadLayerBaseline(cursorPath, scope === opts.scope ? perPeerCursorPath(opts.memoryRoot, peer) : undefined, scope, peer, opts.log);
132
+ if (baseline.kind === "predates-store") {
133
+ opts.log.warn(CURSOR_PREDATES_STORE_NOTICE, { scope, peer, path: baseline.path, note: CURSOR_PREDATES_STORE_OUTS });
134
+ throw new Error(`memory sync: layer ${JSON.stringify(scope)} not synced — its baseline ${baseline.path} predates the store binding (see warn ${CURSOR_PREDATES_STORE_NOTICE})`);
135
+ }
136
+ let cursor = baseline.kind === "cursor" ? baseline.cursor : undefined;
128
137
  let result;
129
138
  let subRound = 0;
130
139
  for (;;) {
131
140
  subRound += 1;
132
- result = await syncMemoryScope({
133
- backend: opts.backend,
134
- scope,
135
- transport: opts.transport,
136
- peer,
137
- ...(cursor !== undefined ? { cursor } : {}),
138
- ...(opts.now !== undefined ? { now: opts.now } : {}),
139
- ...(opts.maxPushEntries !== undefined ? { maxPushEntries: opts.maxPushEntries } : {}),
140
- ...(opts.maxPullEntries !== undefined ? { maxPullEntries: opts.maxPullEntries } : {}),
141
- });
141
+ try {
142
+ result = await syncMemoryScope({
143
+ backend: opts.backend,
144
+ scope,
145
+ transport: opts.transport,
146
+ peer,
147
+ ...(cursor !== undefined ? { cursor } : {}),
148
+ ...(opts.now !== undefined ? { now: opts.now } : {}),
149
+ ...(opts.maxPushEntries !== undefined ? { maxPushEntries: opts.maxPushEntries } : {}),
150
+ ...(opts.maxPullEntries !== undefined ? { maxPullEntries: opts.maxPullEntries } : {}),
151
+ });
152
+ }
153
+ catch (err) {
154
+ if (cursor === undefined || err?.code !== CURSOR_MISMATCH_CODE)
155
+ throw err;
156
+ opts.log.warn("memory_sync_cursor_rebound", { scope, peer, subRound, note: "the persisted cursor is bound to another store — running this round from no cursor and replacing it" });
157
+ cursor = undefined;
158
+ subRound -= 1;
159
+ continue;
160
+ }
142
161
  for (const w of result.warnings ?? [])
143
162
  opts.log.warn("memory_sync_warning", { scope, peer, subRound, warning: w });
144
163
  if (!(result.pushTruncated === true || result.pullTruncated === true))
@@ -192,10 +211,6 @@ export function createMemorySyncRunner(opts) {
192
211
  return result;
193
212
  };
194
213
  const round = async (reason) => {
195
- if (!legacyCursorChecked) {
196
- legacyCursorChecked = true;
197
- await adoptLegacyCursor(opts.memoryRoot, opts.scope, peer, opts.log);
198
- }
199
214
  const layers = [];
200
215
  const failures = [];
201
216
  for (const scope of layersOfRound()) {
@@ -2,7 +2,7 @@ import { type MemoryBackend, type MemoryEntry, type PatchReport } from "@sema-ag
2
2
  import type { MemorySyncStore } from "./plugins/memory-sync-store-pg.js";
3
3
  /** 一轮同步请求(验型后的干净形状——`parseMemorySyncRequest` 是唯一铸造点)。 */
4
4
  export interface MemorySyncRequest {
5
- /** 对端标识(MemorySyncCursor.peer,per-(scope,peer) 游标分区键)。 */
5
+ /** 对端标识(`CentralSyncCursor.peer`,per-(scope,peer) 游标分区键)。 */
6
6
  peer: string;
7
7
  /** 客户端游标的共同基线:id → rev at last completed sync round(空 map = 首轮)。 */
8
8
  baseRevs: Record<string, string>;
@@ -49,6 +49,8 @@ export interface CatalogEntryLike {
49
49
  readonly api?: unknown;
50
50
  /** [ref]:供应商附加头的承载形(`unknown`:判据在 `model-entry-headers.ts`,不信这张型)。 */
51
51
  readonly headers?: unknown;
52
+ /** 引擎已退役的每模型引导句(core 7.56.0 [ref];settings-schema 的 `ModelEntry` 仍收它)—— 只读在场与否,见 {@link judgeCatalogEntry}。 */
53
+ readonly promptGuidance?: unknown;
52
54
  }
53
55
  /**
54
56
  * **逐条判据**:`undefined` = 本部署能完整服务它。判序即语义:先形(不合形的条目谈不上走哪条腿),再腿。
@@ -31,6 +31,17 @@ export function judgeCatalogEntry(m, ctx) {
31
31
  const headers = readCatalogEntryHeaders(m.headers, m.api);
32
32
  if (!headers.ok)
33
33
  return entryInvalidRefusal(m.id, m.provider, headers.fields, headers.issue);
34
+ if (Array.isArray(m.promptGuidance) && m.promptGuidance.length > 0) {
35
+ return {
36
+ ...refusalCause("config.model_entry_invalid"),
37
+ id: m.id,
38
+ provider: m.provider,
39
+ fields: ["promptGuidance"],
40
+ detail: "the catalog entry carries per-model guidance sentences (promptGuidance), which the engine no longer delivers — the entry is not served here " +
41
+ "rather than served with its sentences silently dropped; move each sentence into a center or deployment prompt overlay on the behavior band " +
42
+ "and remove promptGuidance from the entry to bring it back",
43
+ };
44
+ }
34
45
  const lane = catalogBrainLane(m.provider);
35
46
  const mount = laneMount(lane, ctx);
36
47
  if (!mount.mounted) {
@@ -1,23 +1,3 @@
1
- /**
2
- * **env 模型路由读数的唯一读口**:`readModelRouteEnv(env)`、env 腿的条目表 `envLaneTable`,与车道值级端口 `laneAndEndpointFor`。
3
- *
4
- * ## 形(一只读口、一处调用)
5
- * 「env 里哪几把键是模型路由、空串 = 未设、provider 的显式 / 推断 / 缺省、env 腿铸哪几个条目槽」的读法只在这里:
6
- * · {@link readModelRouteEnv}:`parseModelDomain`(`config.ts`,起服铸 `ServiceConfig` 的路由字段)吃它的读数(`process.env` 与测试快照是同一个入参位);
7
- * · {@link envLaneTable}:env 腿的条目名与键序(`parseModelDomain` 铸真 `Model` 表经它);
8
- * · {@link laneAndEndpointFor}:值级端口 —— 「这只模型在这张路由表上走哪条车道、这条车道的端点 / 凭据取哪一对 env 键」。车道只经 `brainLaneFor`
9
- * (core `brainLaneOf` 对路由表的答案)取,键名取 {@link MODEL_ROUTE_ENV_KEYS};**只交键名不交值**。
10
- * 路由判据本身(「将要服务的那张表里每条 openai 兼容路由是否解析得到端点」)不在这里:唯一属主是 `model-route-endpoint.ts` 的 `judgeModelRouteEndpoint`,
11
- * 起服段与 `GET /v1/models.modelPlane` 经 `judgeServedModelRoute` 问它 —— 它们判的是**将要服务的那张表**(env 表或目录表),不是本文件读出的 env 视图。
12
- *
13
- * ## 对外
14
- * 本模块的精选再导出是子路径 `@sema-agent/server/model-route-env`(`src/model-route-env.ts`):引擎 core 是 BYOM(只吃调用方给的路由表,不读这些键),
15
- * 别仓要在引擎起之前回答「走哪条车道、端点 / 凭据取哪一对键」,读这一只,不各抄一份键名与车道判。
16
- *
17
- * ## 纯
18
- * 不读 `process.env`、不读文件、不枚举快照 —— 只按 {@link MODEL_ROUTE_ENV_KEYS} 点名取值(依赖闭包里没有 `node:*` / `process`,
19
- * `test/model-route-env-reading.test.ts` 钉)。同入同出;返回值是新对象。provider 词域外的值在这里按引擎派发的口径读作网关腿(`brainLaneFor`:域外词的路由表里没有那个键 ⇒ 引擎路由器落网关 fallback),不在此拒(域外拒启是 `model-provider-word` 那条不变量的事)。
20
- */
21
1
  import { type ModelBrainLane } from "./model-provider.js";
22
2
  /**
23
3
  * 路由读数读的九把 env 键(**闭表**;{@link readModelRouteEnv} 只碰这几把,测试用代理钉「读集 ⊆ 本表」)。
@@ -59,8 +39,9 @@ export interface ModelRouteEnvReading {
59
39
  /** `MODEL_GATEWAY_FALLBACK_URLS` 逐项 trim、丢空项。 */
60
40
  readonly gatewayFallbackUrls: string[];
61
41
  /**
62
- * `MODEL_API_KEY`(网关腿的部署级凭据):**原样**读 —— 与其余各把不同,空串**不**折成未设。brain 装配以**真值**判这把凭据发不发(空串部署一个凭据字节都不发),
42
+ * `MODEL_API_KEY`(网关腿的部署级凭据):读数**原样**交出 —— 与其余各把不同,空串**不**折成未设:
63
43
  * 起服铸的 `ServiceConfig.gatewayApiKey` 逐字保留空串(compose 的 `${VAR:-}` 模板与空 Secret 挂载天天产它);读数改折叠会改变那一位。
44
+ * 「这把凭据设了没有」的问法不在读数里折,而是消费方问 {@link declaredCredential}(引擎的 `isBlankCredential`:空串与只含空白都 = 没有)。
64
45
  * 它只与网关端点配对(没有 {@link gatewayBaseUrl} 就不装载),配对由消费方判。
65
46
  */
66
47
  readonly gatewayApiKey: string | undefined;
@@ -85,6 +66,9 @@ export interface ModelRouteEnvReading {
85
66
  /** cheap 槽铸不铸(见 {@link EnvCheapSlot})。 */
86
67
  readonly cheapSlot: EnvCheapSlot;
87
68
  }
69
+ /** 一把凭据键「设了没有」的唯一问法(两把 anthropic 键与网关键 `MODEL_API_KEY` 同读):引擎的 `isBlankCredential`(整串 trim 后为空 ⇒ 没有凭据)—— 与引擎对同一个值的读法同一只,
70
+ * 不自拼第二种「空」:只含空白的 key 旁边的 token 是 bearer(引擎让那只头作凭据照发),不是同设冲突;两把都空白 = 缺席、路由不挂;只含空白的网关 key = 没有部署凭据。 */
71
+ export declare const declaredCredential: (v: string | undefined) => string | undefined;
88
72
  /** 逗号串读法的归一点:逐项 trim、丢空项(缺席 = 空串 = `[]`)。本文件的 CSV 路由键与 `config.ts` 的逗号串旋钮(按名薄壳 `csv(name)`)同读这一只;
89
73
  * 目录模块的回显分词与 `SERVICE_AUTH_TOKENS` 的 `k=v` 对分词是同形的另两处,尚未改调(清账版收,本函数届时挪到中性模块)。 */
90
74
  export declare const csvOf: (raw: string | undefined) => string[];
@@ -98,7 +82,7 @@ export declare function readModelRouteEnv(env: ModelRouteEnv): ModelRouteEnvRead
98
82
  * · `ANTHROPIC_API_KEY` ⇒ `x-api-key`(只发它);
99
83
  * · `ANTHROPIC_AUTH_TOKEN` ⇒ `Authorization: Bearer`(只发它);
100
84
  * · 两个都设 ⇒ `conflict`:两个名字说的是两种头,哪个赢都是替运维猜(7.135.0 及以前是「AUTH_TOKEN 优先」,x-api-key 被静默丢弃)⇒ 起服拒启,拒句 {@link anthropicCredentialRefusal}。
101
- * 空串 = 未设(与 {@link readModelRouteEnv} 同尺)。入参是两个名字各自的值 —— env 读数的两位或 `config.anthropic` 的 `apiKey` / `authToken` —— 不读 `process.env`。
85
+ * 「设了没有」按引擎的 `isBlankCredential` 读(空串与只含空白都 = 未设;与 {@link declaredCredential} 同一只)。入参是两个名字各自的值 —— env 读数的两位或 `config.anthropic` 的 `apiKey` / `authToken` —— 不读 `process.env`。
102
86
  * 读者:起服(`config.ts` 的拒启锚与跨键不变量表 `anthropic-credential-exclusive` 同一句)· brain 装配(交引擎哪种头)· hook 直连腿(哪种头、交引擎配对判官的那份值)·
103
87
  * 车道端口 {@link laneAndEndpointFor}(哪把键)· 起服的 Bearer 部署诊断(`boot/web-admin.ts`)。
104
88
  */