@sema-agent/server 7.135.0 → 7.136.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 (185) hide show
  1. package/MIGRATION.md +64 -2
  2. package/USAGE.md +62 -25
  3. package/deploy/sema-up/README.md +1 -1
  4. package/deploy/sema-up/chart/templates/NOTES.txt +1 -1
  5. package/deploy/sema-up/chart/values.yaml +1 -1
  6. package/dist/approval-card.d.ts +60 -4
  7. package/dist/approval-card.js +18 -1
  8. package/dist/approval-content-kind.d.ts +1 -0
  9. package/dist/approval-content-kind.js +1 -1
  10. package/dist/auth-bridge.d.ts +34 -5
  11. package/dist/auth-bridge.js +20 -3
  12. package/dist/boot/budget-tracing.d.ts +1 -2
  13. package/dist/boot/budget-tracing.js +2 -2
  14. package/dist/boot/org-memory.js +1 -1
  15. package/dist/boot/resolve-spec.js +10 -7
  16. package/dist/boot/runner-deps.js +4 -2
  17. package/dist/boot/stage-04-stores.d.ts +1 -1
  18. package/dist/boot/stage-05-execution-env.d.ts +1 -1
  19. package/dist/boot/stage-06-runners.d.ts +1 -1
  20. package/dist/boot/stage-07-capability-layer.d.ts +1 -1
  21. package/dist/boot/stage-08-reapers.d.ts +1 -1
  22. package/dist/boot/stage-09-leader.d.ts +1 -1
  23. package/dist/boot/stage-10-http-server.d.ts +1 -1
  24. package/dist/boot/stores.js +2 -3
  25. package/dist/boot/web-admin.js +10 -17
  26. package/dist/brain.js +12 -3
  27. package/dist/budget.d.ts +3 -3
  28. package/dist/budget.js +4 -0
  29. package/dist/capabilities/mcp-probe.d.ts +5 -4
  30. package/dist/capability-facts.d.ts +3 -7
  31. package/dist/capability-facts.js +3 -5
  32. package/dist/center-credential.d.ts +18 -4
  33. package/dist/center-credential.js +18 -3
  34. package/dist/config-catalog.js +12 -10
  35. package/dist/config-d-migration.js +1 -1
  36. package/dist/config-invariants.d.ts +1 -1
  37. package/dist/config-invariants.js +8 -0
  38. package/dist/config-lkg.d.ts +0 -38
  39. package/dist/config-lkg.js +1 -83
  40. package/dist/config-types.d.ts +12 -4
  41. package/dist/config.js +26 -8
  42. package/dist/deployment-shape.d.ts +1 -1
  43. package/dist/elicitation.d.ts +8 -7
  44. package/dist/elicitation.js +9 -8
  45. package/dist/file-history-disclosure.d.ts +6 -4
  46. package/dist/file-history-disclosure.js +22 -6
  47. package/dist/fleet-client.d.ts +32 -1
  48. package/dist/fleet-client.js +24 -4
  49. package/dist/fleet-lease.d.ts +7 -3
  50. package/dist/fleet-lease.js +31 -23
  51. package/dist/hooks/hook-llm.js +14 -8
  52. package/dist/hooks/hook-runner.d.ts +4 -4
  53. package/dist/hooks/hook-runner.js +2 -2
  54. package/dist/http/checkpoint-ctx.d.ts +28 -9
  55. package/dist/http/checkpoint-ctx.js +5 -1
  56. package/dist/http/dispatch.js +9 -9
  57. package/dist/http/resume-ctx-read.d.ts +2 -16
  58. package/dist/http/resume-ctx-read.js +2 -3
  59. package/dist/http/routes/approvals-assistant.d.ts +0 -2
  60. package/dist/http/routes/approvals-assistant.js +47 -12
  61. package/dist/http/routes/runs.js +2 -2
  62. package/dist/http/routes/session-sync.js +31 -9
  63. package/dist/http/routes/sessions.js +18 -14
  64. package/dist/http/submit-ctx.js +1 -1
  65. package/dist/http/wire-types.d.ts +5 -3
  66. package/dist/index.d.ts +1 -0
  67. package/dist/index.js +1 -0
  68. package/dist/model-route-gap.d.ts +49 -4
  69. package/dist/model-route-gap.js +34 -1
  70. package/dist/object-store-buckets.d.ts +13 -0
  71. package/dist/object-store-buckets.js +3 -0
  72. package/dist/observability/fail-open.d.ts +6 -6
  73. package/dist/observability/fail-open.js +6 -6
  74. package/dist/observability/metrics.js +1 -1
  75. package/dist/observability/principal-context.d.ts +4 -1
  76. package/dist/observability/principal-context.js +6 -1
  77. package/dist/parked-decide.d.ts +4 -3
  78. package/dist/parked-decide.js +26 -7
  79. package/dist/peer-directory.d.ts +2 -1
  80. package/dist/peer-directory.js +5 -5
  81. package/dist/plugins/approval-ask-store-sql.d.ts +8 -0
  82. package/dist/plugins/approval-ask-store-sql.js +3 -0
  83. package/dist/plugins/blob-backend.js +2 -1
  84. package/dist/plugins/checkpoint-index-columns.d.ts +50 -1
  85. package/dist/plugins/checkpoint-index-columns.js +28 -0
  86. package/dist/plugins/checkpoint-store-sql.d.ts +27 -3
  87. package/dist/plugins/checkpoint-store-sql.js +58 -29
  88. package/dist/plugins/file-history-store-sql.d.ts +6 -0
  89. package/dist/plugins/file-history-store-sql.js +30 -23
  90. package/dist/plugins/local-checkpoint-store.js +4 -3
  91. package/dist/plugins/one-time-migrations.d.ts +21 -28
  92. package/dist/plugins/one-time-migrations.js +39 -123
  93. package/dist/plugins/remote-env-k8s.d.ts +18 -5
  94. package/dist/plugins/remote-env-k8s.js +24 -7
  95. package/dist/plugins/s3-answer.d.ts +15 -0
  96. package/dist/plugins/s3-answer.js +5 -0
  97. package/dist/plugins/snapshot-bucket-presence.d.ts +39 -4
  98. package/dist/plugins/snapshot-bucket-presence.js +35 -7
  99. package/dist/plugins/sql-errors.d.ts +39 -0
  100. package/dist/plugins/sql-errors.js +49 -1
  101. package/dist/plugins/store-fault.d.ts +4 -0
  102. package/dist/plugins/store-fault.js +8 -0
  103. package/dist/plugins/tidb-pool.js +1 -1
  104. package/dist/plugins/web-search.d.ts +1 -1
  105. package/dist/plugins/web-search.js +2 -2
  106. package/dist/request-declaration-refusal.d.ts +94 -0
  107. package/dist/request-declaration-refusal.js +78 -0
  108. package/dist/request-image-urls.d.ts +6 -0
  109. package/dist/request-image-urls.js +27 -0
  110. package/dist/request-key-closure.d.ts +5 -0
  111. package/dist/request-key-closure.js +4 -1
  112. package/dist/runtime-caps-resolver.js +1 -1
  113. package/dist/sandbox-pkg-source.d.ts +28 -1
  114. package/dist/sandbox-pkg-source.js +1 -2
  115. package/dist/sealed-key.d.ts +19 -0
  116. package/dist/sealed-key.js +47 -4
  117. package/dist/session-incarnation.d.ts +16 -5
  118. package/dist/session-incarnation.js +7 -4
  119. package/dist/session-row.d.ts +3 -17
  120. package/dist/session-row.js +4 -0
  121. package/dist/session-sync.d.ts +15 -3
  122. package/dist/session-sync.js +5 -2
  123. package/dist/task-a2a.d.ts +52 -81
  124. package/dist/task-a2a.js +219 -89
  125. package/dist/task-mcp.d.ts +6 -14
  126. package/dist/task-mcp.js +16 -51
  127. package/dist/tool-approval.d.ts +23 -10
  128. package/dist/tool-approval.js +51 -36
  129. package/dist/trace/core-keyset-guard.d.ts +2 -2
  130. package/dist/trace/exit-seat.js +37 -13
  131. package/dist/trace/redact.d.ts +28 -12
  132. package/dist/trace/redact.js +233 -94
  133. package/dist/trace/self-minted-wire.d.ts +267 -0
  134. package/dist/trace/self-minted-wire.js +79 -0
  135. package/dist/url-credential-refusal.d.ts +52 -0
  136. package/dist/url-credential-refusal.js +14 -0
  137. package/dist/url-refusal.d.ts +13 -4
  138. package/dist/url-refusal.js +8 -2
  139. package/dist/workspace-space.d.ts +27 -0
  140. package/dist/workspace-space.js +26 -0
  141. package/package.json +3 -2
  142. package/scripts/drain-check-local.mjs +2 -1
  143. package/scripts/drain-check.mysql.sql +3 -1
  144. package/scripts/drain-check.pg.sql +3 -1
  145. package/skills/schedule.md +1 -1
  146. package/wire-changes/server@7.104.0.json +134 -0
  147. package/wire-changes/server@7.105.0.json +53 -0
  148. package/wire-changes/server@7.106.0.json +475 -0
  149. package/wire-changes/server@7.107.0.json +64 -0
  150. package/wire-changes/server@7.108.0.json +153 -0
  151. package/wire-changes/server@7.109.0.json +46 -0
  152. package/wire-changes/server@7.110.0.json +90 -0
  153. package/wire-changes/server@7.111.0.json +86 -0
  154. package/wire-changes/server@7.112.0.json +60 -0
  155. package/wire-changes/server@7.113.0.json +26 -0
  156. package/wire-changes/server@7.114.0.json +26 -0
  157. package/wire-changes/server@7.115.0.json +97 -0
  158. package/wire-changes/server@7.116.0.json +218 -0
  159. package/wire-changes/server@7.116.1.json +26 -0
  160. package/wire-changes/server@7.117.0.json +65 -0
  161. package/wire-changes/server@7.118.0.json +129 -0
  162. package/wire-changes/server@7.119.0.json +65 -0
  163. package/wire-changes/server@7.120.0.json +89 -0
  164. package/wire-changes/server@7.121.0.json +219 -0
  165. package/wire-changes/server@7.122.0.json +54 -0
  166. package/wire-changes/server@7.123.0.json +26 -0
  167. package/wire-changes/server@7.124.0.json +336 -0
  168. package/wire-changes/server@7.124.1.json +26 -0
  169. package/wire-changes/server@7.125.0.json +111 -0
  170. package/wire-changes/server@7.126.0.json +285 -0
  171. package/wire-changes/server@7.127.0.json +77 -0
  172. package/wire-changes/server@7.127.1.json +26 -0
  173. package/wire-changes/server@7.127.2.json +53 -0
  174. package/wire-changes/server@7.128.0.json +26 -0
  175. package/wire-changes/server@7.129.0.json +106 -0
  176. package/wire-changes/server@7.129.1.json +26 -0
  177. package/wire-changes/server@7.130.0.json +26 -0
  178. package/wire-changes/server@7.131.0.json +118 -0
  179. package/wire-changes/server@7.132.0.json +226 -0
  180. package/wire-changes/server@7.133.0.json +1155 -0
  181. package/wire-changes/server@7.134.0.json +107 -0
  182. package/wire-changes/server@7.135.0.json +174 -0
  183. package/wire-changes/server@7.136.0.json +448 -0
  184. package/dist/url-credential.d.ts +0 -52
  185. package/dist/url-credential.js +0 -49
@@ -21,7 +21,7 @@
21
21
  * 没有方法、没有捕获的行为。
22
22
  */
23
23
  import { z } from "zod";
24
- import { ALLOW_RULE_MEMBERS, READ_ROOT_CANDIDATE_DIR_MAX, type AskClass, type AskEvidenceAbsence, type PendingAction as CorePendingAction, type ReadRootGrantCandidate, type ResumeStartupCause, type RuleOffer, type RuleOffersAbsence as CoreRuleOffersAbsence, type SteerReplayFacet } from "@sema-agent/core";
24
+ import { ALLOW_RULE_MEMBERS, READ_ROOT_CANDIDATE_DIR_MAX, type AskClass, type AskEvidenceAbsence, type CheckpointSummary as CoreCheckpointSummary, type PendingAction as CorePendingAction, type ReadRootGrantCandidate, type ResumeStartupCause, type RuleOffer, type RuleOffersAbsence as CoreRuleOffersAbsence, type SteerReplayFacet, type ToolApprovalCard } from "@sema-agent/core";
25
25
  import type { AskRow } from "./plugins/approval-ask-store-sql.js";
26
26
  import type { SettleCause, SettleOutcome } from "./approval-deny-reasons.js";
27
27
  import type { ToolApprovalFrame } from "./tool-approval.js";
@@ -440,7 +440,7 @@ export interface AskClassPair {
440
440
  * [ref] ②(core 7.37.0 [ref])第六 / 七位 `askClass` / `classes`:这一问的类对(经 {@link readAskClassPair};两位同在同缺,与活卡帧 / 呈卡帧的卡
441
441
  * 同名同义同值)—— durable 审批席按类答的依据。缺席 = 老行(core 7.37.0 之前 park 的,续跑不补)/ 读不出(计 [ref] tag)。
442
442
  * [ref](core 7.51.0 [ref])第八位 `boundGrantAbsence`:这张卡为什么没有授予绑定摘要(经 {@link readClosedWordSeat};与活卡帧 / inbox 行同名同义同值)——
443
- * `not_bindable` = 这一问不绑任何授予(「本会话放行」可按工具记)。缺席 = 技能卡(带摘要;摘要不上队列行,见 ⑧b)/ 7.51.0 之前停驻的行(core inbox 投
443
+ * `not_bindable` = 这一问不绑任何授予(「本会话放行」可按工具记)。缺席 = 技能卡(带摘要;摘要与清单、成因词三位走另一只投影 {@link skillCardFacts},见其顶注)/ 7.51.0 之前停驻的行(core inbox 投
444
444
  * `unreadable`,队列行如实缺席)/ 集外词(计 [ref] tag)。
445
445
  */
446
446
  export type ParkRowFacts = Pick<ToolApprovalPark, "requiresRealApproval" | "ruleOffersAbsence" | "mandated" | "mandate" | "origin" | "askClass" | "classes" | "boundGrantAbsence">;
@@ -471,6 +471,32 @@ export type ParkRowFacts = Pick<ToolApprovalPark, "requiresRealApproval" | "rule
471
471
  * 不许拿本函数的产物去推强制 —— 两者共用的是 schema,不是折叠。
472
472
  */
473
473
  export declare function parkRowFacts(stored: unknown): ParkRowFacts;
474
+ /**
475
+ * 🔴 **技能卡三位的唯一投影**:授予绑定摘要 `boundGrantDigest`、它哈希的清单 `boundGrants`、分类器没给判词的成因 `classifierNoRuling` ——
476
+ * 助手收件箱行(`GET /v1/assistant/inbox`)、运维队列行(`GET /v1/approvals` 的 `pending[]`)、`/v1/approvals/stream` 的 `pending` 帧三张停驻读面
477
+ * **经这一只函数**投它们。同一张停驻的技能卡于是三面同一份字节:运维从队列决这张卡时,看得到批准它还授予了什么。
478
+ *
479
+ * **输入恒是 core 的检查点摘要**({@link CoreCheckpointSummary},`summarizeCheckpoint` 的产物)—— 三位的校验点单点在 core:摘要是串才回显;清单**只在哈希等于摘要时**才发布
480
+ * (「never a list beside a digest that binds another」—— 一份与摘要对不上的清单会让批准人看着一份清单、批的却是另一份绑定);成因词只在闭集成员时回显。
481
+ * 本仓**不重算哈希**(core 的 `boundInputHashOf` 不在公开导出面上,清单校验读口 `readBoundBinding` 同样不导出),所以**不许**拿寄存行 `pendingAction` 上的原值直接投 ——
482
+ * 原值上的清单是未经哈希校验的(这正是三位此前不上队列行的原因,见 `trace/core-keyset-guard.ts` ⑧b 记账的旧注)。两只店各自拿到「这一行的摘要」的办法不同
483
+ * (LOCAL 孪生本来就握着 core 对同一行投的摘要;SQL 孪生对带三位之一的行读一次该行再调 core 的 `summarizeCheckpoint`,见 `plugins/checkpoint-store-sql.ts`),
484
+ * 但投影只有这一只:OMIT 契约 —— 缺席即缺席,恒不铸 `undefined` 值的键。
485
+ *
486
+ * `boundGrants` 是**部署文本**(技能名、清单条目):本函数不脱敏、不转义,与收件箱行逐字同口径 —— 渲染按上下文转义是客户端的事(契约同句)。
487
+ * 三位都不进 `card_json`(同步路铸点,另一条纪律)。
488
+ *
489
+ * 🚧 清单校验读口 `readBoundBinding` 若成为 core 的公开导出,SQL 孪生那一次整行读与 {@link parkRowCarriesSkillCardFacts} 一并退役:`parkRowFacts` 直接读寄存行原值经 core 的读口投三位。
490
+ */
491
+ export type SkillCardFacts = Pick<CoreCheckpointSummary, "boundGrantDigest" | "boundGrants" | "classifierNoRuling">;
492
+ export declare function skillCardFacts(summary: SkillCardFacts): SkillCardFacts;
493
+ /**
494
+ * 这一行的寄存行(`pendingAction`,读自持久层 ⇒ `unknown`)**有没有可能**让 core 的摘要投出三位里的任何一位 —— 只回答「值不值得为它取一次摘要」,**不投值**:
495
+ * `tool_approval` 臂上摘要字段是串(core 只在这时回显摘要与清单),或成因词键在场(是不是闭集成员由 core 的摘要判)。判错的方向只有一个 —— 多取一次摘要(摘要读数为空),
496
+ * 绝不漏取:摘要字段不是串 ⇒ core 的摘要既无摘要也无清单;成因词键不在 ⇒ 无成因词 —— 两者都不满足的行,摘要里这三位恒空。普通卡(绝大多数行)因此零额外读。
497
+ * 只读键在不在 / 是不是串,不读值的内容,所以不需要 {@link readClosedWordSeat} 那样的计数。
498
+ */
499
+ export declare function parkRowCarriesSkillCardFacts(stored: unknown): boolean;
474
500
  /** [ref](core 7.4.0 [ref])—— 回落卡的计数与窗。`limit` 是**闭二词**(core d.ts 逐字),两个计数是
475
501
  * 非负整数,`autoDenyAfterMs` 是 core 契约里的 `0..2147483647` 非负整数(`0` = 本卡不武装窗:部署把
476
502
  * 旋钮关了,或 TOTAL 档的卡按 [ref]① 恒 0 等人)。四成员**全必填**——core 的 `DenialLimitFallback` 上
@@ -524,6 +550,18 @@ export declare const ApprovalCardSchema: z.ZodObject<{
524
550
  }, z.core.$strict>;
525
551
  governanceForced: z.ZodOptional<z.ZodLiteral<true>>;
526
552
  rememberRefused: z.ZodOptional<z.ZodLiteral<true>>;
553
+ approvalCard: z.ZodOptional<z.ZodEnum<{
554
+ question: "question";
555
+ plan: "plan";
556
+ skill: "skill";
557
+ shell: "shell";
558
+ workflow: "workflow";
559
+ "file-edit": "file-edit";
560
+ "file-write": "file-write";
561
+ "notebook-edit": "notebook-edit";
562
+ fetch: "fetch";
563
+ generic: "generic";
564
+ }>>;
527
565
  inputHasBidi: z.ZodOptional<z.ZodLiteral<true>>;
528
566
  allowRuleShadowed: z.ZodOptional<z.ZodArray<z.ZodObject<{
529
567
  member: z.ZodEnum<{
@@ -664,6 +702,18 @@ export declare const ApprovalCardEnvelopeSchema: z.ZodObject<{
664
702
  }, z.core.$strict>;
665
703
  governanceForced: z.ZodOptional<z.ZodLiteral<true>>;
666
704
  rememberRefused: z.ZodOptional<z.ZodLiteral<true>>;
705
+ approvalCard: z.ZodOptional<z.ZodEnum<{
706
+ question: "question";
707
+ plan: "plan";
708
+ skill: "skill";
709
+ shell: "shell";
710
+ workflow: "workflow";
711
+ "file-edit": "file-edit";
712
+ "file-write": "file-write";
713
+ "notebook-edit": "notebook-edit";
714
+ fetch: "fetch";
715
+ generic: "generic";
716
+ }>>;
667
717
  inputHasBidi: z.ZodOptional<z.ZodLiteral<true>>;
668
718
  allowRuleShadowed: z.ZodOptional<z.ZodArray<z.ZodObject<{
669
719
  member: z.ZodEnum<{
@@ -806,6 +856,9 @@ export interface ApprovalCardSource {
806
856
  governanceForced?: true;
807
857
  /** 7.116.0 S4:「本会话放行」不会被记住(帧上同名键,见 `ApprovalCardSchema.rememberRefused`)。 */
808
858
  rememberRefused?: true;
859
+ /** 7.136.0:引擎铸的卡词 —— 与 wire 帧**同一份素材**(发帧点经 `readApprovalCard` 读定的那一格)⇒ 活卡帧 / `approval_request` 的卡 / `card_json` /
860
+ * 重放帧四面同源(见 `ApprovalCardSchema.approvalCard`)。 */
861
+ approvalCard?: ToolApprovalCard;
809
862
  /** E-14:bidi 在场位 —— 与 wire 帧**同一份素材**(`ToolApprovalFrame` 结构上满足本接口)⇒ live 帧 /
810
863
  * `approval_request` / `card_json` / 重放帧四面同源,不是四处各扫一遍。 */
811
864
  inputHasBidi?: true;
@@ -880,7 +933,7 @@ export declare function buildApprovalRequestFrame(input: {
880
933
  /**
881
934
  * 🔴 **呈卡帧的活面事实座**(呈卡腿上旧族退役之后,开卡帧的全部事实都由本族承载)。
882
935
  *
883
- * 这十个座是活卡帧 `tool_approval` 上有、而卡(`ApprovalCardSchema`,`card_json` 的耐久信封)上**没有**的那几位:
936
+ * 这十个座是活卡帧 `tool_approval` 上有、而卡(`ApprovalCardSchema`,`card_json` 的耐久信封)上**没有**的那几位(`approvalCard` 7.136.0 起也在卡上,见本注末段):
884
937
  * 卡外的事实此前只骑活卡帧,呈卡腿的消费方靠「两帧按 approvalId 合读」拿到它们。呈卡腿自此只发本族帧 ⇒ 它们挪到**活铸**的
885
938
  * 呈卡帧顶层,同名同型同值 —— 值取自同一只帧对象(活卡帧的那一次铸定,`tool-approval.ts` 的 `askBroadcast`),本仓不另算一遍。
886
939
  *
@@ -889,6 +942,9 @@ export declare function buildApprovalRequestFrame(input: {
889
942
  * (`readRootCandidate` 有不进卡的硬理由:耐久面兑现不了它,见活卡帧该座顶注)。
890
943
  *
891
944
  * `requiresRealApproval` 不在表里:卡上 `risk.requiresRealApproval` 是同一个事实(铸卡第三参就是它),一个事实一个读法。
945
+ * ⚠️ **`approvalCard` 是表里唯一一位 7.136.0 起同时在卡上的座**(`ApprovalCardSchema.approvalCard`:断连重放的卡要渲回同一张专卡,卡词必须进卡;
946
+ * 同一次读定、同值)。按上一句的规矩它该离表(活铸帧顶层这一份退役 —— wire BREAKING,下游 sdk 的孪生表同改),本版按 additive 交付、未退役:
947
+ * 一个事实两处读,登记为待收的债,收法 = 离表 + 消费方改读 `card.approvalCard`,不是在这里加第三处。
892
948
  */
893
949
  export declare const APPROVAL_REQUEST_LIVE_FACT_KEYS: readonly ["mandated", "mandate", "origin", "boundGrantDigest", "boundGrants", "classifierNoRuling", "boundGrantAbsence", "approvalCard", "readRootCandidate", "probeReason"];
894
950
  /** 呈卡帧活面事实座的类型面 = 活卡帧同名座的 `Pick`(同型由构造保证,不手抄)。 */
@@ -1015,7 +1071,7 @@ export declare function buildRevokeFrame(batchId: string, askIds: readonly strin
1015
1071
  * 过窗未收敛的行(`expiresInMs === 0`)**仍然重放**,不在这里代打 `expireAsk` CAS(那会制造第五个
1016
1072
  * 竞争者;收敛是车2 的窗到期竞争者与车5 恢复扫描的职责)。
1017
1073
  */
1018
- export declare function buildReplayFrame(row: AskRow, nowMs: number): ApprovalRequestFrame | undefined;
1074
+ export declare function buildReplayFrame(row: Pick<AskRow, "askId" | "taskId" | "expiresAtMs" | "cardJson">, nowMs: number): ApprovalRequestFrame | undefined;
1019
1075
  /**
1020
1076
  * [ref] —— 持久行上那张卡**要不要人**:卡面 `risk.requiresRealApproval`(铸卡时取自引擎在 `AskRequest` 上盖的同一位,
1021
1077
  * {@link buildApprovalCard} 第三参)。读者 = 耐久 ask 回决口在裁决之前交给引擎判官 `policyCannotAnswer` 的那一问(`host-decision.ts` 的 `heldAskOf`)。
@@ -1,7 +1,8 @@
1
1
  import { z } from "zod";
2
- import { ALLOW_RULE_MEMBERS, ASK_EVIDENCE_ABSENCE_VALUES, BOUND_GRANT_ABSENCES, DENIAL_LIMIT_BOUNDS, MAX_RULE_TEXT_CHARS, PERSISTED_RULE_MATCHES, UNCOVERED_SEGMENT_REASONS, READ_ROOT_CANDIDATE_DIR_MAX, RESUME_STARTUP_CAUSES, RULE_OFFERS_ABSENCES, RULE_OFFER_KINDS, STEER_REPLAY_FACETS, isAskClass, readRuleOffers, isAskOrigin, isAutoModeFallbackCause, isMintableProbeReason, isPersistedRuleMandate, screenAskClassMembers } from "@sema-agent/core";
2
+ import { ALLOW_RULE_MEMBERS, ASK_EVIDENCE_ABSENCE_VALUES, TOOL_APPROVAL_CARDS, BOUND_GRANT_ABSENCES, DENIAL_LIMIT_BOUNDS, MAX_RULE_TEXT_CHARS, PERSISTED_RULE_MATCHES, UNCOVERED_SEGMENT_REASONS, READ_ROOT_CANDIDATE_DIR_MAX, RESUME_STARTUP_CAUSES, RULE_OFFERS_ABSENCES, RULE_OFFER_KINDS, STEER_REPLAY_FACETS, isAskClass, readRuleOffers, isAskOrigin, isAutoModeFallbackCause, isMintableProbeReason, isPersistedRuleMandate, screenAskClassMembers } from "@sema-agent/core";
3
3
  import { redactSecrets } from "./trace/redact.js";
4
4
  import { recordFailOpen } from "./observability/fail-open.js";
5
+ import { readApprovalCard } from "./approval-content-kind.js";
5
6
  import { capText } from "./caller-text-echo.js";
6
7
  import { retireParkArmWords, retireStoredCardWords } from "./retired-card-words.js";
7
8
  export const MAX_AGENT_NAME = 200;
@@ -345,6 +346,19 @@ export function parkRowFacts(stored) {
345
346
  ...(boundGrantAbsence !== undefined ? { boundGrantAbsence } : {}),
346
347
  };
347
348
  }
349
+ export function skillCardFacts(summary) {
350
+ return {
351
+ ...(summary.boundGrantDigest !== undefined ? { boundGrantDigest: summary.boundGrantDigest } : {}),
352
+ ...(summary.boundGrants !== undefined ? { boundGrants: summary.boundGrants } : {}),
353
+ ...(summary.classifierNoRuling !== undefined ? { classifierNoRuling: summary.classifierNoRuling } : {}),
354
+ };
355
+ }
356
+ export function parkRowCarriesSkillCardFacts(stored) {
357
+ if (typeof stored !== "object" || stored === null || !("kind" in stored) || stored.kind !== "tool_approval")
358
+ return false;
359
+ const digest = "boundGrantDigest" in stored ? stored.boundGrantDigest : undefined;
360
+ return typeof digest === "string" || ("classifierNoRuling" in stored && stored.classifierNoRuling !== undefined);
361
+ }
348
362
  export const DenialLimitFallbackSchema = z
349
363
  .object({
350
364
  consecutive: z.number().int().nonnegative(),
@@ -377,6 +391,7 @@ export const ApprovalCardSchema = z
377
391
  .strict(),
378
392
  governanceForced: z.literal(true).optional(),
379
393
  rememberRefused: z.literal(true).optional(),
394
+ approvalCard: z.enum(TOOL_APPROVAL_CARDS).optional(),
380
395
  inputHasBidi: z.literal(true).optional(),
381
396
  allowRuleShadowed: z
382
397
  .array(z
@@ -444,6 +459,7 @@ export function buildApprovalCard(source, req, requiresRealApproval) {
444
459
  const sourceTaskId = capText(source.sourceTaskId, MAX_IDENT);
445
460
  const sourceAgentName = capText(source.sourceAgentName, MAX_AGENT_NAME);
446
461
  const allowRuleShadowed = readAllowRuleShadowed(req);
462
+ const approvalCard = readApprovalCard(source.approvalCard);
447
463
  return {
448
464
  toolName: capText(source.toolName, MAX_IDENT) ?? "",
449
465
  message: capText(source.message, MAX_MESSAGE) ?? "",
@@ -456,6 +472,7 @@ export function buildApprovalCard(source, req, requiresRealApproval) {
456
472
  },
457
473
  ...(source.governanceForced === true ? { governanceForced: true } : {}),
458
474
  ...(source.rememberRefused === true ? { rememberRefused: true } : {}),
475
+ ...(approvalCard !== undefined ? { approvalCard } : {}),
459
476
  ...(source.inputHasBidi === true ? { inputHasBidi: true } : {}),
460
477
  ...(allowRuleShadowed !== undefined ? { allowRuleShadowed } : {}),
461
478
  ...(probeCause !== undefined ? { probeCause } : {}),
@@ -48,6 +48,7 @@ export declare function parkedFacetOf(gate: ParkedGateFace | undefined): "A" | "
48
48
  * 审批门型 = core `PAUSE_REGISTRY` 里寄存臂是 `tool_approval` 的登记门 —— 与 core `parkedApprovalCardOf` 判「是不是审批门」同一条判据(只在这些门上读卡)。
49
49
  * **派生,不手写**(core 7.55.0 [ref] P1 阶段二):此前本仓手写一份二员词表([ref] 时 core 没有导出词表),一次性迁移 M21 又自派生一份;
50
50
  * core 加一行审批味的门,这里跟着变,零处要改。读者:决断口与拒扫腿按门型绑定取行(`gateKinds`)、`/decide` 的门型守卫、M21 / M29 的候选扫描。
51
+ * 包根同出(`index.ts`):嵌入方 / sdk 读这一只,不手抄。
51
52
  * 到期分法**不**读这张表 —— SQL 里是由 core 两张表生成的 facet 谓词(`plugins/checkpoint-index-columns.ts`),JS 里是 {@link denySweepOwns}。
52
53
  */
53
54
  export type ApprovalGateKind = {
@@ -33,7 +33,7 @@ export function parkedApprovalCard(gate) {
33
33
  export function parkedFacetOf(gate) {
34
34
  return gate !== undefined && isGateKind(gate.kind) ? facetOf({ kind: gate.kind, approvalCard: gate.approvalCard }) : undefined;
35
35
  }
36
- export const APPROVAL_GATE_KINDS = Object.keys(PAUSE_REGISTRY).filter((k) => PAUSE_REGISTRY[k].pending === "tool_approval");
36
+ export const APPROVAL_GATE_KINDS = Object.freeze(Object.keys(PAUSE_REGISTRY).filter((k) => PAUSE_REGISTRY[k].pending === "tool_approval"));
37
37
  export function isApprovalGateKind(k) {
38
38
  return k !== undefined && APPROVAL_GATE_KINDS.includes(k);
39
39
  }
@@ -1,7 +1,7 @@
1
1
  import { type AuthBridgeErrorCode, type VerifiedIdentity } from "@sema-agent/settings-schema/api/auth-bridge";
2
+ import { type TokenScopeRefusal } from "@sema-agent/settings-schema/api/scopes";
2
3
  import type { Logger } from "./observability/logger.js";
3
4
  import type { Metrics } from "./observability/metrics.js";
4
- export type { VerifiedIdentity } from "@sema-agent/settings-schema/api/auth-bridge";
5
5
  /**
6
6
  * [ref] ② —— 鉴权桥 issuer 的**唯一**取值(装配 `boot/stage-09-leader.ts` 与 caps `centerWiring.issuer` 同读,不各写一份回退):
7
7
  * 显式 `AUTH_BRIDGE_ISSUER`(`config.authBridgeIssuer`)恒赢 ⇒ `source:"explicit"`;缺席则回退中心基址 `webAdmin.baseUrl`
@@ -34,13 +34,41 @@ export interface WebAdminJwtVerifierOptions {
34
34
  fetchImpl?: typeof fetch;
35
35
  nowMs?: () => number;
36
36
  }
37
+ /** 验证腿的拒因(闭集)= 契约 R9 的五个码 ∪ `readTokenScope` 的拒词;两边都是契约的闭集,加词 ⇒ 这里随之变宽(穷举分支的读者编译红)。 */
38
+ type AuthBridgeRefusal = AuthBridgeErrorCode | TokenScopeRefusal;
39
+ /** 本服务受理的桥身份:契约 `VerifiedIdentity`(验证器「令牌带了什么」的报告形)之上,scope 经 `readTokenScope` 读定后**必带**。 */
40
+ type BridgeIdentity = Omit<VerifiedIdentity, "scope"> & {
41
+ scope: string;
42
+ };
37
43
  export type VerifyOutcome = {
38
44
  ok: true;
39
- identity: VerifiedIdentity;
45
+ identity: BridgeIdentity;
46
+ } | {
47
+ ok: false;
48
+ error: AuthBridgeRefusal;
49
+ };
50
+ /** 拒因记账的去处(验证器选项与 HTTP 装配各自持有同一对 logger / metrics)。 */
51
+ type BridgeSinks = {
52
+ readonly logger?: Logger | undefined;
53
+ readonly metrics?: Pick<Metrics, "inc"> | undefined;
54
+ };
55
+ /** 注入边界收的结局:与 {@link VerifyOutcome} 同形,只是成功身份的 `scope` 是 `unknown` —— 这一位正是边界要判的形,它不信型面
56
+ * (席是嵌入方可换的:`""` 过得了 `scope: string`,JS 侧连缺省 / 非串都交得进来)。`VerifyOutcome` 可赋给它,调用方零改动。 */
57
+ type ReportedOutcome = {
58
+ ok: true;
59
+ identity: Omit<BridgeIdentity, "scope"> & {
60
+ scope?: unknown;
61
+ };
40
62
  } | {
41
63
  ok: false;
42
- error: AuthBridgeErrorCode;
64
+ error: AuthBridgeRefusal;
43
65
  };
66
+ /**
67
+ * 注入边界:任何验证器(内建 {@link createWebAdminJwtVerifier},或嵌入方注入的 `ServiceDeps.webAdminJwtVerifier`)交来的结局,在这里定「装不装身份」。
68
+ * 成功身份的 scope 经**同一只** `readTokenScope` 再读一次(入参型见 {@link ReportedOutcome})。
69
+ * 读不出 ⇒ 同一只记账口、不交身份(调用方按验证失败处置:不设身份 ⇒ 门答 generic 401)。验证失败的结局验证器自己已记过账,这里只答「不装」。
70
+ */
71
+ export declare function admitBridgeIdentity(outcome: ReportedOutcome, sinks: BridgeSinks): BridgeIdentity | undefined;
44
72
  /** The live object `createWebAdminJwtVerifier` produces — a single `verify` entry point over the process-level JWKS cache. */
45
73
  export interface WebAdminJwtVerifier {
46
74
  verify: (bearer: string) => Promise<VerifyOutcome>;
@@ -50,8 +78,9 @@ export declare const DEFAULT_JWKS_TTL_SEC: number;
50
78
  /** 一次 JWKS 拉取的时限(毫秒):kid 未知、超离线宽限、后台刷新三条路用同一只拉取,同一个时限。 */
51
79
  export declare const JWKS_FETCH_TIMEOUT_MS = 10000;
52
80
  /**
53
- * registry-JWT verifier(单例,进程级 JWKS 缓存)。`verify(bearer)` 全程不 throw——一切异常折为
54
- * AUTH_BRIDGE_ERROR_CODES(HTTP 面由调用方恒答 generic 401,码只进日志/metrics,R9)。
81
+ * registry-JWT verifier(单例,进程级 JWKS 缓存)。`verify(bearer)` 全程不 throw——一切异常折为拒因闭集
82
+ * {@link AuthBridgeRefusal}(HTTP 面由调用方恒答 generic 401,码只进日志/metrics,R9)。
55
83
  */
56
84
  export declare function createWebAdminJwtVerifier(opts: WebAdminJwtVerifierOptions): WebAdminJwtVerifier;
85
+ export {};
57
86
  //# sourceMappingURL=auth-bridge.d.ts.map
@@ -1,5 +1,6 @@
1
1
  import { createPublicKey, verify as cryptoVerify } from "node:crypto";
2
2
  import { AUTH_BRIDGE_ALGS, DEFAULT_CLOCK_SKEW_SEC, DEFAULT_JWKS_REFRESH_MIN_INTERVAL_SEC, DEFAULT_OFFLINE_GRACE_SEC, WEB_ADMIN_JWKS_PATH, WebAdminJwks, classifyTimeClaims, jwksWithinOfflineGrace, shouldForceJwksRefresh, toVerifiedIdentity, } from "@sema-agent/settings-schema/api/auth-bridge";
3
+ import { readTokenScope } from "@sema-agent/settings-schema/api/scopes";
3
4
  import { buildDisplaySafeUrl } from "./trace/redact.js";
4
5
  export function authBridgeIssuerOf(config) {
5
6
  if (config.authBridgeIssuer !== undefined)
@@ -8,6 +9,20 @@ export function authBridgeIssuerOf(config) {
8
9
  return { issuer: config.webAdmin.baseUrl, source: "fallback" };
9
10
  return undefined;
10
11
  }
12
+ function recordBridgeRefusal(sinks, error, at = {}) {
13
+ sinks.metrics?.inc("auth_bridge_verify_total", { outcome: error });
14
+ sinks.logger?.warn?.("auth_bridge_rejected", { error, ...(at.kid ? { kid: at.kid.slice(0, 128) } : {}), ...(at.iss !== undefined ? { iss: at.iss } : {}) });
15
+ }
16
+ export function admitBridgeIdentity(outcome, sinks) {
17
+ if (!outcome.ok)
18
+ return undefined;
19
+ const scoped = readTokenScope({ scope: outcome.identity.scope });
20
+ if ("refused" in scoped) {
21
+ recordBridgeRefusal(sinks, scoped.refused);
22
+ return undefined;
23
+ }
24
+ return { ...outcome.identity, scope: scoped.scope };
25
+ }
11
26
  export const DEFAULT_JWKS_TTL_SEC = 15 * 60;
12
27
  export const JWKS_FETCH_TIMEOUT_MS = 10_000;
13
28
  const MAX_JWKS_BYTES = 256 * 1024;
@@ -42,8 +57,7 @@ export function createWebAdminJwtVerifier(opts) {
42
57
  let inflight;
43
58
  const withinGrace = () => lastFetchSuccessMs !== undefined && jwksWithinOfflineGrace({ lastFetchSuccessMs, nowMs: now() }, { offlineGraceSec });
44
59
  const fail = (error, kid) => {
45
- opts.metrics?.inc("auth_bridge_verify_total", { outcome: error });
46
- opts.logger?.warn?.("auth_bridge_rejected", { error, ...(kid ? { kid: kid.slice(0, 128) } : {}), iss: displayIssuer });
60
+ recordBridgeRefusal(opts, error, { kid, iss: displayIssuer });
47
61
  return { ok: false, error };
48
62
  };
49
63
  async function refreshJwks() {
@@ -144,8 +158,11 @@ export function createWebAdminJwtVerifier(opts) {
144
158
  const mapped = toVerifiedIdentity(payload, opts.audience ? { audience: opts.audience } : undefined);
145
159
  if (!mapped.ok)
146
160
  return fail(mapped.error, kid);
161
+ const scoped = readTokenScope(payload);
162
+ if ("refused" in scoped)
163
+ return fail(scoped.refused, kid);
147
164
  opts.metrics?.inc("auth_bridge_verify_total", { outcome: "ok" });
148
- return { ok: true, identity: mapped.identity };
165
+ return { ok: true, identity: { ...mapped.identity, scope: scoped.scope } };
149
166
  }
150
167
  return { verify };
151
168
  }
@@ -1,6 +1,5 @@
1
1
  import { ModelUsageTracker, PromptManifestTracker } from "../budget.js";
2
2
  import type { ServiceConfig } from "../config.js";
3
- import { FleetUsageAccumulator } from "../fleet-client.js";
4
3
  import { CostQuota } from "../observability/cost-quota.js";
5
4
  import type { Logger } from "../observability/logger.js";
6
5
  import type { Metrics } from "../observability/metrics.js";
@@ -26,7 +25,7 @@ export declare function createBudgetAndTracing(ctx: BudgetTracingCtx): {
26
25
  costQuota: CostQuota | import("../plugins/pg-cost-quota.js").PgCostQuota | import("../plugins/tidb-cost-quota.js").TiDBCostQuota;
27
26
  modelUsageTracker: ModelUsageTracker;
28
27
  promptManifestTracker: PromptManifestTracker;
29
- fleetUsage: FleetUsageAccumulator | undefined;
28
+ fleetUsage: import("../fleet-client.js").FleetUsageBins | undefined;
30
29
  fleetLease: import("../fleet-lease.js").FleetLeaseManager | undefined;
31
30
  tracer: import("@sema-agent/core").TracerHook;
32
31
  sideQueryAccounting: (principal: string | undefined, r: {
@@ -1,6 +1,6 @@
1
1
  import { createBrainAssembly } from "../brain.js";
2
2
  import { ModelUsageTracker, PromptManifestTracker, buildPricing, createSideQueryAccountant, createTracer } from "../budget.js";
3
- import { FleetUsageAccumulator } from "../fleet-client.js";
3
+ import { createFleetUsageBins } from "../fleet-client.js";
4
4
  import { createFleetLeaseFromEnv } from "../fleet-lease.js";
5
5
  import { centerLaneConfigured } from "../web-admin-client/center-request.js";
6
6
  import { CostQuota } from "../observability/cost-quota.js";
@@ -25,7 +25,7 @@ export function createBudgetAndTracing(ctx) {
25
25
  : new CostQuota(bounds.limitMicroUsd, bounds.windowMs);
26
26
  const modelUsageTracker = new ModelUsageTracker();
27
27
  const promptManifestTracker = new PromptManifestTracker();
28
- const fleetUsage = centerLaneConfigured(config) ? new FleetUsageAccumulator() : undefined;
28
+ const fleetUsage = centerLaneConfigured(config) ? createFleetUsageBins(config.webAdmin.credential) : undefined;
29
29
  const fleetLease = createFleetLeaseFromEnv(config, { logger, metrics });
30
30
  const tracer = createTracer(metrics, costQuota, modelUsageTracker, fleetUsage, fleetLease, (m) => config.modelQuotaWeights[m] ?? 1, promptManifestTracker);
31
31
  const sideQueryAccounting = createSideQueryAccountant(metrics, costQuota, fleetUsage, fleetLease, (m) => config.modelQuotaWeights[m] ?? 1);
@@ -31,7 +31,7 @@ export function createOrgMemoryAdmissionWiring(opts) {
31
31
  fetchSection: (principal) => fetchPrincipalOrgMemory({ baseUrl: centerLeg.baseUrl, credential }, principal, fetch, centerLeg.worker),
32
32
  grantTtlMs: config.memoryOrgGrantTtlMs,
33
33
  unavailableBackoffMs: config.memoryOrgUnavailableBackoffMs,
34
- }));
34
+ })).now;
35
35
  return { lookup: (principal) => directoryNow().lookup(principal) };
36
36
  })()
37
37
  : staticJson !== undefined
@@ -36,7 +36,8 @@ import { normalizeAttachments, normalizeResilience, normalizeResumeAtMode, norma
36
36
  import { isAbsoluteHostPath } from "@sema-agent/settings-schema";
37
37
  import { effectiveHostWorkspace, parseAdditionalDirectories, satisfiedByProcessCwd, shellEnvMismatchCount } from "../task-cwd.js";
38
38
  import { DEPLOYMENT_SHAPE_PREDICATES } from "../deployment-shape.js";
39
- import { assertRequestA2aPeerUrls, assertRequestA2aUnlocked, resolveRequestA2a } from "../task-a2a.js";
39
+ import { assertRequestA2aEntries, resolveRequestA2a, snapshotRequestA2a } from "../task-a2a.js";
40
+ import { assertRequestImageUrls } from "../request-image-urls.js";
40
41
  import { assertRequestMcpEntries, assertRequestMcpUnlocked, resolveRequestMcp } from "../task-mcp.js";
41
42
  import { storedToolAxesRereadM19 } from "../stored-request-tool-axes-m19.js";
42
43
  import { storedHooksRereadM20 } from "../stored-request-hooks-m20.js";
@@ -139,9 +140,12 @@ export function createResolveSpec(ctx) {
139
140
  }
140
141
  }
141
142
  }
142
- assertRequestA2aUnlocked(body.a2aPeers, lockedKeys);
143
+ const storedToolAxes = opts?.leg === "fresh" ? undefined : storedToolAxesRereadM19(new Date().toISOString().slice(0, 10));
144
+ const a2aPeers = snapshotRequestA2a(body.a2aPeers, { reread: storedToolAxes !== undefined });
145
+ if (opts?.leg === "fresh")
146
+ assertRequestA2aEntries(a2aPeers);
143
147
  if (opts?.leg === "fresh")
144
- assertRequestA2aPeerUrls(body.a2aPeers);
148
+ assertRequestImageUrls(body.images);
145
149
  const gated = await gateScenarioAndAppend(body, auth, opts);
146
150
  const effMode = effectivePermissionMode(body, gated.parsedSettings.settings);
147
151
  if (effMode !== undefined && modePolicyOf(effMode).writeFace === "open") {
@@ -152,7 +156,7 @@ export function createResolveSpec(ctx) {
152
156
  const lane = bindSettingsCwdEnvAndModel(body, auth, gated, opts);
153
157
  const anchors = await resolveHistoryAnchors(body, auth);
154
158
  const projectKey = memoryEngine ? await memoryProjectLayers.prepare(config, auth?.memoryScope, realTaskRootOf(auth)) : undefined;
155
- const spec = assembleSpecLiteral(body, auth, req, opts, { ...gated, ...lane, ...anchors, projectKey }, effMode);
159
+ const spec = assembleSpecLiteral(body, auth, req, opts, { ...gated, ...lane, ...anchors, projectKey, a2aPeers, storedToolAxes }, effMode);
156
160
  const folded = await foldGovernanceAndSettings(body, auth, spec, gated);
157
161
  const final = await applyImageFactsAndRouting(body, auth, folded.governed, {
158
162
  scenarioName: gated.scenarioName,
@@ -355,8 +359,7 @@ export function createResolveSpec(ctx) {
355
359
  return deriveAskEffective(askForm.form, "unresolved") === "human_reachable";
356
360
  };
357
361
  const assembleSpecLiteral = (body, auth, req, opts, parts, effMode) => {
358
- const { scenarioName, cap, hands, acceptedAppend, parsedSettings, attachmentNotice, taskHooks, additionalDirectories, additionalReadDirectories, wireCatalog, picked, resumeAtEntryId, rewindFilesToEntryId, s4DefaultScopes, projectKey, } = parts;
359
- const storedToolAxes = opts?.leg === "fresh" ? undefined : storedToolAxesRereadM19(new Date().toISOString().slice(0, 10));
362
+ const { scenarioName, cap, hands, acceptedAppend, parsedSettings, attachmentNotice, taskHooks, additionalDirectories, additionalReadDirectories, wireCatalog, picked, resumeAtEntryId, rewindFilesToEntryId, s4DefaultScopes, projectKey, a2aPeers, storedToolAxes, } = parts;
360
363
  const spec = {
361
364
  objective: attachmentNotice ? `${picked.cleanedObjective}\n\n${attachmentNotice}` : picked.cleanedObjective,
362
365
  ...buildPromptSeats(scenarioName, cap.prompt, typeof body.systemPrompt === "string" ? body.systemPrompt : undefined),
@@ -490,7 +493,7 @@ export function createResolveSpec(ctx) {
490
493
  ...(parsedSettings.settings?.skillListingBudgetFraction !== undefined ? { skillListingBudgetFraction: parsedSettings.settings.skillListingBudgetFraction } : {}),
491
494
  ...(parsedSettings.settings?.skillListingMaxDescChars !== undefined ? { skillListingMaxDescChars: parsedSettings.settings.skillListingMaxDescChars } : {}),
492
495
  mcp: resolveRequestMcp(mcpForScenario(config.mcpServers, scenarioName), body.mcpServers, config, logger, opts?.onNotice !== undefined ? { sessionId: auth?.sessionId, emit: opts.onNotice } : undefined, storedToolAxes),
493
- a2a: resolveRequestA2a(a2aForScenario(config.a2aPeers, scenarioName), body.a2aPeers, config, logger, opts?.leg === "fresh" ? "fresh" : "resume", storedToolAxes),
496
+ a2a: resolveRequestA2a(a2aForScenario(config.a2aPeers, scenarioName), a2aPeers, config, logger, opts?.leg === "fresh" ? "fresh" : "resume", storedToolAxes),
494
497
  toolPolicy: toolPolicyForHands(hands, durableEnabled
495
498
  ? createApprovalBaselinePolicy(config, {
496
499
  kind: "durable",
@@ -20,6 +20,8 @@ import { storeFormRefusalInIncident } from "../memory-store-refusal.js";
20
20
  import { coreFileHistoryCaptureSeat } from "../file-history-capture.js";
21
21
  import { DEPLOYMENT_SHAPE_PREDICATES } from "../deployment-shape.js";
22
22
  import { rewindFailureCode } from "../file-history-disclosure.js";
23
+ import { errorKindOf } from "../observability/err-text.js";
24
+ import { buildShownUrlsInText } from "../url-refusal.js";
23
25
  export function createRunnerDepsOnAsk(toolApproval) {
24
26
  if (!toolApproval)
25
27
  return undefined;
@@ -263,12 +265,12 @@ export function createRunnerDeps(ctx) {
263
265
  return;
264
266
  }
265
267
  if (ctx.phase === "mcp") {
266
- logger.warn("mcp_server_unavailable", { sessionId: ctx.sessionId, info: String(err) });
268
+ logger.warn("mcp_server_unavailable", { sessionId: ctx.sessionId, kind: errorKindOf(err), info: buildShownUrlsInText(String(err)) });
267
269
  metrics.inc("mcp_server_unavailable_total");
268
270
  return;
269
271
  }
270
272
  if (ctx.phase === "a2a") {
271
- logger.warn("a2a_peer_unavailable", { sessionId: ctx.sessionId, info: String(err) });
273
+ logger.warn("a2a_peer_unavailable", { sessionId: ctx.sessionId, kind: errorKindOf(err), info: buildShownUrlsInText(String(err)) });
272
274
  metrics.inc("a2a_peer_unavailable_total");
273
275
  return;
274
276
  }
@@ -15,7 +15,7 @@ export declare function runStage04(ctx: Awaited<ReturnType<typeof runStage03>>):
15
15
  fileHistoryErasure: import("../file-history-capture.js").FileHistoryErasureFace | undefined;
16
16
  fileHistoryStore: import("../plugins/store-backend.js").ServiceFileHistoryStore | undefined;
17
17
  fleetLease: import("../fleet-lease.js").FleetLeaseManager | undefined;
18
- fleetUsage: import("../fleet-client.js").FleetUsageAccumulator | undefined;
18
+ fleetUsage: import("../fleet-client.js").FleetUsageBins | undefined;
19
19
  memoryBundleFaces: import("../memory-bundle-engine.js").MemoryBundleFaces | undefined;
20
20
  memoryComplianceFaces: import("../memory-operator-faces.js").MemoryComplianceFaces | undefined;
21
21
  memoryOriginFaces: import("../memory-operator-faces.js").MemoryOriginFaces | undefined;
@@ -30,7 +30,7 @@ export declare function runStage05(ctx: Awaited<ReturnType<typeof runStage04>>):
30
30
  fileHistoryErasure: import("../file-history-capture.js").FileHistoryErasureFace | undefined;
31
31
  fileHistoryStore: import("../plugins/store-backend.js").ServiceFileHistoryStore | undefined;
32
32
  fleetLease: import("../fleet-lease.js").FleetLeaseManager | undefined;
33
- fleetUsage: import("../fleet-client.js").FleetUsageAccumulator | undefined;
33
+ fleetUsage: import("../fleet-client.js").FleetUsageBins | undefined;
34
34
  memoryBundleFaces: import("../memory-bundle-engine.js").MemoryBundleFaces | undefined;
35
35
  memoryComplianceFaces: import("../memory-operator-faces.js").MemoryComplianceFaces | undefined;
36
36
  memoryOriginFaces: import("../memory-operator-faces.js").MemoryOriginFaces | undefined;
@@ -93,7 +93,7 @@ export declare function runStage06(ctx: Awaited<ReturnType<typeof runStage05>>):
93
93
  fileHistoryErasure: import("../file-history-capture.js").FileHistoryErasureFace | undefined;
94
94
  fileHistoryStore: import("../plugins/store-backend.js").ServiceFileHistoryStore | undefined;
95
95
  fleetLease: import("../fleet-lease.js").FleetLeaseManager | undefined;
96
- fleetUsage: import("../fleet-client.js").FleetUsageAccumulator | undefined;
96
+ fleetUsage: import("../fleet-client.js").FleetUsageBins | undefined;
97
97
  memoryBundleFaces: import("../memory-bundle-engine.js").MemoryBundleFaces | undefined;
98
98
  memoryComplianceFaces: import("../memory-operator-faces.js").MemoryComplianceFaces | undefined;
99
99
  memoryOriginFaces: import("../memory-operator-faces.js").MemoryOriginFaces | undefined;
@@ -108,7 +108,7 @@ export declare function runStage07(ctx: Awaited<ReturnType<typeof runStage06>>):
108
108
  fileHistoryErasure: import("../file-history-capture.js").FileHistoryErasureFace | undefined;
109
109
  fileHistoryStore: import("../plugins/store-backend.js").ServiceFileHistoryStore | undefined;
110
110
  fleetLease: import("../fleet-lease.js").FleetLeaseManager | undefined;
111
- fleetUsage: import("../fleet-client.js").FleetUsageAccumulator | undefined;
111
+ fleetUsage: import("../fleet-client.js").FleetUsageBins | undefined;
112
112
  memoryBundleFaces: import("../memory-bundle-engine.js").MemoryBundleFaces | undefined;
113
113
  memoryComplianceFaces: import("../memory-operator-faces.js").MemoryComplianceFaces | undefined;
114
114
  memoryOriginFaces: import("../memory-operator-faces.js").MemoryOriginFaces | undefined;
@@ -121,7 +121,7 @@ export declare function runStage08(ctx: Awaited<ReturnType<typeof runStage07>>):
121
121
  fileHistoryErasure: import("../file-history-capture.js").FileHistoryErasureFace | undefined;
122
122
  fileHistoryStore: import("../plugins/store-backend.js").ServiceFileHistoryStore | undefined;
123
123
  fleetLease: import("../fleet-lease.js").FleetLeaseManager | undefined;
124
- fleetUsage: import("../fleet-client.js").FleetUsageAccumulator | undefined;
124
+ fleetUsage: import("../fleet-client.js").FleetUsageBins | undefined;
125
125
  memoryBundleFaces: import("../memory-bundle-engine.js").MemoryBundleFaces | undefined;
126
126
  memoryComplianceFaces: import("../memory-operator-faces.js").MemoryComplianceFaces | undefined;
127
127
  memoryOriginFaces: import("../memory-operator-faces.js").MemoryOriginFaces | undefined;
@@ -145,7 +145,7 @@ export declare function runStage09(ctx: Awaited<ReturnType<typeof runStage08>>):
145
145
  fileHistoryErasure: import("../file-history-capture.js").FileHistoryErasureFace | undefined;
146
146
  fileHistoryStore: import("../plugins/store-backend.js").ServiceFileHistoryStore | undefined;
147
147
  fleetLease: import("../fleet-lease.js").FleetLeaseManager | undefined;
148
- fleetUsage: import("../fleet-client.js").FleetUsageAccumulator | undefined;
148
+ fleetUsage: import("../fleet-client.js").FleetUsageBins | undefined;
149
149
  memoryBundleFaces: import("../memory-bundle-engine.js").MemoryBundleFaces | undefined;
150
150
  memoryComplianceFaces: import("../memory-operator-faces.js").MemoryComplianceFaces | undefined;
151
151
  memoryOriginFaces: import("../memory-operator-faces.js").MemoryOriginFaces | undefined;
@@ -144,7 +144,7 @@ export declare function runStage10(ctx: Awaited<ReturnType<typeof runStage09>>):
144
144
  fileHistoryErasure: import("../file-history-capture.js").FileHistoryErasureFace | undefined;
145
145
  fileHistoryStore: import("../plugins/store-backend.js").ServiceFileHistoryStore | undefined;
146
146
  fleetLease: import("../fleet-lease.js").FleetLeaseManager | undefined;
147
- fleetUsage: import("../fleet-client.js").FleetUsageAccumulator | undefined;
147
+ fleetUsage: import("../fleet-client.js").FleetUsageBins | undefined;
148
148
  memoryBundleFaces: import("../memory-bundle-engine.js").MemoryBundleFaces | undefined;
149
149
  memoryComplianceFaces: import("../memory-operator-faces.js").MemoryComplianceFaces | undefined;
150
150
  memoryOriginFaces: import("../memory-operator-faces.js").MemoryOriginFaces | undefined;
@@ -9,7 +9,7 @@ import { TiDBMemoryEngineBackend, ensureTiDBMemoryEngineSchema } from "../plugin
9
9
  import { PgMemoryHistoryStore, PgMemorySyncStore, ensurePgMemoryHistorySchema, ensurePgMemorySyncSchema } from "../plugins/memory-sync-store-pg.js";
10
10
  import { TiDBMemoryHistoryStore, TiDBMemorySyncStore, ensureTiDBMemoryHistorySchema, ensureTiDBMemorySyncSchema } from "../plugins/memory-sync-store-tidb.js";
11
11
  import { MinioBlobBackend } from "../plugins/blob-backend.js";
12
- import { ensureSnapshotBucket } from "../plugins/snapshot-bucket-presence.js";
12
+ import { ensureSnapshotBuckets } from "../plugins/snapshot-bucket-presence.js";
13
13
  import { PgBackgroundAgentStore, TiDBBackgroundAgentStore, ensurePgBackgroundAgentSchema, ensureTiDBBackgroundAgentSchema } from "../plugins/background-agent-store-sql.js";
14
14
  import { PgMailboxStore, TiDBMailboxStore, ensurePgMailboxSchema, ensureTiDBMailboxSchema } from "../plugins/mailbox-store-sql.js";
15
15
  import { createDropOnlyRecipientLifecycle } from "../plugins/mailbox-recipient-lifecycle.js";
@@ -58,8 +58,7 @@ export async function openStores(ctx) {
58
58
  let backend;
59
59
  let storeDegradedReason;
60
60
  const dsnConfigured = !!(config.tidb || config.pg);
61
- if (config.snapshotBlobStore)
62
- await ensureSnapshotBucket(config.snapshotBlobStore, config.storeLockWaitMs, logger);
61
+ await ensureSnapshotBuckets(config, logger);
63
62
  const wantDb = config.sessionBackend === "tidb" ||
64
63
  config.dbBackend === "local" ||
65
64
  (config.sessionBackend === "auto" && dsnConfigured);
@@ -12,7 +12,7 @@ import { applyCenterArtifact, centerSourceOnError, withPromptArtifactBackfill }
12
12
  import { centerScenarios, centerScenarioDetails } from "../capabilities/scenarios.js";
13
13
  import { isRosterGateArmed } from "../config.js";
14
14
  import { DEPLOYMENT_SHAPE_PREDICATES } from "../deployment-shape.js";
15
- import { defaultLkgPath, defaultSkillCacheDir, saveLkg, loadLkg, legacyV1LkgPath, migrateV1Lkg } from "../config-lkg.js";
15
+ import { defaultLkgPath, defaultSkillCacheDir, saveLkg, loadLkg } from "../config-lkg.js";
16
16
  import { answerStillCurrent, centerStateBin, credentialIdentityNow, judgeCenterCredentialAtBoot } from "../center-credential.js";
17
17
  import { createCenterConfigTier } from "../center-config-tier.js";
18
18
  import { buildCenterCredentialHealthView, createCenterCredentialRenewer } from "../center-credential-renewer.js";
@@ -21,6 +21,7 @@ import { createConfigProvider, raceBootFetch, serviceConfigSourceKind, BOOT_FETC
21
21
  import { ConfigDirUntrustedError } from "../config-dir-trust.js";
22
22
  import { createKeyResolver } from "../key-resolver.js";
23
23
  import { buildSealedKeyPublicFace, ensureCheckpointCtxSealing, ensureSealedKeyStore, reportExecutionPublicKey } from "../sealed-key.js";
24
+ import { anthropicLaneCredentialOf } from "../model-route-gap.js";
24
25
  import { applyEffective, applyCenterReadFace, buildReadFaceBaseline, buildReadFaceSwapCandidate, restoreReadFaceBaseline, mutateInPlace, logEffectiveDiff, applySkillsManifest, skillManifestEntriesNotInstalled, resolveMcpServers, resolveA2aPeers, restartReasons, modelPlaneChanged, withModelPlaneOf, fullyLandedForLkg, NO_CENTER_EFFECTIVE, isNoCenterEffective, fetchPromptArtifact } from "../web-admin-client/facade.js";
25
26
  import { buildConfigHandoff, buildRestartSignal, configHandoffMissing } from "../fleet/engine-signal.js";
26
27
  import { createMcpRevocationLedger, enabledMcpEntries } from "../web-admin-client/mcp-revocation.js";
@@ -133,7 +134,7 @@ export async function createWebAdminRuntime(ctx) {
133
134
  }
134
135
  return r;
135
136
  };
136
- const sealedKeyDir = join(config.localDataRoot ?? localRoot, "sealed-key");
137
+ const sealedKeyDir = config.sealedKeyDir ?? join(config.localDataRoot ?? localRoot, "sealed-key");
137
138
  let sealedKeys;
138
139
  try {
139
140
  sealedKeys = await ensureSealedKeyStore(sealedKeyDir, logger);
@@ -146,6 +147,11 @@ export async function createWebAdminRuntime(ctx) {
146
147
  });
147
148
  }
148
149
  catch (err) {
150
+ if (config.sealedKeyDir !== undefined) {
151
+ throw new Error(`SEALED_KEY_DIR=${config.sealedKeyDir}: the declared model-key custody directory cannot hold a sealed-key store (${String(err)}) — ` +
152
+ `refusing to start rather than run with every sealed model unusable (no_key_store). Make that directory creatable, owned by ` +
153
+ `the service user and chmod-able to 0700 on a writable filesystem, or unset SEALED_KEY_DIR to use <data root>/sealed-key.`);
154
+ }
149
155
  logger.warn("sealed_key_store_unavailable", { err: String(err), note: "sealed api keys cannot be unsealed on this host — models carrying sealedApiKey will fail loud per-model" });
150
156
  }
151
157
  let checkpointCtxSealing;
@@ -153,7 +159,7 @@ export async function createWebAdminRuntime(ctx) {
153
159
  checkpointCtxSealing = await ensureCheckpointCtxSealing(sealedKeyDir, logger);
154
160
  }
155
161
  catch (err) {
156
- logger.warn("checkpoint_ctx_sealing_unavailable", { err: err instanceof Error ? err.message : String(err), note: "suspended tasks' request credentials cannot be sealed on this host; with durable approvals on the boot refuses — make <data root>/sealed-key/checkpoint-ctx-keys/ creatable and chmod-able by the service, or repair / remove a key file there whose public and private halves do not belong together" });
162
+ logger.warn("checkpoint_ctx_sealing_unavailable", { err: err instanceof Error ? err.message : String(err), dir: join(sealedKeyDir, "checkpoint-ctx-keys"), note: "suspended tasks' request credentials cannot be sealed on this host; with durable approvals on the boot refuses — make that directory (under the sealed-key custody directory: SEALED_KEY_DIR, default <data root>/sealed-key) creatable and chmod-able by the service, or repair / remove a key file there whose public and private halves do not belong together" });
157
163
  }
158
164
  const configProvider = serviceConfigSourceKind(config) !== undefined
159
165
  ? createConfigProvider({
@@ -458,19 +464,6 @@ export async function createWebAdminRuntime(ctx) {
458
464
  return null;
459
465
  }
460
466
  const lkgPath = lkgPathFor(identity);
461
- const legacy = await migrateV1Lkg({ legacyPath: config.configLkgPath ?? legacyV1LkgPath(config, cc?.worker), binPath: lkgPath, worker: cc?.worker, identity });
462
- switch (legacy.outcome) {
463
- case "none":
464
- break;
465
- case "migrated":
466
- logger.info("config_lkg_migrated", { from: legacy.from, retiredTo: legacy.retiredTo, to: lkgPath, note: "formatVersion 1 LKG (pull-token identity = this worker) migrated once into this credential identity's bin; the old file was renamed, not deleted" });
467
- if (legacy.retireError !== undefined)
468
- logger.warn("config_lkg_legacy_not_retired", { path: legacy.from, reason: legacy.retireError, note: "the bin was written and is used; only the old file's rename / copy failed" });
469
- break;
470
- case "not-migrated":
471
- logger.warn("config_lkg_unusable", { path: legacy.path, reason: legacy.reason, note: "env fallback serves; the cache rewrites on the next clean candidate" });
472
- return null;
473
- }
474
467
  const read = await loadLkg(lkgPath, cc?.worker, identity);
475
468
  if (!read.lkg) {
476
469
  if (read.reason !== "absent")
@@ -800,7 +793,7 @@ export async function createWebAdminRuntime(ctx) {
800
793
  },
801
794
  initKeyResolver() {
802
795
  keyResolver = createKeyResolver(config.modelApiKeyEnv, process.env, config.modelApiKeys);
803
- if (process.env.ANTHROPIC_AUTH_TOKEN && !process.env.ANTHROPIC_API_KEY && (Object.keys(config.modelApiKeys).length > 0 || Object.keys(config.modelApiKeyEnv).length > 0)) {
796
+ if (anthropicLaneCredentialOf(config.anthropic ?? {})?.kind === "bearer" && (Object.keys(config.modelApiKeys).length > 0 || Object.keys(config.modelApiKeyEnv).length > 0)) {
804
797
  logger.warn("per_model_key_bearer_gateway_combo", {
805
798
  perModelKeys: Object.keys(config.modelApiKeys).length + Object.keys(config.modelApiKeyEnv).length,
806
799
  note: "ANTHROPIC_AUTH_TOKEN (Bearer) deployment with per-model keys: core's per-call auth REPLACES the Authorization header with x-api-key for those models — a Bearer-only gateway will 401 them. Remove the per-model key for such models, or use a gateway accepting x-api-key.",