@sema-agent/server 7.151.0 → 7.152.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 (286) hide show
  1. package/MIGRATION.md +266 -0
  2. package/README.md +15 -3
  3. package/README.zh-CN.md +10 -2
  4. package/USAGE.md +93 -64
  5. package/deploy/sema-up/README.md +5 -4
  6. package/deploy/sema-up/cluster-up.sh +6 -6
  7. package/deploy/sema-up/kube-up.sh +5 -5
  8. package/deploy/sema-up/lib/flagshape.sh +36 -8
  9. package/deploy/sema-up/machines.example.yaml +3 -1
  10. package/deploy/sema-up/sema-up.sh +22 -16
  11. package/dist/approval-ask-audit-store.d.ts +1 -1
  12. package/dist/approval-ask-machine.d.ts +4 -10
  13. package/dist/approval-ask-retention.d.ts +1 -1
  14. package/dist/approval-card.d.ts +10 -12
  15. package/dist/approval-gate-currency.d.ts +8 -8
  16. package/dist/approval-gate-currency.js +3 -4
  17. package/dist/approval-hmac.d.ts +17 -1
  18. package/dist/approval-hmac.js +7 -1
  19. package/dist/approval-queue-kind.d.ts +1 -1
  20. package/dist/approval.d.ts +2 -2
  21. package/dist/approval.js +2 -2
  22. package/dist/bind-host.d.ts +1 -3
  23. package/dist/bind-host.js +2 -3
  24. package/dist/boot/coordinators.d.ts +1 -1
  25. package/dist/boot/coordinators.js +9 -10
  26. package/dist/boot/device-lane.js +2 -0
  27. package/dist/boot/execution-env.d.ts +1 -0
  28. package/dist/boot/execution-env.js +31 -5
  29. package/dist/boot/leader.d.ts +31 -30
  30. package/dist/boot/leader.js +38 -28
  31. package/dist/boot/leg-path-adjudication.d.ts +40 -0
  32. package/dist/boot/leg-path-adjudication.js +18 -0
  33. package/dist/boot/parked-revive-gate.js +3 -15
  34. package/dist/boot/reapers.d.ts +1 -1
  35. package/dist/boot/reapers.js +1 -1
  36. package/dist/boot/resolve-spec.js +12 -26
  37. package/dist/boot/runner-deps.d.ts +39 -35
  38. package/dist/boot/runner-deps.js +92 -89
  39. package/dist/boot/shutdown.d.ts +6 -0
  40. package/dist/boot/shutdown.js +10 -4
  41. package/dist/boot/stage-02-web-admin-pull.js +4 -5
  42. package/dist/boot/stage-05-execution-env.js +2 -1
  43. package/dist/boot/stage-06-runners.d.ts +2 -0
  44. package/dist/boot/stage-06-runners.js +10 -4
  45. package/dist/boot/stage-07-capability-layer.d.ts +1 -0
  46. package/dist/boot/stage-07-capability-layer.js +1 -1
  47. package/dist/boot/stage-08-reapers.d.ts +1 -0
  48. package/dist/boot/stage-09-leader.d.ts +1 -0
  49. package/dist/boot/stage-09-leader.js +2 -2
  50. package/dist/boot/stage-10-http-server.d.ts +8 -0
  51. package/dist/boot/stage-10-http-server.js +11 -15
  52. package/dist/boot/stores.js +7 -4
  53. package/dist/boot/web-admin.js +2 -7
  54. package/dist/capabilities/approvals-push.d.ts +3 -3
  55. package/dist/capabilities/scenarios.d.ts +28 -13
  56. package/dist/capabilities/scenarios.js +2 -2
  57. package/dist/capability-facts.d.ts +22 -20
  58. package/dist/capability-facts.js +18 -34
  59. package/dist/card-rule-offers.d.ts +32 -0
  60. package/dist/card-rule-offers.js +130 -0
  61. package/dist/config-catalog.js +12 -11
  62. package/dist/config-dir-trust.js +4 -2
  63. package/dist/config-invariants.d.ts +18 -7
  64. package/dist/config-invariants.js +51 -8
  65. package/dist/config-lkg.d.ts +5 -19
  66. package/dist/config-lkg.js +8 -62
  67. package/dist/config-provider.d.ts +1 -1
  68. package/dist/config-root-migration.d.ts +2 -2
  69. package/dist/config-types.d.ts +28 -38
  70. package/dist/config.d.ts +7 -5
  71. package/dist/config.js +55 -16
  72. package/dist/control-socket.d.ts +51 -0
  73. package/dist/control-socket.js +115 -0
  74. package/dist/deployment-governance.d.ts +2 -1
  75. package/dist/device-ws-hub.d.ts +7 -0
  76. package/dist/device-ws-hub.js +7 -1
  77. package/dist/elicitation.js +2 -2
  78. package/dist/entry-problems.d.ts +40 -3
  79. package/dist/entry-problems.js +3 -1
  80. package/dist/execution-env-refusal.d.ts +8 -2
  81. package/dist/execution-env-refusal.js +3 -0
  82. package/dist/fleet/engine-signal.d.ts +12 -29
  83. package/dist/fleet/engine-signal.js +1 -7
  84. package/dist/fleet-client.js +2 -5
  85. package/dist/gate-settlement.d.ts +1 -8
  86. package/dist/gate-settlement.js +0 -4
  87. package/dist/history-anchor.js +1 -1
  88. package/dist/hitl-delivery.d.ts +2 -3
  89. package/dist/hitl-delivery.js +0 -2
  90. package/dist/hooks/hook-llm.js +4 -2
  91. package/dist/hooks/hook-runner.d.ts +3 -2
  92. package/dist/hooks/hook-runner.js +16 -1
  93. package/dist/host-decision.d.ts +11 -11
  94. package/dist/http/active-run-conflict.d.ts +35 -2
  95. package/dist/http/active-run-conflict.js +48 -19
  96. package/dist/http/approval-sweeps.d.ts +1 -1
  97. package/dist/http/approval-sweeps.js +5 -2
  98. package/dist/http/checkpoint-ctx.d.ts +2 -0
  99. package/dist/http/checkpoint-ctx.js +1 -0
  100. package/dist/http/dispatch.d.ts +6 -2
  101. package/dist/http/dispatch.js +25 -5
  102. package/dist/http/durable-run-leg.js +0 -1
  103. package/dist/http/health-reader.d.ts +16 -9
  104. package/dist/http/health-reader.js +2 -1
  105. package/dist/http/health-self-report.js +1 -1
  106. package/dist/http/owner-access.d.ts +2 -3
  107. package/dist/http/owner-access.js +3 -4
  108. package/dist/http/principal-gate.d.ts +49 -21
  109. package/dist/http/principal-gate.js +61 -11
  110. package/dist/http/request-channel.d.ts +23 -0
  111. package/dist/http/request-channel.js +9 -0
  112. package/dist/http/request-guards.js +17 -2
  113. package/dist/http/resume-ctx-read.js +20 -3
  114. package/dist/http/resume-legs.d.ts +2 -2
  115. package/dist/http/resume-legs.js +111 -41
  116. package/dist/http/route-ctx.d.ts +73 -7
  117. package/dist/http/route-ctx.js +17 -0
  118. package/dist/http/route-table.d.ts +4 -0
  119. package/dist/http/route-table.js +4 -0
  120. package/dist/http/routes/admin-config-refresh.js +3 -3
  121. package/dist/http/routes/admin-drain.d.ts +3 -0
  122. package/dist/http/routes/admin-drain.js +7 -7
  123. package/dist/http/routes/admin-memory-optout.js +3 -3
  124. package/dist/http/routes/adoption.js +3 -5
  125. package/dist/http/routes/approvals-assistant.d.ts +2 -1
  126. package/dist/http/routes/approvals-assistant.js +95 -48
  127. package/dist/http/routes/capabilities.d.ts +4 -0
  128. package/dist/http/routes/capabilities.js +30 -5
  129. package/dist/http/routes/config-catalog.js +2 -2
  130. package/dist/http/routes/devices.js +1 -1
  131. package/dist/http/routes/diagnostics.d.ts +3 -3
  132. package/dist/http/routes/diagnostics.js +19 -7
  133. package/dist/http/routes/images.js +10 -10
  134. package/dist/http/routes/memory-bundle.js +3 -3
  135. package/dist/http/routes/memory-compliance.js +3 -3
  136. package/dist/http/routes/memory-consolidation.js +2 -2
  137. package/dist/http/routes/memory-origin.js +3 -3
  138. package/dist/http/routes/memory-policy.js +2 -2
  139. package/dist/http/routes/observability.js +3 -3
  140. package/dist/http/routes/retention-ops.js +3 -3
  141. package/dist/http/routes/rules.js +5 -5
  142. package/dist/http/routes/run-permission-mode.d.ts +2 -1
  143. package/dist/http/routes/run-permission-mode.js +2 -2
  144. package/dist/http/routes/runs.d.ts +4 -9
  145. package/dist/http/routes/runs.js +73 -33
  146. package/dist/http/routes/session-sync.d.ts +18 -6
  147. package/dist/http/routes/session-sync.js +38 -36
  148. package/dist/http/routes/sessions.js +20 -9
  149. package/dist/http/routes/tasks.js +28 -37
  150. package/dist/http/routes/workflows.js +1 -1
  151. package/dist/http/server.d.ts +9 -3
  152. package/dist/http/server.js +15 -3
  153. package/dist/http/submit-ctx.d.ts +1 -1
  154. package/dist/http/submit-ctx.js +2 -0
  155. package/dist/human-facing-args.d.ts +33 -0
  156. package/dist/human-facing-args.js +33 -0
  157. package/dist/index.d.ts +1 -1
  158. package/dist/k8s-api-credentials.d.ts +29 -0
  159. package/dist/k8s-api-credentials.js +25 -0
  160. package/dist/lane-home-probe.d.ts +1 -1
  161. package/dist/lane-home-probe.js +2 -1
  162. package/dist/leader/diffup.d.ts +19 -0
  163. package/dist/leader/diffup.js +7 -0
  164. package/dist/leader/leader.d.ts +114 -10
  165. package/dist/leader/leader.js +69 -5
  166. package/dist/leader/repair-wire.js +2 -2
  167. package/dist/leader/run-entry.d.ts +2 -1
  168. package/dist/leader/run-entry.js +1 -1
  169. package/dist/leader/wire.d.ts +42 -132
  170. package/dist/leader/wire.js +81 -67
  171. package/dist/memory-scope.d.ts +20 -9
  172. package/dist/memory-scope.js +15 -3
  173. package/dist/model-entry-headers.d.ts +9 -10
  174. package/dist/model-entry-headers.js +0 -4
  175. package/dist/model-entry-refusal.d.ts +7 -4
  176. package/dist/model-entry-refusal.js +11 -5
  177. package/dist/model-plane-face.d.ts +1 -1
  178. package/dist/model-plane-face.js +3 -1
  179. package/dist/model-route-endpoint.d.ts +13 -7
  180. package/dist/model-route-endpoint.js +14 -11
  181. package/dist/model-select.d.ts +22 -0
  182. package/dist/model-select.js +9 -0
  183. package/dist/model-unreachable-notice.d.ts +11 -0
  184. package/dist/model-unreachable-notice.js +4 -4
  185. package/dist/object-store-buckets.d.ts +640 -6
  186. package/dist/object-store-buckets.js +166 -0
  187. package/dist/observability/fail-open.d.ts +20 -16
  188. package/dist/observability/fail-open.js +20 -16
  189. package/dist/observability/logger.js +3 -1
  190. package/dist/operator-roster.d.ts +68 -0
  191. package/dist/operator-roster.js +32 -0
  192. package/dist/orchestration/workflow-park-decision.d.ts +1 -1
  193. package/dist/outbound-dispatcher.d.ts +71 -8
  194. package/dist/outbound-dispatcher.js +48 -7
  195. package/dist/owner-faces.d.ts +1 -1
  196. package/dist/parked-decide.d.ts +2 -2
  197. package/dist/permission-mode-admission.d.ts +59 -26
  198. package/dist/permission-mode-admission.js +37 -10
  199. package/dist/plugins/approval-ask-store-file.d.ts +4 -0
  200. package/dist/plugins/approval-ask-store-file.js +3 -0
  201. package/dist/plugins/approval-ask-store-memory.d.ts +4 -0
  202. package/dist/plugins/approval-ask-store-memory.js +7 -1
  203. package/dist/plugins/approval-ask-store-sql.d.ts +26 -2
  204. package/dist/plugins/approval-ask-store-sql.js +12 -1
  205. package/dist/plugins/blob-backend.d.ts +83 -7
  206. package/dist/plugins/blob-backend.js +57 -6
  207. package/dist/plugins/checkpoint-index-columns.d.ts +20 -16
  208. package/dist/plugins/checkpoint-index-columns.js +3 -6
  209. package/dist/plugins/checkpoint-store-face.d.ts +119 -61
  210. package/dist/plugins/checkpoint-store-face.js +134 -55
  211. package/dist/plugins/landed-attendants.d.ts +2 -2
  212. package/dist/plugins/local-checkpoint-store.d.ts +13 -3
  213. package/dist/plugins/local-checkpoint-store.js +38 -49
  214. package/dist/plugins/one-time-migrations.d.ts +51 -21
  215. package/dist/plugins/one-time-migrations.js +67 -45
  216. package/dist/plugins/pg-pool.js +11 -9
  217. package/dist/plugins/remote-env-host.d.ts +29 -10
  218. package/dist/plugins/remote-env-host.js +99 -19
  219. package/dist/plugins/remote-env-k8s.d.ts +68 -2
  220. package/dist/plugins/remote-env-k8s.js +107 -24
  221. package/dist/plugins/replica-registration.d.ts +1 -1
  222. package/dist/plugins/replica-registration.js +1 -1
  223. package/dist/plugins/s3-presign.d.ts +23 -0
  224. package/dist/plugins/s3-presign.js +37 -3
  225. package/dist/plugins/scheduler-support.d.ts +2 -2
  226. package/dist/plugins/scheduler-support.js +0 -3
  227. package/dist/plugins/schema-indexes.js +2 -0
  228. package/dist/plugins/send-file-ledger.d.ts +2 -2
  229. package/dist/plugins/send-file-ledger.js +2 -2
  230. package/dist/plugins/send-user-file.d.ts +3 -4
  231. package/dist/plugins/send-user-file.js +56 -52
  232. package/dist/plugins/session-blob-claim-token.d.ts +15 -0
  233. package/dist/plugins/session-blob-claim-token.js +20 -0
  234. package/dist/plugins/session-blob-namespace.d.ts +46 -0
  235. package/dist/plugins/session-blob-namespace.js +116 -0
  236. package/dist/plugins/snapshot-bucket-presence.d.ts +25 -2
  237. package/dist/plugins/snapshot-bucket-presence.js +8 -2
  238. package/dist/plugins/sql-json-column.d.ts +1 -1
  239. package/dist/plugins/store-backend.d.ts +44 -2
  240. package/dist/plugins/store-backend.js +75 -53
  241. package/dist/plugins/task-attachment-store.d.ts +2 -1
  242. package/dist/plugins/task-attachment-store.js +5 -1
  243. package/dist/plugins/tidb-pool.js +19 -24
  244. package/dist/plugins/workspace-custody.d.ts +4 -3
  245. package/dist/question.d.ts +2 -1
  246. package/dist/question.js +5 -13
  247. package/dist/request-form.d.ts +6 -1
  248. package/dist/request-form.js +4 -1
  249. package/dist/rule-issue-reading.d.ts +1 -1
  250. package/dist/rules-consent.d.ts +1 -1
  251. package/dist/run-local.js +8 -9
  252. package/dist/runs.d.ts +17 -8
  253. package/dist/runs.js +15 -2
  254. package/dist/runtime-governance.d.ts +2 -2
  255. package/dist/sema-config-dir.d.ts +2 -1
  256. package/dist/session-sync.d.ts +27 -11
  257. package/dist/session-sync.js +15 -7
  258. package/dist/stores-sql/blob-index-sql.d.ts +30 -9
  259. package/dist/stores-sql/blob-index-sql.js +40 -21
  260. package/dist/stores-sql/checkpoint-store-sql.d.ts +54 -27
  261. package/dist/stores-sql/checkpoint-store-sql.js +70 -146
  262. package/dist/stores-sql/file-history-store-sql.d.ts +64 -16
  263. package/dist/stores-sql/file-history-store-sql.js +100 -28
  264. package/dist/stores-sql/retention-store-sql.js +3 -9
  265. package/dist/task-settings.d.ts +6 -5
  266. package/dist/task-settings.js +3 -3
  267. package/dist/tool-approval.d.ts +342 -518
  268. package/dist/tool-approval.js +498 -1207
  269. package/dist/trace/core-keyset-guard.d.ts +1 -1
  270. package/dist/trace/ledger-events.d.ts +3 -3
  271. package/dist/trace/project.d.ts +2 -3
  272. package/dist/trace/redact.js +3 -2
  273. package/dist/trace/self-minted-wire.d.ts +287 -157
  274. package/dist/trace/self-minted-wire.js +93 -48
  275. package/dist/web-admin-client/apply-effective.js +2 -2
  276. package/dist/web-admin-client/read-warnings.d.ts +2 -2
  277. package/dist/web-admin-client/read-warnings.js +1 -1
  278. package/dist/web-admin-client/types.d.ts +1 -1
  279. package/dist/workspace-space.d.ts +10 -4
  280. package/dist/workspace-space.js +4 -1
  281. package/docs/DEVICE-EXECUTOR-PROTOCOL.md +1 -1
  282. package/package.json +6 -2
  283. package/scripts/embed-minimal.mjs +3 -3
  284. package/wire-changes/server@7.152.0.json +900 -0
  285. package/dist/config-d-migration.d.ts +0 -37
  286. package/dist/config-d-migration.js +0 -60
@@ -1,14 +1,51 @@
1
+ /**
2
+ * **条目问题的机读位** —— 请求体里的工具名清单 / 规则表有坏条目时,拒体(提交口 400 · 设置规则 422 · 续跑重放 409)与受理应答(`warnings`)说「哪几条、为什么」的**唯一一只形**,一处铸。
3
+ *
4
+ * 形(拒体机读位的版式律:事实在拒体根上,`problems[]` 每项的领域结构原样):
5
+ * 拒体 `{ error, errorCode, field, problems: EntryProblem[], total }`
6
+ * 应答 `{ …, warnings: EntryProblem[] }`(受理了、没拒,只告;只在有话说时在场)
7
+ * 一条问题 `{ code, field, entry, reason }`:
8
+ * · `code` = 这一条所在的那张清单**被拒时**拒体会带的码(技能清单 `request.field_invalid`;子代定义的 `denyTools` / `allowTools` `config.agent.unknown_tool`;根 run 的
9
+ * `excludeTools` / `allowTools` `config.tool_face_control`;设置规则桶 `request.unprocessable`)—— 一条问题就是「一只迷你拒绝」;
10
+ * · `field` = 这一条所在清单的**体内坐标**(`agents[0].denyTools`、`excludeTools`、`settings.permissions.deny`;不带条目下标);
11
+ * · `entry` = 条目的脱敏原值({@link redactListEntry}:不加引号、不转义,认出的凭据换记号);
12
+ * · `reason` = 为什么这一条什么也不是,闭词:引擎条目读法的原因词原样(`near_miss` / `tool_name` / `grammar` / `content_unsupported` / `wildcard_all` / `namespace_wildcard`),
13
+ * 规则编译器那一面的判词(引擎名字判官的 `retired` / `unmintable_segment` / `unprefixed_namespace`、引擎规则文法的 `invalid.*` · `unsupported.*` 码原样),
14
+ * 契约包层准入的判词(`below_trust_floor`),与本仓自己的三词({@link SERVER_ENTRY_PROBLEM_REASONS})。铸点的实参型是这几张表的并({@link EntryProblemReason}):
15
+ * 写一个哪张表都没有的词 = tsc 红(本仓自己的词只能从闭集取)。
16
+ * · 拒体的 `error` 句子**不变**:码与句子仍是「先撞上的那一张清单」的(第一条问题的码与坐标 = 体的 `errorCode` 与顶层 `field`),机读位另把**这一遍判下来的全部问题**一次列全 ——
17
+ * 单条问题的体 = 列表长 1,不是另一种形。
18
+ * · `total` = 这一遍判下来的问题总数;`problems` 至多 {@link MAX_ENTRY_PROBLEMS} 条(按扫描序截,每张清单自己的条数帽另在先:超帽的清单整只拒、不逐条读,不进本列表)。
19
+ * `total > problems.length` ⇒ 被截过。拒体恒有 `total`,缺席的「被截与否」不靠数条数猜。
20
+ *
21
+ * 为什么机读位只有这一个铸点:壳要按条提示、不解析句子(句子给人读,`error` 文案冻结但不是协议);一个面一个自己的键表就是 [ref] / [ref] 之后又一种形。
22
+ */
23
+ import type { AllowEntryInertReason, PermissionRuleIssue } from "@sema-agent/core";
24
+ import type { LayerAdmissionVerdict } from "@sema-agent/settings-schema";
25
+ import type { UnmatchableRuleName } from "./namespaced-rule-name.js";
1
26
  /** `problems` 的条数上限(= 一张清单的条数帽 `MAX_ALLOW_LAYER_ENTRIES` 的数;数在这里写死一次,`rule-entry-list.ts` 的帽改了不应拖着机读位走 —— 两者是两个界)。 */
2
27
  export declare const MAX_ENTRY_PROBLEMS = 1000;
3
28
  /**
4
29
  * 本仓自己铸的 `reason` 词(闭集;其余 `reason` 是引擎的词原样 —— 见文件头):
5
30
  * · `not_in_roster` —— 受理应答 `warnings` 的词:放行侧选择器清单里的这个名字不在名册(引擎目录 ∪ 本仓自铸工具 ∪ 本请求挂的调用方工具)、也不是协议命名空间名(懒挂载),引擎照旧受理、之后只告运维;
6
- * · `home_unresolvable` —— 设置规则 422 的词:`~/` 形路径规则而本部署解不出执行环境的家目录。
31
+ * · `home_unresolvable` —— 设置规则 422 的词:`~/` 形路径规则而本部署解不出执行环境的家目录;
32
+ * · `cc_rule_form` —— 名表消费者(按**整串工具名**比对的那几张表:`settings.permissions.neverAuto`,以及运维 / 中心的审批名单)里的带括号条目:这张表只比整名,
33
+ * `Bash(ls)` 永远匹配不到任何活工具。判据是本仓这几张表的比对方式,不是引擎的读法(引擎的 allow 层对同一条另有判词,读的是另一张表)⇒ 本仓的词。
7
34
  */
8
- export declare const SERVER_ENTRY_PROBLEM_REASONS: readonly ["not_in_roster", "home_unresolvable"];
35
+ export declare const SERVER_ENTRY_PROBLEM_REASONS: readonly ["not_in_roster", "home_unresolvable", "cc_rule_form"];
9
36
  export type ServerEntryProblemReason = (typeof SERVER_ENTRY_PROBLEM_REASONS)[number];
10
37
  /** 「读得出、却不在名册」的告知词({@link SERVER_ENTRY_PROBLEM_REASONS} 的第一员):`warnings` 里它之外的词都是引擎的条目读法读成空的原因词。 */
11
38
  export declare const NOT_IN_ROSTER: ServerEntryProblemReason;
39
+ /** 「执行环境的家目录 / 配置根读不出」的拒词(设置规则 422;两个铸点同读这一只)。 */
40
+ export declare const HOME_UNRESOLVABLE: ServerEntryProblemReason;
41
+ /** 「名表消费者里的带括号条目」的拒词(`config.ts` 的名表判据是唯一铸点)。 */
42
+ export declare const CC_RULE_FORM: ServerEntryProblemReason;
43
+ /**
44
+ * 一条问题的 `reason` 可以是哪些词 —— 铸点实参的型(wire 上的 `reason` 仍按开集读:引擎的词表随引擎版本增减):
45
+ * 本仓自铸的三词 ∪ 引擎条目读法的原因词 ∪ 引擎名字判官的判词 ∪ 引擎规则文法的码 ∪ 契约包层准入的 `below_trust_floor`。
46
+ * 哪张表都没有的词在铸点 tsc 红 —— 「自铸了闭集外的词」不可能静默上 wire。
47
+ */
48
+ export type EntryProblemReason = ServerEntryProblemReason | AllowEntryInertReason | UnmatchableRuleName["kind"] | PermissionRuleIssue["code"] | Extract<LayerAdmissionVerdict, "below_trust_floor">;
12
49
  /** 一条问题(wire 形)。 */
13
50
  export interface EntryProblem {
14
51
  readonly code: string;
@@ -17,7 +54,7 @@ export interface EntryProblem {
17
54
  readonly reason: string;
18
55
  }
19
56
  /** 铸一条问题:`entry` 收**原串**,这里过脱敏(调用方没有「忘了脱敏」的可能)。 */
20
- export declare function entryProblem(code: string, field: string, rawEntry: string, reason: string): EntryProblem;
57
+ export declare function entryProblem(code: string, field: string, rawEntry: string, reason: EntryProblemReason): EntryProblem;
21
58
  /** 拒体上的机读位(原样摊在拒体根上:`HttpError.extra` / `refusalBody` 的 `facts`)。型别名而不是接口 —— 要能直接当 `Record<string, unknown>` 用。 */
22
59
  export type EntryProblemsFacts = {
23
60
  readonly field: string;
@@ -1,7 +1,9 @@
1
1
  import { redactListEntry } from "./list-entry-display.js";
2
2
  export const MAX_ENTRY_PROBLEMS = 1_000;
3
- export const SERVER_ENTRY_PROBLEM_REASONS = ["not_in_roster", "home_unresolvable"];
3
+ export const SERVER_ENTRY_PROBLEM_REASONS = ["not_in_roster", "home_unresolvable", "cc_rule_form"];
4
4
  export const NOT_IN_ROSTER = "not_in_roster";
5
+ export const HOME_UNRESOLVABLE = "home_unresolvable";
6
+ export const CC_RULE_FORM = "cc_rule_form";
5
7
  export function entryProblem(code, field, rawEntry, reason) {
6
8
  return { code, field, entry: redactListEntry(rawEntry), reason };
7
9
  }
@@ -2,7 +2,8 @@
2
2
  * 本仓自铸的**执行环境拒码**闭集(`env.*` 族)的唯一属主(纯叶:零值依赖)。
3
3
  *
4
4
  * 一族一句:**这只执行环境没开,而且再问也是同一个答** —— 部署状态(或会话数据)与这条 run 冲突,原样重试不改判,出路在部署。两处产出、同一族:
5
- * · host 车道的工厂在铸环境之前拒(读数在构造时就到手:`lane-home-probe.ts` 的 `laneHomeRefusal`),引擎在准备期原样再抛;
5
+ * · 工厂在铸环境之前拒(host 车道:读数在构造时就到手,`lane-home-probe.ts` 的 `laneHomeRefusal`;k8s 车道:每条 run 铸环境前读一次集群 API 凭据,
6
+ * `boot/execution-env.ts` 的 `createK8sRunEnvFactory`),都经 {@link executionEnvRefusalError} 铸带码的错,引擎在准备期原样再抛、run 以它失败;
6
7
  * · 远端车道在建连时答的**立定拒**(这只环境此后每一次建连都答同一个拒,适配器记住它):码由 `plugins/remote-env-connect-seat.ts` 的拒因表从事实词拼出
7
8
  * —— 那张表是远端车道拼本族码的唯一入口,立定 ⇔ 码在引擎可重试表之外 ⇔ 记住。
8
9
  * 同步提交腿按零工作拒落档(`runs.ts` 的 `EXECUTION_ENV_REFUSAL_HTTP_STATUS`,按本闭集键控:加一员而档没跟 ⇒ tsc 红)。
@@ -12,12 +13,17 @@
12
13
  * `WORKSPACE_SNAPSHOT_BUCKET` 指向已有的桶,或 `WORKSPACE_PERSIST=off`。
13
14
  * · `env.occupant_missing` —— k8s 车道读这条 run 的会话住客:会话行在、却不带住客令牌(存储数据缺陷,重发不改判):给行补令牌或删会话,或关掉要它的旋钮。
14
15
  * · `env.sandbox_refused` —— 隔离车道(k8s / e2b / local-docker)替这条 run 建的沙箱被立定地拒:集群在准入时拒了 pod、成员凭据中继建不起来、
15
- * 快照归档在桶里却取不回、工作区的填充(会话附件 / 项目包种子)放不进且换一台机器也是同一个答。是哪一件、怎么改,句子里说。
16
+ * 快照归档在桶里却取不回、工作区的填充(会话附件 / 项目包种子)放不进且换一台机器也是同一个答、k8s 车道的集群 API 凭据起服之后读不到或被集群 401 拒
17
+ * (`k8s-api-credentials.ts`:凭据起服时就缺是起服拒 `config.k8s_api_credentials_missing`,到不了 run)。是哪一件、怎么改,句子里说。
16
18
  * · `env.host_key_rejected` —— ssh 车道:目标机出示的主机密钥过不了部署钉的判(`SSH_HOST_FINGERPRINT` / `SSH_KNOWN_HOSTS`:指纹不符、条目换了钥、被吊销、没有条目)。
17
19
  * 改钉或查明对面为什么换了钥;同一配置同一主机每次同答。
18
20
  */
19
21
  export declare const EXECUTION_ENV_REFUSAL_CODES: readonly ["env.home_unconfirmed", "env.snapshot_bucket_missing", "env.occupant_missing", "env.sandbox_refused", "env.host_key_rejected"];
20
22
  export type ExecutionEnvRefusalCode = (typeof EXECUTION_ENV_REFUSAL_CODES)[number];
23
+ /** 本族的带码错(唯一铸点):句 = 拒句原文,`code` = 闭集里的一员;工厂原样抛出,引擎在准备期再抛,run 的失败终局原样承运码与句。 */
24
+ export declare function executionEnvRefusalError<C extends ExecutionEnvRefusalCode>(code: C, message: string): Error & {
25
+ readonly code: C;
26
+ };
21
27
  /** 这个码是不是本族的一员(按闭集,不按前缀:引擎自己的 `env.lifetime_expired` 同前缀而不是本族)。 */
22
28
  export declare function isExecutionEnvRefusalCode(code: unknown): code is ExecutionEnvRefusalCode;
23
29
  //# sourceMappingURL=execution-env-refusal.d.ts.map
@@ -1,4 +1,7 @@
1
1
  export const EXECUTION_ENV_REFUSAL_CODES = ["env.home_unconfirmed", "env.snapshot_bucket_missing", "env.occupant_missing", "env.sandbox_refused", "env.host_key_rejected"];
2
+ export function executionEnvRefusalError(code, message) {
3
+ return Object.assign(new Error(message), { code });
4
+ }
2
5
  export function isExecutionEnvRefusalCode(code) {
3
6
  return typeof code === "string" && EXECUTION_ENV_REFUSAL_CODES.includes(code);
4
7
  }
@@ -20,22 +20,17 @@
20
20
  * 注入了读数也不读;所以「`/health` 不报 `leaseState` 而准入照按租约拒」这一形构造不出来。
21
21
  * **身份不是引擎态**:`instanceId`(本进程起步自铸的那一只,`boot/stage-03` 的 uuidv7)是体的身份,只在两出口体的**顶层**说一次,
22
22
  * 铸点不读它、契约形里不重复它。
23
- * 5. **两形一读(展开 / 收缩)**:两出口今天各发两形 —— 嵌套键 {@link ENGINE_SIGNAL_KEY}(契约 `EngineSignal` 整只,{@link buildEngineSignal}),
24
- * 与 8.0 扁平方言(布尔 `draining` + `drainingSince`、`/health` 就绪时不带 `ready`、`restart`、成员三键、`/health` 的世代账)。两形读的是
25
- * **同一次**铸点读数里的**同一个字段**,投影全在本模块({@link buildEngineSignal} / {@link heartbeatReadinessKeys} / {@link healthDrainingKeys} /
26
- * {@link fleetMembershipKeys} / {@link healthConfigLedgerKeys}),出口文件不拼引擎态的键。排空在两形上读的都是排空**事实**(`EngineDraining`,
27
- * 三键齐才在),不是就绪原因 —— 所以「`engineSignal.draining` 在场 ⇔ 扁平 `draining` 为真、`drainingSince` = `engineSignal.draining.since`」
28
- * 是构造出来的,不靠「唯一入口整组写四键」这条运行时不变量(那条不变量只管就绪原因与事实一致)。
29
- * 心跳体 = 契约 `InstanceAnnouncement` + 嵌套键这一只:契约包 10.x 的心跳形还没有它的座位,10.x 中心按默认 strip 解析丢掉它、照收心跳;
30
- * 世代账扁平两键契约心跳形没有座位,只上 `/health`(嵌套形里有,两出口都带)。非 fleet 部署的扁平键与 7.122.0 逐字同。
31
- * 收缩:扁平布尔对(`draining` / `drainingSince`)settings-schema 12.0.0 从契约形删、本引擎 7.124.0+ 删发(届时删它们的投影);嵌套键名在
32
- * 契约包自有这只常量的那一版提货时改读它。
23
+ * 5. **一形**:引擎态只在体上的一只键 `engineSignal`(契约包 `ENGINE_SIGNAL_KEY`,本仓不另拼)下说,值 = 契约 `EngineSignal` 整只({@link buildEngineSignal})。
24
+ * 心跳体 = 契约 `InstanceAnnouncement`(身份 + `modelRefusals`)+ 这一只键 —— 8.0 扁平方言(平铺 `ready` / 布尔 `draining` / `restart` / 成员三键)
25
+ * 随契约包 26.0.0 从心跳形删除,本引擎同版停发;`/health` 的平铺排空对(布尔 `draining` + `drainingSince`)同版停发。`/health` 上其余与信号同名的顶层键
26
+ * (`restart` / 成员三键 / 世代账)是本仓自己的诊断面 wire(契约 `InstanceHealth` 从未给它们座位,读方是 sdk 的 `/health` 读型),投影仍全在本模块
27
+ * ({@link fleetMembershipKeys} / {@link healthConfigLedgerKeys}),出口文件不拼引擎态的键。
33
28
  * 6. **租约四态的词表属主是契约包**(`LeaseState`):本模块的读数型 {@link ServingLeaseView} 按它逐词对齐(下面的编译期断言两向钉),
34
29
  * 契约加一个词 ⇒ 本仓编译红,不会悄悄多出一个本仓读不出的态。
35
30
  *
36
- * 模块形:纯函数(契约包只 import 型;值 import 只有两只纯叶 `http/readiness.ts` 与 `fleet/drain-entry.ts`)—— `http/` 与 `fleet-client.ts` 都读它,不许长出回环。
31
+ * 模块形:纯函数(契约包只取型与键名常量 `ENGINE_SIGNAL_KEY`;本仓值 import 只有两只纯叶 `http/readiness.ts` 与 `fleet/drain-entry.ts`)—— `http/` 与 `fleet-client.ts` 都读它,不许长出回环。
37
32
  */
38
- import type { EngineDraining, EngineSignal, InstanceAnnouncement, LeaseState, RestartSignal } from "@sema-agent/settings-schema/fleet";
33
+ import { ENGINE_SIGNAL_KEY, type EngineDraining, type EngineSignal, type LeaseState, type RestartSignal } from "@sema-agent/settings-schema/fleet";
39
34
  import { type ReadinessInputs, type ReadinessVerdict } from "../http/readiness.js";
40
35
  /**
41
36
  * 租约此刻的读数(租约客户端交出;纯数据)。态的词表 = 契约 `LeaseState`(四词的语义在契约注里:`none` 不生效 / `granted` 持有 /
@@ -52,8 +47,8 @@ export type ServingLeaseView = {
52
47
  } | {
53
48
  readonly state: Extract<LeaseState, "denied">;
54
49
  };
55
- /** 心跳体上的 fleet 成员三键 —— 类型取自契约心跳形(拼法与值域只有契约一个写者)。 */
56
- export type FleetMembershipKeys = Pick<InstanceAnnouncement, "generation" | "leaseState" | "leaseUntil">;
50
+ /** `/health` 上的 fleet 成员三键 —— 类型取自契约 `EngineSignal` 的同名键(拼法与值域只有契约一个写者)。 */
51
+ export type FleetMembershipKeys = Pick<EngineSignal, "generation" | "leaseState" | "leaseUntil">;
57
52
  /** 非 fleet 成员 / 没装租约客户端时的读数(唯一拼法)。成员的推定围栏只住在租约客户端里,不进这只缺省值。 */
58
53
  export declare const LEASE_NONE: ServingLeaseView;
59
54
  /**
@@ -148,12 +143,7 @@ export interface EngineSignalFacts {
148
143
  }
149
144
  /** **唯一**铸点(活判,每次调用现读输入)。 */
150
145
  export declare function mintEngineSignal(deps: EngineSignalInputs): EngineSignalFacts;
151
- /**
152
- * 两出口体上嵌套引擎信号的键名(规则 5;两出口同一只拼法)。契约包 10.x 没有这只常量(它的心跳形也没有这一座位);契约包自有它的那一版
153
- * 提货时,本常量删、改读契约包的。
154
- */
155
- export declare const ENGINE_SIGNAL_KEY = "engineSignal";
156
- /** 体上的嵌套引擎信号:键 {@link ENGINE_SIGNAL_KEY},值 = 契约 `EngineSignal`。 */
146
+ /** 体上的嵌套引擎信号:键 = 契约包的 `ENGINE_SIGNAL_KEY`(两出口同一只拼法,本仓不另拼),值 = 契约 `EngineSignal`。 */
157
147
  export type EngineSignalCarrier = {
158
148
  readonly [ENGINE_SIGNAL_KEY]: EngineSignal;
159
149
  };
@@ -163,18 +153,11 @@ export type EngineSignalCarrier = {
163
153
  */
164
154
  export declare function buildEngineSignal(s: EngineSignalFacts): EngineSignal;
165
155
  /**
166
- * fleet 成员身份三键的**唯一**投影(两出口同调,同值同序):`generation` / `leaseState` / `leaseUntil`。
167
- * 在场律:非 fleet 成员(无 `generation`)⇒ 空对象(两出口逐字节同 7.120.0);成员 ⇒ `generation` + `leaseState` 恒在,
156
+ * fleet 成员身份三键的**唯一**投影(嵌套信号与 `/health` 顶层同调,同值同序):`generation` / `leaseState` / `leaseUntil`。
157
+ * 在场律:非 fleet 成员(无 `generation`)⇒ 空对象;成员 ⇒ `generation` + `leaseState` 恒在,
168
158
  * `leaseUntil` 只在 `granted`。
169
159
  */
170
160
  export declare function fleetMembershipKeys(s: EngineSignalFacts): FleetMembershipKeys;
171
- /** 心跳的 8.0 扁平方言 `ready` / `draining`(恒带,`false` 也带):`ready` = 就绪判,`draining` = 排空事实在场(规则 5,与嵌套形读同一个字段)。 */
172
- export declare function heartbeatReadinessKeys(s: EngineSignalFacts): Pick<InstanceAnnouncement, "ready" | "draining">;
173
- /** `/health` 的 8.0 扁平排空对:只在排空中带 —— `draining: true` + `drainingSince` = 排空事实的 `since`(规则 5,与嵌套形读同一个字段)。 */
174
- export declare function healthDrainingKeys(s: EngineSignalFacts): {
175
- readonly draining?: true;
176
- readonly drainingSince?: number;
177
- };
178
161
  /**
179
162
  * `/health` 的世代账扁平键(未接线 ⇒ 全缺席):target / applied 两版本(与嵌套形同一次读数)+ 两只收货序数(进程内单调,「见过多少代 / 停在哪一代」
180
163
  * 的推进判据)+ `configApplyStaleMs`(两者持续不等的时长,收敛即缺席)。只上 `/health`(契约心跳形没有这些座位)。
@@ -1,3 +1,4 @@
1
+ import { ENGINE_SIGNAL_KEY } from "@sema-agent/settings-schema/fleet";
1
2
  import { readinessOf } from "../http/readiness.js";
2
3
  import { drainingFactOf } from "./drain-entry.js";
3
4
  export const LEASE_NONE = Object.freeze({ state: "none" });
@@ -37,7 +38,6 @@ export function mintEngineSignal(deps) {
37
38
  ...(configApply !== undefined ? { configApply } : {}),
38
39
  };
39
40
  }
40
- export const ENGINE_SIGNAL_KEY = "engineSignal";
41
41
  export function buildEngineSignal(s) {
42
42
  return {
43
43
  ready: s.verdict.ready,
@@ -64,12 +64,6 @@ export function fleetMembershipKeys(s) {
64
64
  }
65
65
  }
66
66
  }
67
- export function heartbeatReadinessKeys(s) {
68
- return { ready: s.verdict.ready, draining: s.draining !== undefined };
69
- }
70
- export function healthDrainingKeys(s) {
71
- return s.draining === undefined ? {} : { draining: true, drainingSince: s.draining.since };
72
- }
73
67
  export function healthConfigLedgerKeys(s) {
74
68
  const g = s.configApply;
75
69
  if (g === undefined)
@@ -1,5 +1,5 @@
1
- import { InstanceAnnouncement, UsageReport, DEFAULT_HEARTBEAT_MS, readCapabilityReading } from "@sema-agent/settings-schema/fleet";
2
- import { ENGINE_SIGNAL_KEY, buildEngineSignal, fleetMembershipKeys, heartbeatReadinessKeys } from "./fleet/engine-signal.js";
1
+ import { ENGINE_SIGNAL_KEY, InstanceAnnouncement, UsageReport, DEFAULT_HEARTBEAT_MS, readCapabilityReading } from "@sema-agent/settings-schema/fleet";
2
+ import { buildEngineSignal } from "./fleet/engine-signal.js";
3
3
  import { centerFetch, centerLaneConfigured } from "./web-admin-client/center-request.js";
4
4
  import { recordFailOpen } from "./observability/fail-open.js";
5
5
  import { createIdentityBins, pinAccountingIdentity } from "./center-credential.js";
@@ -153,11 +153,8 @@ export function startFleetClient(opts) {
153
153
  worker: opts.center.worker,
154
154
  address,
155
155
  version: opts.version,
156
- ...heartbeatReadinessKeys(signal),
157
156
  heartbeatMs,
158
- ...(signal.restart !== undefined ? { restart: signal.restart } : {}),
159
157
  ...(modelRefusals !== undefined ? { modelRefusals } : {}),
160
- ...fleetMembershipKeys(signal),
161
158
  [ENGINE_SIGNAL_KEY]: engineSignal,
162
159
  };
163
160
  sending = true;
@@ -12,8 +12,7 @@
12
12
  * 调用方对一条引擎续跑腿的分类({@link GateCommitment})只说「这条腿到边界时能证什么」,**从不单独铸位** —— 位要有边界作证。
13
13
  * 不铸的出口(都在调用点成文):`checkpoint.resume_aborted` 取消(拿不到 resolve 的返回值 ⇒ 证不出)、抛出臂的取消(受理之后也可能走到 ⇒
14
14
  * **刻意不带**证据,fail-closed)、4xx、交给宿主 / 新铸一跑 / 同一决定重投的回执(`delivered`,门由别人结清或仍待决)、停驻子代认领到的
15
- * token 不是选中的那一张(⇒ `409 decide.gate_moved`,不复活)。证据只随**同一次决定**的回放走:停驻赎回席的反向重试回放摘掉它
16
- * ({@link withoutSettlementEvidence})。
15
+ * token 不是选中的那一张(⇒ `409 decide.gate_moved`,不复活)。
17
16
  *
18
17
  * ## 读法(三句,契约 §4a「结清证据」同句)
19
18
  * · 位在场 ⇒ 门已以此决定结清过(历史证据;与 `errorCode:"cancelled"` 或 `retriable:true` 并存时同样成立 —— 它不证明卡的**当前**状态、
@@ -57,12 +56,6 @@ export interface GateSettlementEvidence {
57
56
  export declare const NO_SETTLEMENT_EVIDENCE: GateSettlementEvidence;
58
57
  /** **唯一铸点**:一次边界跨越 → 体上的证据片段。 */
59
58
  export declare function buildSettlementEvidence(crossing: SettlementCrossing): GateSettlementEvidence;
60
- /**
61
- * 一张已带证据的回执被拿去答**另一个**决定(停驻赎回席的反向重试:回放首次受理的那一向、不改判)⇒ 证据两键都摘掉 ——
62
- * 证据说的是当初被结清的那次决定,这一次请求的决定从没被结清。同向重试是同一次请求的回放,体原样(证据随它)。
63
- * 只摘、不铸:本模块之外没有第二个写这两键的地方。
64
- */
65
- export declare function withoutSettlementEvidence<B extends Record<string, unknown>>(body: B): Omit<B, keyof GateSettlementEvidence>;
66
59
  /** **唯一读法**:这张回决应答说「门已以此决定结清过」吗(`200` 且体上的位为真)。两个读者同调这一只。 */
67
60
  export declare function decisionCommittedOf(out: {
68
61
  readonly status: number;
@@ -30,10 +30,6 @@ export function buildSettlementEvidence(crossing) {
30
30
  }
31
31
  }
32
32
  }
33
- export function withoutSettlementEvidence(body) {
34
- const { decisionCommitted: _committed, checkpointId: _identity, ...rest } = body;
35
- return rest;
36
- }
37
33
  export function decisionCommittedOf(out) {
38
34
  return out.status === 200 && out.body.decisionCommitted === true;
39
35
  }
@@ -2,7 +2,7 @@ import { HttpError } from "./security.js";
2
2
  import { recordFailOpen } from "./observability/fail-open.js";
3
3
  import { protocolEntry, readVisibleRun } from "./http/owner-access.js";
4
4
  const NO_ANCHOR = "no rewind anchor is recorded under that handle";
5
- const PROMPT_WITHOUT_ANCHOR = `${NO_ANCHOR}: it names a prompt of this session that recorded none (a prompt that carried attachments records none when its attachment frames were interrupted or their count did not match)`;
5
+ const PROMPT_WITHOUT_ANCHOR = `${NO_ANCHOR}: it names a prompt of this session that recorded none`;
6
6
  export function anchorReaderOf(req, w, caller) {
7
7
  return protocolEntry(req, w, "run.anchor", caller);
8
8
  }
@@ -16,10 +16,9 @@
16
16
  import type { QuestionFrame } from "./question.js";
17
17
  import type { ElicitationFrame } from "./elicitation.js";
18
18
  import type { ApprovalCardLegFrame, ApprovalRevokeFrame } from "./approval-card.js";
19
- import type { ToolApprovalFrame } from "./tool-approval.js";
20
19
  import type { LedgerEventType } from "./trace/ledger-events.js";
21
- /** 三族的人在环帧(开 / 收 / 撤)。九个帧型全在账本闭集里(下面那条编译期断言)。 */
22
- export type HitlFrame = QuestionFrame | ElicitationFrame | ApprovalCardLegFrame | ApprovalRevokeFrame | ToolApprovalFrame;
20
+ /** 三族的人在环帧(开 / 收 / 撤)。七个帧型全在账本闭集里(下面那条编译期断言)。 */
21
+ export type HitlFrame = QuestionFrame | ElicitationFrame | ApprovalCardLegFrame | ApprovalRevokeFrame;
23
22
  /**
24
23
  * 一次投递在各只 sink 上的接下与否 —— **只有这一次投递涉及的 sink 才有键**(不在场 / 不在 `onto` 里的没有键)。
25
24
  * 也是 {@link HitlTransport.deliver} 的 `onto` 入参形:值为 `true` 的 sink 才写。
@@ -17,8 +17,6 @@ function frameKey(frame) {
17
17
  return `elicitation=${frame.elicitationId}`;
18
18
  case "approval_request":
19
19
  case "approval_complete":
20
- case "tool_approval":
21
- case "tool_approval_complete":
22
20
  return `approval=${frame.approvalId}`;
23
21
  case "approval_revoke":
24
22
  return `batch=${frame.batchId}`;
@@ -1,5 +1,6 @@
1
1
  import { admitRouteRequest, applyReasoningToRequest, AUTO_MODE_CLASSIFIER_LOW_REASONING_BUDGET_TOKENS, BrainError, joinRequestUrl, lowestReasoningSeat, mergeReasoningHeaders, resolveRouteCredential, routeKeyOf } from "@sema-agent/core";
2
- import { matchCatalogModel, refusedCatalogEntry, servedModelTableLeg } from "../model-select.js";
2
+ import { modelRefusalLegOf, matchCatalogModel, refusedCatalogEntry, servedModelTableLeg } from "../model-select.js";
3
+ import { configSourceKind } from "../config-provider.js";
3
4
  import { echoModelRef, modelUnavailableMessage } from "../model-entry-refusal.js";
4
5
  import { resolveOpenaiRouteEndpoint } from "../model-route-endpoint.js";
5
6
  import { anthropicLaneCredentialOf } from "../model-route-gap.js";
@@ -47,6 +48,7 @@ function routeCredentialHeader(credential) {
47
48
  }
48
49
  export function createHookLlm(deps) {
49
50
  const { config, metrics } = deps;
51
+ const webAdminIsConfigSource = configSourceKind(config) === "remote";
50
52
  const anthropicRouteBaseUrl = () => anthropicRouteRoot(config.anthropic ?? {});
51
53
  const shapeFrom = (m, providerModelId = m.id) => {
52
54
  const catalogRef = m.name;
@@ -55,7 +57,7 @@ export function createHookLlm(deps) {
55
57
  case "anthropic":
56
58
  return { ok: true, catalogRef, providerModelId, baseUrl: m.baseUrl || anthropicRouteBaseUrl(), api: "anthropic-messages", model: m };
57
59
  case "gateway": {
58
- const endpoint = resolveOpenaiRouteEndpoint(catalogRef, m, config.gatewayBaseUrl, servedModelTableLeg(config));
60
+ const endpoint = resolveOpenaiRouteEndpoint(catalogRef, m, config.gatewayBaseUrl, modelRefusalLegOf(servedModelTableLeg(config), webAdminIsConfigSource));
59
61
  return endpoint.ok ? { ok: true, catalogRef, providerModelId, baseUrl: endpoint.baseUrl, api: "openai-completions", model: m } : unresolvedPick(endpoint.refusal);
60
62
  }
61
63
  }
@@ -37,7 +37,7 @@ export declare const MAX_HOOK_OUTPUT_BYTES: number;
37
37
  * 且 4096 的单条帽保证**前两条**钩子的话仍整段进得去(截断是配置广度的代价,不是常态)。
38
38
  */
39
39
  export declare const MAX_HOOK_CONTEXT_TOTAL_CHARS = 10000;
40
- /** 契约里**引擎属主**的 `settings.hooks` 事件(契约包的九员字面量元组;壳属主的事件引擎不跑,owner-single)。 */
40
+ /** 契约里**引擎属主**的 `settings.hooks` 事件(契约包的十员字面量元组;壳属主的事件引擎不跑,owner-single)。 */
41
41
  export type EngineOwnedHookEvent = (typeof ENGINE_OWNED_HOOK_EVENTS)[number];
42
42
  /**
43
43
  * 律二 · **事件对位只有一张表,一事件一站**:引擎属主的每个 `settings.hooks` 事件 → 它挂的那一个 `classic.*` 站(同名站)。
@@ -56,6 +56,7 @@ export declare const SETTINGS_HOOK_STATIONS: {
56
56
  readonly StopFailure: "classic.StopFailure";
57
57
  readonly PreCompact: "classic.PreCompact";
58
58
  readonly PostCompact: "classic.PostCompact";
59
+ readonly PermissionDenied: "classic.PermissionDenied";
59
60
  };
60
61
  /**
61
62
  * **一条车道一张注册**:每张的名字 —— wire 可见(`wiring_manifest.mods[].name`、`allowRuleShadowed[].entries`、问因项 `askReasons[].registration`),
@@ -170,7 +171,7 @@ export type ParseHooksConfigResult = {
170
171
  * 升级前被拦的 Bash 升级后放行(安全轴上的回退)。所以这条规则住在 fresh 专用的判据里,与 `taskSettingsKeyIssue` 同姿势
171
172
  * (「fresh 400 / resume 宽容」双层:会砖存量的规则只咬 fresh)。resume 照旧整只采纳,别名那一组继续永不命中(与 7.111.0 逐字同),其余照跑。
172
173
  * · **哪些事件** = 契约 `HOOK_EVENT_MATCHER_FIELD[event] === "tool_name"` ∧ 引擎属主 `HOOK_EVENT_OWNER[event] === "engine"`
173
- * (今天恰是上面三个;`PermissionRequest` / `PermissionDenied` 也匹配 `tool_name` 但属壳,壳自己跑,不是本 runner 的读法)。**不手抄事件表**([ref])。
174
+ * (今天 = 上面三个 + `PermissionDenied`(settings-schema 26.0.0 起引擎属主,名 = 同一次调用在门上的 wire 名,派生自动带上);`PermissionRequest` 也匹配 `tool_name` 但属壳,壳自己跑,不是本 runner 的读法)。**不手抄事件表**([ref])。
174
175
  * · **哪些名字算别名** = core 静态目录(`describeToolCatalog()`)里某条 `face.aliases` 的成员,且它自己不是另一条目的 wire 名({@link engineToolAliases})。
175
176
  * **只读这一只真源**([ref])。本仓自身不声明带别名的工具;嵌入方经 `resolveSpec` 席挂的别名与 MCP 工具名在受理面看不见(名册是每任务装配的),**不在射程**。
176
177
  * · **正名同在则不拒**:`正名|别名` / `List.*` 会命中正名,不是「静默不命中」,且正是 7.107.0 CHANGELOG 给的「滚动期两名都写」补偿形。
@@ -56,6 +56,7 @@ export const SETTINGS_HOOK_STATIONS = {
56
56
  StopFailure: "classic.StopFailure",
57
57
  PreCompact: "classic.PreCompact",
58
58
  PostCompact: "classic.PostCompact",
59
+ PermissionDenied: "classic.PermissionDenied",
59
60
  };
60
61
  function chainsBelowTaskOn(patterns, station) {
61
62
  return patterns.some((p) => p === station || (p.endsWith(".*") && station.startsWith(p.slice(0, -1))));
@@ -1664,7 +1665,8 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
1664
1665
  const stopFailureEntries = lit("StopFailure");
1665
1666
  const preCompactEntries = lit("PreCompact");
1666
1667
  const postCompactEntries = lit("PostCompact");
1667
- if (!pre && !post && !postFailure && !postBatch && !promptSubmit && !stopEntries && !stopFailureEntries && !preCompactEntries && !postCompactEntries) {
1668
+ const permissionDeniedEntries = lit("PermissionDenied");
1669
+ if (!pre && !post && !postFailure && !postBatch && !promptSubmit && !stopEntries && !stopFailureEntries && !preCompactEntries && !postCompactEntries && !permissionDeniedEntries) {
1668
1670
  return undefined;
1669
1671
  }
1670
1672
  const onceSpent = new Set();
@@ -2178,6 +2180,19 @@ function createLaneRegistration(lane, config, ctx, budgetMs) {
2178
2180
  await runObserveOnlyEvent("PostCompact", postCompactEntries, cctx.trigger, payload, ctx, once, halt);
2179
2181
  });
2180
2182
  }
2183
+ if (permissionDeniedEntries) {
2184
+ translators.PermissionDenied = (dctx, halt) => settleOnce(onceSpent, async (once) => {
2185
+ const payload = {
2186
+ ...basePayload(ctx, dctx.permissionMode),
2187
+ hook_event_name: "PermissionDenied",
2188
+ tool_name: dctx.toolName,
2189
+ tool_input: dctx.input,
2190
+ tool_use_id: dctx.toolCallId,
2191
+ reason: clipDataText(dctx.reason, MAX_HOOK_FEEDBACK_CHARS),
2192
+ };
2193
+ await runObserveOnlyEvent("PermissionDenied", permissionDeniedEntries, dctx.toolName, payload, ctx, once, halt);
2194
+ });
2195
+ }
2181
2196
  const events = Object.keys(translators);
2182
2197
  return {
2183
2198
  name: SETTINGS_HOOKS_REGISTRATIONS[lane],
@@ -71,8 +71,8 @@ export type HostDecision = Extract<ResumeOutcome, {
71
71
  * ══ 决定体的出处位 `decidedBy`:一只闭集、一只读法、一只映射 ═══════════════════════════════════════════════
72
72
  *
73
73
  * 规则一句话:**一个审批决定用一只键说是谁做的** —— `decidedBy ∈ {"person","policy"}`,缺席 = `"person"`;读它的只有
74
- * {@link readDecider}(三条工具审批决定口共读:live `POST /v1/tool-approvals/:id/respond`、耐久 ask 账
75
- * `POST /v1/tasks/:id/asks/:askId/decision`、耐久 `POST /v1/approvals/:sessionId/decide`),把它交给引擎的只有
74
+ * {@link readDecider}(两条工具审批决定口共读:决断口
75
+ * `POST /v1/tasks/:taskId/asks/:askId/decision`、耐久 `POST /v1/approvals/:sessionId/decide`),把它交给引擎的只有
76
76
  * {@link liveHostSource}(同步座 `AskOutcome.settledBy`)与 {@link hostDecisionFacts}(停驻座 `hostDecision.decidedBy`)。
77
77
  * · 词与决定动词**正交**:策略可以放行也可以拒(core 7.39.0 起引擎铸 `policy_allowed` / `policy_refused`)。唯一的例外是
78
78
  * 引擎自己的那一条 —— 一张要人的卡(`requiresRealApproval`)不归策略答,见 {@link heldAskOf}(判官是 core 的 `policyCannotAnswer`)。
@@ -103,14 +103,14 @@ export declare const DECIDED_BY_NOT_IN_PROOF = "decidedBy is not supported on a
103
103
  /** 一张要人的卡上策略的放行(两条决定口同一句;判官 core `policyCannotAnswer`,问形见 {@link heldAskOf})。 */
104
104
  export declare const POLICY_CANNOT_ALLOW_PERSON_ASK = "decidedBy \"policy\" cannot allow this ask \u2014 it demands a person's approval (risk.requiresRealApproval), and a policy's answer is not a person's; answer it as a person, or refuse it as the policy";
105
105
  /**
106
- * 退役键 `settledBy`(7.93.3–7.117.x 的「只配 deny」那一位)的拒句。三条决定口共用这一句,出句的铸点是 {@link retiredDecisionKeyFacts}(各口不直接引用本常量)。
107
- * live `/respond` 的解析不是键闭集的(未知键一律忽略),而这只键不是随便一个未知键:它是调用方在**明确陈述**「这是策略答的」—— 忽略它就是把缺席律(person)
108
- * 套在一个说了话的体上(旧壳的策略拒记成人拒;一张要人的卡上旧形的放行被读成人的放行,绕过「要人的卡不归策略答」那一判)。所以那条口
109
- * 在裁决之前响亮拒它,与同一只 parser 里 `scope` 的拒同一条先例;耐久两口本来就在键闭集 / strict 体上拒它,句子改由同一铸点出。
106
+ * 退役键 `settledBy`(7.93.3–7.117.x 的「只配 deny」那一位)的拒句。决定口共用这一句,出句的铸点是 {@link retiredDecisionKeyFacts}(各口不直接引用本常量)。
107
+ * 这只键不是随便一个未知键:它是调用方在**明确陈述**「这是策略答的」—— 忽略它就是把缺席律(person)套在一个说了话的体上(旧壳的策略拒记成人拒;
108
+ * 一张要人的卡上旧形的放行被读成人的放行,绕过「要人的卡不归策略答」那一判)。各口在键闭集 / strict 体上拒它,句子由同一铸点出
109
+ * (7.151.x 及以前的 live 应答口体不是键闭集的、在裁决之前专门拒它;那条口 7.152.0 起已删)。
110
110
  */
111
111
  export declare const SETTLED_BY_RETIRED = "settledBy is retired \u2014 send decidedBy: \"person\" | \"policy\" (who made this decision; absent = \"person\"); ignoring it would record a policy's answer as a person's";
112
112
  /**
113
- * 退役键 `settledBy` 的**拒绝事实** —— 三条工具审批决定口(live `POST /v1/tool-approvals/:id/respond`、耐久 ask 账
113
+ * 退役键 `settledBy` 的**拒绝事实** —— 两条工具审批决定口(决断口
114
114
  * `POST /v1/tasks/:taskId/asks/:askId/decision`、`POST /v1/approvals/:sessionId/decide`)对它的拒,**句**与**机读位**同出自这一处:
115
115
  * · `error` = {@link SETTLED_BY_RETIRED}(三口同一句,没有哪一口自说一句 —— 此前耐久 ask 账说 strict 体的通用句、`/decide` 说键闭集句);
116
116
  * · `extra` = `{ field: "settledBy" }`,直接作 `sendError` 的 `extra` / 并进 400 体。`field` 是 400 体上既有的那一把键(`request.field_invalid` 的
@@ -152,7 +152,7 @@ export type DeciderReading = {
152
152
  * 决定体决定者两格(`decidedBy` + `decidedVia`)的**唯一读法**。次序即契约:
153
153
  * ① `decidedBy` 缺席 ⇒ `"person"`(缺席律:一条不说话的决定就是一个人按的 —— 与修前逐字同形);
154
154
  * ② 直连门在场且 `decidedBy` 在场 ⇒ `not_in_proof`(不论值:它不在签名载荷里,能改线上字节的一方可以把人翻成策略;
155
- * 第二参给字面 `false` 的调用点 = 那条口没有决策证明,live `/respond` 即此);
155
+ * 各调用点交部署的 `directDoorActive`;7.151.x 及以前的 live 应答口没有决策证明、给字面 `false`,那条口 7.152.0 起已删);
156
156
  * ③ `decidedBy` 闭集外(`"sla_timeout"`、结算词、别的串、非串、`null`)⇒ `outside_closed_set`({@link DECIDED_BY_OUTSIDE_CLOSED_SET});
157
157
  * ④ `decidedVia` 在场(`undefined` 之外一律算在场,`null` 也是 —— 与 `decidedBy` 同一条在场口径)而它不在 core `DECIDED_VIA` 里,或旁边的决定者
158
158
  * 没有座位(人;含 ① 落成的缺席 person ⇒ 直连门上只带 `decidedVia` 也走这一臂,直连门从不受理它)⇒ `outside_closed_set`({@link DECIDED_VIA_OUTSIDE_SEAT});
@@ -176,11 +176,11 @@ export declare function readDecider(body: {
176
176
  export declare function liveHostSource(decider: ApprovalDecider): HostSource | undefined;
177
177
  /**
178
178
  * 引擎自己的那一条例外:**一张要人的卡不归策略答** —— 判官是 core 的 `policyCannotAnswer(question, decidedBy)`([ref] 包根导出;引擎的续跑入口、
179
- * 执行带与同步座读同一条)。本仓**只在自己的副作用先于引擎落地的两条口**上于裁决之前问它(live `/respond`:会话放行 / 常驻规则 / 一条按 approve
180
- * 回放的 DECIDED 行;耐久 ask 账:一条宣称 approve 的 DECIDED 行),并且只问**放行**那一向(与引擎续跑入口同:拒永远答得了)。耐久 `/decide` 不判:
179
+ * 执行带与同步座读同一条)。本仓**只在自己的副作用先于引擎落地的那一条口**上于裁决之前问它(决断口 `POST /v1/tasks/:taskId/asks/:askId/decision`:
180
+ * 会话放行 / 常驻规则 / 一条宣称 approve 的 DECIDED 行;7.151.x 及以前的 live 应答口也问,那条口 7.152.0 起已删),并且只问**放行**那一向(与引擎续跑入口同:拒永远答得了)。耐久 `/decide` 不判:
181
181
  * 引擎在 CAS 之前就拒(`checkpoint.invalid_outcome`,卡留 pending),本口的副作用全在引擎受理之后 —— 在那里再问一次就是第二个判官。
182
182
  *
183
- * 交给判官的「问」= {@link heldAskOf}:本仓两条口持有的都不是引擎的原物(活卡条目记的是铸条目那一次从 `AskRequest` 读定的那一位;耐久 ask 账行上是
183
+ * 交给判官的「问」= {@link heldAskOf}:决断口两形持有的都不是引擎的原物(活卡条目记的是铸条目那一次从 `AskRequest` 读定的那一位;ask 账行上是
184
184
  * 卡面 `risk.requiresRealApproval`,读不出按要人读),以引擎的问形(core `HeldQuestion` 的 `ask` 决定臂)交过去 —— 「谁答不了」只在引擎那一处判。
185
185
  */
186
186
  export declare function heldAskOf(demandsAPerson: boolean): Extract<PermissionResult, {
@@ -15,6 +15,7 @@
15
15
  */
16
16
  import { type GovernancePosture } from "../runtime-governance.js";
17
17
  import type { ShellGateDoctrine } from "@sema-agent/core";
18
+ import { type ParkedRunStatus } from "../plugins/store-contracts.js";
18
19
  import type { RunStore } from "../plugins/store-backend.js";
19
20
  import { type PendingRowBinding } from "../plugins/checkpoint-store-face.js";
20
21
  /** 与 runs.ts/tasks.ts 三个 409 位共享的旧文案(byte-frozen:api-error-text-freeze 门认这句)。 */
@@ -71,11 +72,43 @@ export interface PendingGateMaterial {
71
72
  * 报的是同一行。残余如实记:这一位仍不是**跨 run** 的去重键 —— activeTaskId 换了,门自然也换。 */
72
73
  checkpointId?: string;
73
74
  }
75
+ /**
76
+ * 持有者的状态词:run 状态表判为在跑或停驻的词(在跑 `running` ∪ 停驻词 —— 停驻词从表派生,今天 `suspended` / `needs_review`)。
77
+ * 收场词(完成 / 失败 / 阻断)不在其中:持有者行已收场而认领还在(收尾窗 / 崩溃残留),状态键不写。
78
+ */
79
+ export type OccupantRunStatus = "running" | ParkedRunStatus;
80
+ /**
81
+ * **会话占用两键**(wire):`activeTaskId` = 这只会话的单活认领此刻的持有者(认领已放 ⇒ `null`,键恒在);`activeTaskStatus` = 那条 run 行存着的状态,
82
+ * 在跑 / 停驻才写键({@link OccupantRunStatus})。唯一铸法 = {@link occupantOf};出现面:409 `conflict.session_active_run` 各体(提交 / 续跑 / 删除 / run 外回退)
83
+ * 与 SSE 冲突 done 帧、会话头探针 `GET /v1/sessions/:id/head` 的 200 体 —— 同一时刻两边的两键逐字相等。
84
+ */
85
+ export type SessionOccupant = {
86
+ readonly activeTaskId: string | null;
87
+ readonly activeTaskStatus?: OccupantRunStatus;
88
+ };
89
+ /**
90
+ * 🔴 **占用两键的唯一投影**:认领持有者(任一处读到的那一格 —— 写口认领冲突里观察到的、删除围栏判到的、按会话读的认领)→ {@link SessionOccupant}。
91
+ * 状态 = 持有者那一行(不带属主的一格事实,经属主存取器 `runFactsOf` 读),在跑 / 停驻才写键。没有 run 店 ⇒ 只有持有者。
92
+ * 读店故障原样抛 —— 失败方向归调用方:提交面的 409 体降级成只带持有者({@link buildActiveRunConflict} 的留痕臂),读面响亮(500,不答一个看似诚实的少键体)。
93
+ */
94
+ export declare function occupantOf(runStore: Pick<RunStore, "getRun"> | undefined, holder: string | null | undefined): Promise<SessionOccupant>;
95
+ /**
96
+ * 拒体上的占用两键(409 的失败方向:拒体本身绝不被材料挡住):{@link occupantOf},持有者行读不出 ⇒ 只剩持有者 + F 类留痕(与提交面材料同一只 tag)。
97
+ * 读者:提交 / 续跑面的铸式({@link buildActiveRunConflict})、删除口与 run 外回退口的 409。
98
+ */
99
+ export declare function refusalOccupantOf(runStore: Pick<RunStore, "getRun"> | undefined, holder: string | null | undefined): Promise<SessionOccupant>;
100
+ /**
101
+ * 按会话读的那一读:run 店的单活认领(`getActiveTaskId`,跨副本 = 共享店里的那一格)→ {@link occupantOf}。读者:会话头探针(读面:任一读故障响亮)。
102
+ * 读的是存着的认领,不落死亡判决:心跳过期而还没被收割 / 观察的持有者照它行上存着的状态答(与「其余按认领判的门不判存活」同一条;
103
+ * 写口的认领冲突判官先判死它、所以提交不会因它 409)。
104
+ */
105
+ export declare function readSessionOccupant(runStore: Pick<RunStore, "getActiveTaskId" | "getRun">, sessionId: string): Promise<SessionOccupant>;
74
106
  export interface ActiveRunConflictBody {
75
107
  error: string;
76
108
  errorCode: "conflict.session_active_run";
109
+ /** 占用两键({@link SessionOccupant},唯一投影 {@link occupantOf})。 */
77
110
  activeTaskId: string | null;
78
- activeTaskStatus?: string;
111
+ activeTaskStatus?: OccupantRunStatus;
79
112
  /** [ref] S1([ref]):running 形专属的**活性证据**——本副本 ledger sink 最后一次 durable append 距今
80
113
  * 的毫秒数(「turn 真在推进」的判别材料;与行 updatedAt 的进程心跳语义刻意分离)。**同副本
81
114
  * best-effort**:缺席 = 无法证明(跨副本/重启后),不是「不活」——诚实缺席,绝不铸 0。消费端
@@ -100,7 +133,7 @@ export interface ActiveRunConflictDoneResult {
100
133
  errorCode: "conflict.session_active_run";
101
134
  errorMessage: string;
102
135
  activeTaskId: string | null;
103
- activeTaskStatus?: string;
136
+ activeTaskStatus?: OccupantRunStatus;
104
137
  /** [ref] S1:与 409 body 同键同语义(见 {@link ActiveRunConflictBody.msSinceLastActivity})。 */
105
138
  msSinceLastActivity?: number;
106
139
  pendingGate?: PendingGateMaterial;