@sema-agent/sdk 20.0.3 → 21.0.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 (41) hide show
  1. package/README.md +78 -1
  2. package/dist/errors.d.ts +7 -1
  3. package/dist/errors.d.ts.map +1 -1
  4. package/dist/errors.js +7 -1
  5. package/dist/errors.js.map +1 -1
  6. package/dist/events.d.ts +61 -3
  7. package/dist/events.d.ts.map +1 -1
  8. package/dist/events.js.map +1 -1
  9. package/dist/idempotency.d.ts +4 -0
  10. package/dist/idempotency.d.ts.map +1 -1
  11. package/dist/idempotency.js +4 -0
  12. package/dist/idempotency.js.map +1 -1
  13. package/dist/index.d.ts +5 -2
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +1 -0
  16. package/dist/index.js.map +1 -1
  17. package/dist/resources/approvals.d.ts +6 -3
  18. package/dist/resources/approvals.d.ts.map +1 -1
  19. package/dist/resources/approvals.js +2 -1
  20. package/dist/resources/approvals.js.map +1 -1
  21. package/dist/resources/assistant.d.ts +1 -1
  22. package/dist/resources/assistant.js +1 -1
  23. package/dist/resources/models.d.ts +3 -1
  24. package/dist/resources/models.d.ts.map +1 -1
  25. package/dist/resources/models.js +3 -1
  26. package/dist/resources/models.js.map +1 -1
  27. package/dist/resources/session-sync.d.ts +1 -1
  28. package/dist/resources/tasks.d.ts +7 -1
  29. package/dist/resources/tasks.d.ts.map +1 -1
  30. package/dist/resources/tasks.js +7 -1
  31. package/dist/resources/tasks.js.map +1 -1
  32. package/dist/resources/tool-approvals.d.ts +15 -1
  33. package/dist/resources/tool-approvals.d.ts.map +1 -1
  34. package/dist/resources/tool-approvals.js +8 -0
  35. package/dist/resources/tool-approvals.js.map +1 -1
  36. package/dist/types.d.ts +184 -65
  37. package/dist/types.d.ts.map +1 -1
  38. package/dist/types.js +5 -8
  39. package/dist/types.js.map +1 -1
  40. package/openapi.yaml +264 -57
  41. package/package.json +1 -1
package/dist/types.d.ts CHANGED
@@ -57,29 +57,27 @@
57
57
  * null" may be correct — check for a normalizer at the boundary before widening it to `| null`.
58
58
  */
59
59
  import type { SemaSettings } from "./settings.js";
60
- import type { AllowRuleShadow, AskOrigin, AutoModeFallbackCause, BoundSkillGrants, ClassifierUnavailable, DenialLimitFallback, PersistedRuleMandate, RuleOffer, RuleOffersAbsence, ToolApprovalFrame } from "./resources/tool-approvals.js";
60
+ import type { ApprovalDecidedBy } from "./resources/approvals.js";
61
+ import type { AllowRuleShadow, AskOrigin, AutoModeFallbackCause, BoundSkillGrants, ClassifierUnavailable, DenialLimitFallback, PersistedRuleMandate, RuleOffer, RuleOffersAbsence, ToolApprovalCardWord, ToolApprovalFrame } from "./resources/tool-approvals.js";
61
62
  /** Authenticated end-user identity. Opaque to the service (used as memory scope + session owner). The SDK
62
63
  * normalizes; the service does NOT validate the format. Convention: `user:` / `org:` / `ai:` / `anon:`. */
63
64
  export type Principal = string;
64
65
  /** Builtin scenarios of a stock `@sema-agent/server` that this SDK offers as known names — **four**, all in the table its
65
66
  * `buildScenarios()` returns (`src/capabilities/scenarios.ts`). `code` is the factory default ([891]); `default` is the
66
67
  * domain-neutral assistant face; `scan` is the neutral read-only repo lane; `code-review` is the multi-lens review lane.
67
- * ⚠️ The server's table has ONE more name today, `discuss` (the multi-agent discussion round-table), and it is still
68
- * accepted — it is deliberately NOT listed here: it sits inside core #1056's (7.35.0) retirement sweep (server S-630 ②), and
69
- * listing it now only to delete it at 7.35.0 would be two hard breaking changes on one type surface. Its fate is decided
70
- * by that wave, and this list changes once, then. (`Scenario` is open, so `scenario: "discuss"` compiles today.)
68
+ * ⚠️ Servers ≤7.125.x list ONE more name, `discuss` (the multi-agent discussion round-table); **server 7.126.0 retired it with the whole team-orchestration
69
+ * surface (no alias)** — a 7.126.0+ server answers it 400 `scenario_unknown`. It was never listed here. (`Scenario` is open, so `scenario: "discuss"` still compiles; the 400 is the notice.)
71
70
  * 🔴 CHECKED AGAINST THE SERVER, not hand-kept (K-20): `test/scenario-capabilities.test.ts` ① reads the builtin table out of
72
71
  * the PUBLISHED `@sema-agent/server` bytes (devDep dist; `SEMA_SERVER_SRC=` reads an unpublished checkout) and requires it
73
- * to equal this list plus the one closed, dated hold-out (`SCENARIO_SERVER_ONLY_PENDING` in `test/_keyset-divergence.ts`) —
74
- * a server rename or retirement turns that cell red on the next pin bump.
72
+ * to equal this list — on the pinned-bytes leg plus the closed hold-out the pinned server still lists (`SCENARIO_SERVER_ONLY_PENDING` in
73
+ * `test/_keyset-divergence.ts`, empty on the source leg) — a server rename or retirement turns that cell red on the next pin bump.
75
74
  * 🔴 Three RETIRED names are deliberately NOT here, and none left a transition alias:
76
75
  * - `oa` — server 5.0.0 deleted it whole ([2354]; its `OA_*` env names are now boot-refusing tombstones).
77
76
  * - `autonomous` — retired by [2400] CAPS-OPS-11 (clay 2026-08-03, 不留任何过渡). It used to be `code` with
78
77
  * finalVerification pinned on; final verification is now a pure caller-side knob, so the migration shape is
79
78
  * `scenario:"code"` + `body.finalVerification:true`.
80
79
  * - `team` — renamed `discuss` (server #273 / C-R14), and the old name's alias was withdrawn (#342), so a server
81
- * answers it 400 today. Removed here in K-20. (The discuss scenario's body key `team`, which picks the roster
82
- * template, kept its historical name — that is a request key, not this union.)
80
+ * answers it 400 today. Removed here in K-20.
83
81
  * Sending a retired name to a ≥5.1.0 server is a LOUD typed 400 `scenario_unknown` (the response carries the
84
82
  * deployment's live vocabulary), not a silent fold to `default`. */
85
83
  export declare const KNOWN_SCENARIOS: readonly ["code", "default", "code-review", "scan"];
@@ -226,9 +224,10 @@ export type ApprovalReach = (typeof APPROVAL_REACH)[number];
226
224
  *
227
225
  * 🔴 **顶层键自 server 7.78.1 起是闭集**(硬 BREAKING,零别名;行为面收窄)——`POST /v1/tasks` /
228
226
  * `/v1/tasks/stream` / `/v1/runs` 的**提交腿**上,受理集之外的顶层键 **400 `request.body_shape`**
229
- * (此前是**静默丢**)。受理集 = 本型的**具名**成员 ∪ 场景透传五键(`businessContext` / `lenses` /
230
- * `repo` / `rounds` / `team`;`objective` / `scenario` / `council` / `debate` 本就是具名成员)。
231
- * ⇒ 下面那条 `[k: string]: unknown` **只剩场景透传这一个正当用途**:它不再是「随便挂什么都行」的口。
227
+ * (此前是**静默丢**)。受理集 = 本型的**具名**成员 ∪ 场景透传键(**server ≥7.126.0 只剩 `repo` 一个**;`objective` / `scenario` 本就是具名成员)。
228
+ * 🔴 **server 7.126.0 退出受理集的键(硬 BREAKING,零别名)**:`council` / `debate`(具名提交面键)与 `businessContext` / `lenses` / `rounds` / `team`(场景透传键)—— 团队编排面整个退役(`discuss` 场景、
229
+ * `code-review` 的评审团腿同批删);送它们 ⇒ 400 `request.body_shape` + `unknownKeys`。本包 21.0.0 同删 `council` / `debate` 两个具名成员,不留别名。
230
+ * ⇒ 下面那条 `[k: string]: unknown` **只剩场景透传这一个正当用途**(今天只有 `repo`):它不再是「随便挂什么都行」的口 —— 🔴 它也**不会**替你拦住已退役的键(索引签名让它们仍能编译,拒绝发生在 server 的 400 上)。
232
231
  * 拼错一个具名键(`memoryCaptrue` / `permissionmode`)现在是响亮的 400 而不是「声明从未存在」;
233
232
  * 按引擎 `TaskSpec` 手拼出来的座(`readFace` / `readDenyPatterns` / `writeFace` / `shellGate` /
234
233
  * `handsReadOnly`)同样 400 —— 它们是**部署席/派生席**,从不从请求体进(`writeFace` 的任务层那一位自
@@ -251,13 +250,23 @@ export interface TaskRequest {
251
250
  * nothing re-bills. 🔴 server ≥7.125.0: `Idempotency-Key` is ALSO a unique key on the run row (contract §0.7) — two keys to ONE row; sent together they
252
251
  * must point at the same row, and a key that points at a row this `taskId` does not name is 409 `conflict.run_exists`
253
252
  * (sentence `a run already exists for this submission's taskId or Idempotency-Key`; the code is unchanged, nothing about the row is echoed).
253
+ * 🔴 server ≥7.126.0 (contract §0.7 "same request = same body"): the SAME `Idempotency-Key` carried with a DIFFERENT request body is 409 `conflict.idempotency_payload_mismatch`
254
+ * — not replayed, not created, the row untouched. Body identity = the received JSON body with keys recursively sorted and `taskId` removed (headers never count; a value, a nested
255
+ * value, an extra key or a reordered array is a different request). To retry, resend the SAME body; for a different request use a NEW key. Only the key's own binding is compared
256
+ * (a hit by `taskId` alone, or a row created without a key, is not body-compared).
254
257
  * 🔴 Shape-gated: a non-uuidv7 value is a 400 `request.id_invalid` (the caller cannot inject an arbitrary PK
255
258
  * shape — it is the same alphabet the server mints). Owner-gated replay: a taskId owned by ANOTHER principal
256
259
  * answers 409 `conflict.run_exists`, never that tenant's run (no cross-tenant id oracle).
257
260
  * Omit ⇒ the server mints one. Use `newIdempotencyKey()`-style uniqueness discipline: reusing a taskId
258
261
  * across DIFFERENT work is how you silently get the old run's answer. */
259
262
  taskId?: string;
260
- /** Continue a conversation: pass the same sessionId across turns. Omit on first turn → service mints one. */
263
+ /** Continue a conversation: pass the same sessionId across turns. Omit on first turn → service mints one.
264
+ * 🔴 **server ≥7.126.0 — a caller-supplied session id has ONE shape law on every door: a canonical uuid of ANY version** (lowercase 8-4-4-4-12 hex, version nibble 1–8; a client-preset v4 and the server-minted v7 both pass;
265
+ * contract §0.8) — the same judge the store verbs use (`fork` / `delete` / `policy` / 2c sync). Anything else ⇒ **400 `request.id_invalid`** (branch on the CODE; the sentence is display only and this package never matches it).
266
+ * A self-chosen name (`"myproj"`, a string with spaces) is **not** a session id any more — keep your own name-to-uuid mapping. Also gone: the old "≤ 64 characters" length cap and its `request.field_invalid` refusal.
267
+ * 🔴 **The empty string `""` is no longer "absent"** (it used to mint a fresh session): it is a non-uuid ⇒ 400. To mean "new session" **omit the key**. The check is shape-only (it does not look up whether the session exists;
268
+ * continuing a uuid that does not exist still creates it — use {@link requireExistingSession} to forbid that). A2A `contextId` rides this same key and is judged by the same rule. Existing sessions stored under an old self-chosen
269
+ * id stay readable by their id but can no longer be continued through a submit. */
261
270
  sessionId?: string;
262
271
  /** 🔴 D1 补型(2026-07-29;形自 server `src/http/wire-types.ts` 亲读)—— design/114 Phase3 warm-resume 硬断言:
263
272
  * 要求 `sessionId` **已经存在**。`true` 且会话真的不在(过期/清掉/从未建过)⇒ 这一 run **FAIL LOUD**
@@ -377,18 +386,6 @@ export interface TaskRequest {
377
386
  * 基线冲突时 center/config **赢**(peer 名就是工具命名空间段)。**上限 32 条,超出的条目同样被丢弃并
378
387
  * 具名**(不是 400 —— 与坏形同一条处置)。 */
379
388
  a2aPeers?: A2aServerSpec[];
380
- /** `code-review` 场景的**贵档**(server `src/http/wire-types.ts:86-87` 铸点):`council:true` 把评审
381
- * 扇出成 N 个并行镜头 + 一个仲裁者(`run_council`),而不是 lead 就地评。
382
- * 🔴 在**两条缝**上被读,两条都算数:①场景装配器据它挂 `run_council`
383
- * (`src/capabilities/scenarios.ts:683`);②`src/boot/resolve-spec.ts:940/1555` 把它读成**显式组队声明**
384
- * —— 放宽本任务的墙钟租期预算,并**抑制**价值路由的自动升档。只有字面 `true` 算数(两条缝同判)。
385
- * 非 `code-review` 场景上第①条空转,第②条照旧生效。 */
386
- council?: boolean;
387
- /** 在 council 之上再跑 L2 **同侪辩论**轮。🔴 两条缝**不对称**,别把它当独立开关:
388
- * ①场景装配器只在 `council === true` 的分支里读它(`src/capabilities/scenarios.ts:690`)⇒
389
- * **单独送 `debate:true` 不会有辩论轮**;②`resolve-spec` 的显式组队判据是 `council || debate`
390
- * (`:940/1555`)⇒ 单独送它**仍然**会放宽租期预算并抑制自动升档。同样只有字面 `true` 算数。 */
391
- debate?: boolean;
392
389
  /** 图文输入:`{ data, mimeType }`(内联 base64)或 `{ url }`。
393
390
  * 🔴 **内联臂的准入(server ≥7.117.0 / core 7.42.0)**:`mimeType` 必须是 `image/png` / `image/jpeg` / `image/gif` / `image/webp` 之一(发 API 自己的类型词,不发扩展名),解码后的字节必须带**声明类型**的文件签名,
394
391
  * 解码后不得超 5 MiB —— 过不了 ⇒ 引擎在**第一次模型调用之前**拒(UserPromptSubmit hook 之后,一个模型 token 没烧),**400 `config.image_invalid`**,`error` 以 `TaskSpec.images: ` 起
@@ -786,15 +783,26 @@ export interface TaskRequest {
786
783
  /** server ≥1.221 (core 1.314 工具面控制批,[1052]②): roster TRUE-UNMOUNT list — the named wire tools'
787
784
  * schemas never reach the model (the deny gate saves no tokens; this does), and the assembly manifest
788
785
  * narrows honestly. Tighten-only: core's inheritance invariant unions it into EVERY child spawn path.
789
- * Malformed (non-array / empty-string items) → 400 fail-loud at submit. */
786
+ * Malformed (non-array / empty-string items) → 400 fail-loud at submit.
787
+ * 🔴 **server ≥7.126.0(core 7.49.0 #1623;契约 G.9e)—— 与 {@link allowTools} 读同一文法**:条目 = wire 名或别名、`Tool(content)`(整只工具)、`mcp__srv` / `mcp__srv__*` / 工具段通配;
788
+ * 名单里有一个这一 run **没有任何工具答应**的名字 ⇒ 引擎开跑前拒 `config.tool_face_control`(同步腿 400,一个 token 没烧;流式 / 后台腿是 `failed` 终局带同码),**不再静默忽略那个名字**;
789
+ * `"*"` 在这张名单上也被拒(此前它是一只叫 `*` 的工具;「卸全部」的拼法仍只有 {@link excludeAllTools})。deny 赢:可用工具 = 这一 run 挂的一切 ∩ {@link allowTools} − 本名单。 */
790
790
  excludeTools?: string[];
791
+ /** server ≥7.126.0(core 7.49.0 #1623;契约 G.9e):这一 run 的**可用性选择器**,原样进引擎的 `TaskSpec.allowTools` —— server 零读法:不算补集、不过滤条目、`[]` 不折成缺席、不与 `settings.permissions.allow`
792
+ * (allow 层,免问)混词。可用工具 = 这一 run 挂的一切(调用方工具、手、引擎自己的工具、MCP / A2A、场景与腿工具)∩ 本名单 − {@link excludeTools}(deny 赢),由引擎在开跑前一次算出。
793
+ * 🔴 **读法**:`["*"]` = 本层不设名单(缺席同义);`[]` = 什么都不给;条目 = wire 名或别名、`Tool(content)`(整只工具)、`mcp__srv` / `mcp__srv__*` / 工具段通配(`mcp__*` 在这张名单上被拒)。
794
+ * 腿的协议工具(委派子代的 `ReportBlocked` 等)不需要点名。子代定义的 {@link TaskAgentDefinition.allowTools} / `denyTools` 与本键是**同一只选择器**(三来源同判)。
795
+ * 🔴 **未知名拒跑**:名单里有一个没有任何工具答应的名字 ⇒ `config.tool_face_control`(同步腿 **400**,一个 token 没烧;流式 / 后台腿是 `failed` 终局带同码;子代那一路的同类拒是终局码 `config.agent.unknown_tool`,不是 HTTP 码)。
796
+ * 坏形(非字符串数组)⇒ 400 `request.field_invalid`,与 `excludeTools` / `deferTools` 同一只门。引擎不认该座(装着的引擎 < 7.49.0)⇒ 响亮拒 400 `request.field_invalid` 点名 `allowTools`(不静默丢:丢一只收窄键就是放宽)。
797
+ * 🔴 **探测靠键闭集,没有能力位**:≤7.125.x 对它答 `400 request.body_shape` 并在 `unknownKeys` 里列名。⚠️ 辖域:A2A 入站面(`message/send`)不承载本键。 */
798
+ allowTools?: string[];
791
799
  /** server ≥7.90.0 (core 7.8.0 design/388 的**请求面**;契约 G.9b / 判据 G-40): **整只工具面卸载** ——
792
800
  * 这一 run 里调用方工具、脚手架、手(Bash/Edit/Write…)、MCP、A2A、skills 一个都不挂,模型没有任何
793
801
  * 工具可调,终局必然是**纯文本**。wire 上看得见的样子:`wiring_manifest.tools` 的 `count === 0` 且
794
802
  * `entries` 为空(披露**一次**,一条 leg 一帧),整条流上零 `tool_start` / `tool_end` / `tool_disclosure`。
795
803
  *
796
- * 🔴 **与 {@link excludeTools} 是两种语义,刻意不折叠**:`"*"` 是一个**合法的调用方工具名**,所以
797
- * 「卸全部」不能写成 `excludeTools:["*"]`(那会把「卸全部」与「卸一只叫 `*` 的工具」塌成一件事)。
804
+ * 🔴 **与 {@link excludeTools} 是两种语义,刻意不折叠**:「卸全部」不写成 `excludeTools:["*"]` —— server ≥7.126.0(引擎 7.49.0)起那张名单里的 `*` 本身就被引擎拒
805
+ * (`config.tool_face_control`,同步腿 400;此前它是一只叫 `*` 的调用方工具名,「卸全部」与「卸一只叫 `*` 的工具」曾因此不能塌成一件事)。
798
806
  * 两键**同带各自生效**,不冲突、不拒(全卸之后名单里那几只本来也不在)。
799
807
  * 🔴 **类型只收字面 `true`**:server 只把 literal `true` 写上 `TaskSpec` —— 挂一个 `false` 上去等于
800
808
  * 替引擎重申一次它自己的缺省,而那个缺省的属主是引擎。要动态开关就写
@@ -953,9 +961,11 @@ export interface TaskAgentDefinition {
953
961
  whenToUse?: string;
954
962
  /** Compact variant of `whenToUse` for lean tool listings. ≤4096 chars. */
955
963
  whenToUseLean?: string;
956
- /** Allowlist of tool names the agent may use. Omit ⇒ inherit all tools. */
964
+ /** Allowlist of tool names the agent may use. Omit ⇒ inherit all tools.
965
+ * server ≥7.126.0(core 7.49.0 #1623):名字归引擎一只判 —— 与根 run 的 {@link TaskRequest.allowTools} / {@link TaskRequest.excludeTools} 是同一只选择器(开跑前,三来源同判);
966
+ * 没有任何工具答应的名字 ⇒ 整 run 拒终局码 `config.agent.unknown_tool`(不是 HTTP 码;server 受理口只判形与条数)。 */
957
967
  allowTools?: string[];
958
- /** Denylist of tool names (subtractive; applied after `allowTools`). */
968
+ /** Denylist of tool names (subtractive; applied after `allowTools`). 同上:server ≥7.126.0 起读同一只选择器(`Tool(content)` ⇒ 整只工具;`denyTools:["Monitor"]` ⇒ 子代没有 `Monitor`)。 */
959
969
  denyTools?: string[];
960
970
  /** Skills preloaded into the agent: `{ name, description, content }` (+ optional allowedTools / disallowedTools / files).
961
971
  * server ≥7.116.0:子代技能受理两只清单(`allowedTools` / `disallowedTools`,读法见 {@link SkillSpec.allowedTools};≤7.115.x 是未知键整条拒)。
@@ -1063,15 +1073,10 @@ export type TerminalCause = {
1063
1073
  * 🔴 wire 上它同样**不带 `token`**(与顶层 paused 臂同一条摘除规则);`gate` / `checkpointId` 照常在。
1064
1074
  * 引擎自己组装的失败上恒缺席。 */
1065
1075
  nestedPause?: PausedCause;
1066
- /** server ≥7.110.0(core 7.38.0 提货,S-955):模型服务商**拒绝**导致的失败带过境的结构化细节 ——
1067
- * `{ kind:"provider_rejected", status, code? }`,`status` = 服务商 HTTP 状态(401 / 403 / 429 同样带);消费端判「可改重发」
1068
- * 看 `status`,不要从 `message` 文本里猜。同一只对象过境三面:同步 200 体 / `done.result` / `GET /v1/runs/:id`。
1069
- * 缺席 = 这次失败不是服务商拒绝,或 server <7.110.0。 */
1070
- detail?: {
1071
- kind: "provider_rejected";
1072
- status: number;
1073
- code?: string;
1074
- };
1076
+ /** 失败的**机读账**(server ≥7.110.0 起一臂 `provider_rejected`;**server ≥7.126.0 / core 7.49.0 起是按 `kind` 分臂的闭集联合** {@link TerminalFailureDetail},三臂:
1077
+ * `provider_rejected` · `coded` · `model_output_invalid`)。**按 `detail.kind` 分支,不按 `message` 文本;新成员随 core minor 加入 ⇒ 分支必须留缺省臂**。
1078
+ * 同一只对象过境三面:同步 200 体 / `done.result` / `GET /v1/runs/:id`。缺席 = 这次失败没有可投的机读事实(不是「旧版本」的信号);`provider_rejected` 臂的 `status` 要点见各臂注。 */
1079
+ detail?: TerminalFailureDetail;
1075
1080
  } | {
1076
1081
  kind: "blocked";
1077
1082
  /** 这条 run 为什么没干活(治理判决不是失败)—— 两个来源,由 {@link detail} 分辨:无 `detail` = agent 自己 `ReportBlocked` 的话;
@@ -1081,6 +1086,76 @@ export type TerminalCause = {
1081
1086
  * 在场 ⇔ 就是 hook 挡下提示;缺席 = agent 自己 `ReportBlocked`,或 server <7.113.0。 */
1082
1087
  detail?: TerminalBlockedDetail;
1083
1088
  } | PausedCause;
1089
+ /**
1090
+ * `terminal.failed.detail` —— 失败的机读账(契约 §5.0a;core `TerminalFailureDetail`,server ≥7.126.0 起是**按 `kind` 分臂的闭集联合**,三臂;新成员随 core minor 加入,
1091
+ * **按 `kind` 分支的消费方必须留缺省臂**。server 对不认识的 `kind`(更新的引擎)把整棵 `detail` 的字符串叶过脱敏后照转,不丢不改形)。
1092
+ * · {@link TerminalProviderRejectedDetail} —— 模型服务商用 4xx 拒绝了这次请求(server ≥7.110.0;≥7.126.0 多四键);
1093
+ * · {@link TerminalCodedDetail} —— 带机读码抛出、抛点同时写了结构化 `detail` 的失败(server ≥7.126.0);
1094
+ * · {@link TerminalModelOutputInvalidDetail} —— 模型这一轮的工具调用无法执行而失败(server ≥7.126.0)。
1095
+ * 同一事实在会话读面的 assistant 消息上另有两键(`apiErrorRoute` / `modelOutputInvalid`,`GET /v1/sessions/:id` 的 `messages[]` 逐字转发,本包不为引擎消息型建联合)。
1096
+ */
1097
+ export type TerminalFailureDetail = TerminalProviderRejectedDetail | TerminalCodedDetail | TerminalModelOutputInvalidDetail;
1098
+ /** `provider_rejected` 臂(契约 §5.0a):**只在模型服务商用 4xx 拒绝了这次请求、且这次拒绝就是这条结果的原因时在场**;5xx、建连 / 流式中断、200 体里的带内错误、锁冲突、请求构建守卫、一切非服务商的失败 ⇒ 缺席(缺席不是「旧版本」的信号)。 */
1099
+ export interface TerminalProviderRejectedDetail {
1100
+ kind: "provider_rejected";
1101
+ /** 拒绝的 HTTP 状态(400–499,与 `apiFailure.status` 同值)。401 / 403 / 429 同样带:判「用户可以改了再发」读 `status`(或 `code`),**不是** `detail` 在不在。 */
1102
+ status: number;
1103
+ /** **服务商自己的错误词**(它错误信封里的 `error.code`,否则 `error.type`,如 `invalid_request_error`),服务商没给时缺席;1–128 可见 ASCII 的形状闸,越形整枚缺席。 */
1104
+ code?: string;
1105
+ /** server ≥7.126.0(core 7.49.0 #1454):这次拒绝对账户说了什么 —— 引擎的闭集词(core `PROVIDER_CONDITIONS` 五词:`quota_exhausted`〔停:要人处置或等窗口重置〕/ `throttled` / `overloaded` / `unknown`〔可重试条件、重试预算用尽〕/ `stop_other`〔凭据、模型权限、请求本身〕);
1106
+ * 逐字透传,闭集声明、开集读(带 default 臂)。与重试帧 `status.providerCondition` 是同一份判词的终局读法。缺席 = 宿主自建消息没判。 */
1107
+ providerCondition?: ProviderConditionWord | (string & {});
1108
+ /** server ≥7.126.0:{@link providerCondition} 所据的证据(`unified_header` / `provider_code` / `status`);与它同进同退;开集读。 */
1109
+ providerConditionSource?: BrainProviderConditionSource | (string & {});
1110
+ /** server ≥7.126.0:与 `quota_exhausted` 并排带的「窗口什么时候重置」(终局消息的 `providerResetAtMs`,epoch 毫秒)。 */
1111
+ providerResetAtMs?: number;
1112
+ /** server ≥7.126.0:被拒的那次请求走的**路**(凭据来路的旋钮词 —— 🔐 从不带钥匙值或 URL,见 {@link TerminalRequestRoute})。缺席 = 终局消息没说(第一方 brain 恒说)。 */
1113
+ route?: TerminalRequestRoute;
1114
+ }
1115
+ /** `coded` 臂(server ≥7.126.0):run 抛了一个**带码**的错,而抛点同时写了结构化 `detail`(如检查点错误的 `{ reason }`);`terminal.code` 是同一只错误的码。只在那条错误链上带着至少一个可投成员时在场。 */
1116
+ export interface TerminalCodedDetail {
1117
+ kind: "coded";
1118
+ /** 抛点写的 `detail`,JSON 纯值快照(字符串、有限数、布尔、null、及其数组 / 纯对象;有界;其它种类的成员被略去)。凭据名下的成员是 `"[redacted]"`;每个字符串叶过一遍错误句脱敏(凭据形换成记号,路径保留)。 */
1119
+ detail: {
1120
+ [key: string]: TerminalCodedDetailValue;
1121
+ };
1122
+ }
1123
+ /** {@link TerminalCodedDetail.detail} 的值:JSON 纯值。 */
1124
+ export type TerminalCodedDetailValue = string | number | boolean | null | TerminalCodedDetailValue[] | {
1125
+ [key: string]: TerminalCodedDetailValue;
1126
+ };
1127
+ /** `model_output_invalid` 臂(server ≥7.126.0):模型这一轮的工具调用无法执行而失败。 */
1128
+ export interface TerminalModelOutputInvalidDetail {
1129
+ kind: "model_output_invalid";
1130
+ /** 丢弃成因:`truncated`(调用参数在解析完之前被截断)/ `unnamed`(调用没有工具名)—— 与 `task.tool_turn_incomplete` 通告同词。 */
1131
+ cause: "truncated" | "unnamed";
1132
+ /** 只与 `truncated` 并排:流报告的输出上限事实。 */
1133
+ outputLimit?: {
1134
+ capStop: boolean;
1135
+ outputTokens?: number;
1136
+ capTokens?: number;
1137
+ };
1138
+ }
1139
+ /** `status` 帧 `providerCondition` 的三词(server ≥7.126.0 / core 7.49.0 #1454;core `PROVIDER_CONDITIONS` 的可重试子集 —— 重试帧只带这三词):`throttled`(被限流)· `overloaded`(提供方过载)· `unknown`(判不出,等同缺席,退避)。 */
1140
+ export type BrainProviderCondition = "throttled" | "overloaded" | "unknown";
1141
+ /** `status` 帧 `providerConditionSource` 的三词(server ≥7.126.0 / core 7.49.0 #1454):判词所据的证据 —— `unified_header`(提供方的统一限额响应头)· `provider_code`(提供方错误信封里的错误词)· `status`(仅 HTTP 状态码)。 */
1142
+ export type BrainProviderConditionSource = "unified_header" | "provider_code" | "status";
1143
+ /** 引擎的提供方条件词(core `PROVIDER_CONDITIONS`,server ≥7.126.0 过境):重试帧只带前三词里的 `throttled | overloaded | unknown`({@link BrainProviderCondition}),终局另可带 `quota_exhausted` / `stop_other`。 */
1144
+ export type ProviderConditionWord = BrainProviderCondition | "quota_exhausted" | "stop_other";
1145
+ /**
1146
+ * `TerminalProviderRejectedDetail.route` —— 被拒请求走的路(server ≥7.126.0;core `RequestRoute`)。🔐 词名的是**旋钮**(凭据从哪来、怎么骑、哪个旋钮定的根),从不是钥匙值或 URL。
1147
+ * · `credentialSource` —— `per-model`(为这个模型解出的)/ `deployment-config`(部署构造期兜底)/ `absent`(哪里都没有凭据);
1148
+ * · `carrier` —— 凭据怎么骑:`apiKey` 旋钮或一个带认证的头;恰在 `credentialSource` 为 `absent` 时缺席;
1149
+ * · `carrierBag` —— 带认证的头来自哪只袋:`options` / `model` / `config`;
1150
+ * · `root` —— 哪个旋钮定了请求的根:`model` / `deployment` / `lane-default`。
1151
+ * 闭集声明、开集读(新词随 core 到货)。
1152
+ */
1153
+ export interface TerminalRequestRoute {
1154
+ credentialSource: "per-model" | "deployment-config" | "absent" | (string & {});
1155
+ carrier?: "apiKey" | "header" | (string & {});
1156
+ carrierBag?: "options" | "model" | "config" | (string & {});
1157
+ root: "model" | "deployment" | "lane-default" | (string & {});
1158
+ }
1084
1159
  /**
1085
1160
  * 一次耐久暂停的因由(`TerminalCause` 的 paused 臂)—— 提交了 checkpoint,这条 run 可恢复。
1086
1161
  *
@@ -1119,17 +1194,32 @@ export interface SealedKeyCapability {
1119
1194
  publicKey: string;
1120
1195
  }
1121
1196
  /**
1122
- * `GET /v1/capabilities` 的 `workspaceSync` 段(server ≥7.125.0,契约附录 B.1 / B.1a)—— **恰两键**,与 server `src/workspace-space.ts` 的 `WorkspaceSyncCapability` 逐键同
1123
- * (测试源码腿 / dist 腿对拍;成员闭集登记在契约 B.1a:两键都是「恒在场」成员,随整个对象在场)。
1197
+ * `GET /v1/capabilities` 的 `workspaceSync` 段(server ≥7.125.0,契约附录 B.1 / B.1a;**server ≥7.126.0 起成员各自在场**)—— 四个**全可选**成员,与 server `src/capabilities/composite-members.ts` 的成员表
1198
+ * `workspaceSync: ["persist", "keep", "timeoutMs", "cache"]` 逐键同(测试源码腿 / dist 腿对拍),在场律各有各的设施:
1199
+ * · `persist` / `keep` / `timeoutMs` —— present-iff **快照存储**(k8s 车道 ∧ `MINIO_*` 三键齐;7.125.0 的 `persist` / `keep` 「恒在场、随对象」到 7.126.0 改为 present-iff;`timeoutMs` 7.126.0 起才有 ⇒ **7.125.x 的体只有 `{ persist, keep }`**,`persist` ↔ `keep` 同进同退,`timeoutMs` 在场则另两键必在);
1200
+ * · `cache` —— present-iff **构建缓存卷开着**(k8s 车道 ∧ `WORKSPACE_CACHE=volume`;**与快照存储无关**)。
1201
+ * 整个对象 present-iff 任一成员在场 ⇒ 开了缓存卷而没配快照存储的部署,对象只有 `cache`:**「对象在」不再蕴含 `persist` 在**。
1202
+ * 🔴 **读跨轮保留一律读 `persist === "space"`**(别读「对象在」)。
1124
1203
  */
1125
1204
  export interface WorkspaceSyncCapability {
1126
- /** 运维旋钮 `WORKSPACE_PERSIST` 的有效值,**两词闭集**,🔴 **缺省 `"off"`**(持久化是 opt-in):
1127
- * · `"space"` —— 运维显式开了:工作区按会话住客跨轮保留;
1128
- * · `"off"` —— 快照存储在、但**没开**(缺省,或运维显式关):每轮新建工作区。🔴 **与整个对象缺席不同义**(缺席 = 这台部署根本没有这项设施)。
1129
- * 壳 / 中心只在 `"space"` 时渲「工作文件跨轮保留」。 */
1130
- persist: "space" | "off";
1131
- /** 每个空间(会话住客)保留的快照份数(运维旋钮 `WORKSPACE_SNAPSHOT_KEEP`,整数 `[1, 50]`,缺省 3);超出的旧快照在每次存成功之后删。 */
1132
- keep: number;
1205
+ /** 运维旋钮 `WORKSPACE_PERSIST` 的有效值,**两词闭集**,🔴 **缺省 `"space"`**(server ≥7.126.0;server 7.125.0 的缺省是 `"off"`):
1206
+ * · `"space"` —— 工作区按会话住客跨轮保留(k8s 车道 ∧ 快照存储在场时的缺省);
1207
+ * · `"off"` —— 快照存储在、但运维**显式关了**:每轮新建工作区。🔴 **与整个成员缺席不同义**(缺席 = 这台部署没有快照存储)。
1208
+ * 壳 / 中心只在 `"space"` 时渲「工作文件跨轮保留」。present-iff 快照存储,与 {@link keep} 同进同退(7.125.x 的体也是这一对)。 */
1209
+ persist?: "space" | "off";
1210
+ /** 每个空间(会话住客)保留的快照份数(运维旋钮 `WORKSPACE_SNAPSHOT_KEEP`,整数 `[1, 50]`,缺省 3);超出的旧快照在每次存成功之后删。present-iff 快照存储(同 {@link persist})。 */
1211
+ keep?: number;
1212
+ /** **快照时限**(server ≥7.126.0;运维旋钮 `WORKSPACE_SNAPSHOT_TIMEOUT_MS`,毫秒,整数 `[30000, 3600000]`,缺省 300000):run 末上传与连沙箱时恢复的墙钟上界,也是下一条 run 等上一条存完的最长等待 ——
1213
+ * 壳据此告知用户「快照上界」。present-iff 快照存储(同 {@link persist});**7.125.x 的体没有这一键**,在场则 {@link persist} / {@link keep} 必在。 */
1214
+ timeoutMs?: number;
1215
+ /** **按空间的构建缓存卷**(server ≥7.126.0;`WORKSPACE_CACHE=volume`):每个空间(会话住客)一只构建缓存卷挂在 `mount`(在工作区之外,**不进快照、可丢**),工具缓存(Gradle / Maven / npm / pip / uv / Go;Rust 不盖)经 pod env 指过去;
1216
+ * 某条 run 拿不到卷 ⇒ 那条 run 照起、不挂卷(构建慢,不失败);委派子代 / 后台代理不挂卷。present-iff **构建缓存卷开着**(与快照存储无关)。 */
1217
+ cache?: WorkspaceCacheCapability;
1218
+ }
1219
+ /** `workspaceSync.cache`(server ≥7.126.0):`mount` = 缓存卷在 pod 里的绝对路径(缺省 `/cache`,在工作区之外);`size` = 每只卷请求的容量,k8s quantity 串(缺省 `20Gi`)。 */
1220
+ export interface WorkspaceCacheCapability {
1221
+ mount: string;
1222
+ size: string;
1133
1223
  }
1134
1224
  /**
1135
1225
  * S-173(K-24;server ≥7.104.0)—— 一条**停在门上**的 run 在 `GET /v1/runs/:id` 行上的 `status` 词,也是同步提交撞 park 时
@@ -1538,6 +1628,25 @@ export interface ModelsResponse {
1538
1628
  name?: string;
1539
1629
  };
1540
1630
  droppedEntries?: DroppedEntry[];
1631
+ /** server ≥7.126.0 · **present-iff**:当前生效的配置是因候选判官整拒了最近一份候选而回落的那一份时在场(见 {@link CandidateRejected});缺席不下「无拒」的结论(也可能是更早的 server)。 */
1632
+ candidateRejected?: CandidateRejected;
1633
+ }
1634
+ /**
1635
+ * `GET /v1/models` 顶层 `candidateRejected`(server ≥7.126.0;**additive,present-iff**):**最近一次配置候选被候选判官整拒的结论**。
1636
+ * 候选判官(起服 / 刷新 / 迟到起服同一只)任一域判形失败或 prompts 面坏形 ⇒ 整份候选不收、一个域都不应用,引擎继续用回落的那一份(盘上 LKG / 上一代已采纳的候选 / env);
1637
+ * 此前这件事只在引擎日志里,用户在终端只见 `unknown model "<自配的名>"`。壳 / 管理面据此在拒句里带真因。
1638
+ * · `domains` —— 判官交出的判形失败的**配置域名**(契约包的域键,如 `mcp` / `models` / `prompts`;排序去重)。认不出的词按原样渲。
1639
+ * · `at` —— 本进程判官判下这份候选的时刻(ISO 8601;同一份候选、同一组坏域重判不刷新它)。
1640
+ * · `source` —— 这份候选是哪种配置源读出来的:`"local"` = 本机配置目录,`"remote"` = 中心;壳据此说「改你的配置文件」还是「找管理员」。
1641
+ * · 🔐 **零自由文本**:不带拒因句、不带文件路径、不带版本号(那些只走本机日志)。
1642
+ * · **在场律(一条)**:本键在场 ⇔ 当前生效的配置是因判官整拒了最近一份候选而回落的那一份。后来的候选被判 clean ⇒ 缺席;从没判过拒 / 没有配置管道(纯 env 部署)⇒ 缺席;
1643
+ * dry-run 姿势恒缺席。**不铸 `null` / `[]`**(与恒在场的 `droppedEntries` 不同)。因此**缺席 ≠「配置一定干净」**:消费方只在键**在场**时据它渲真因,缺席时保持原行为。
1644
+ * · 与同一应答的 `models` 是同一次读的两面:键在场 ⇒ 这份 `models` 是回落的那一份(候选里的模型一个都不在)。无独立能力位(端点恒在,键的有无即在场律)。
1645
+ */
1646
+ export interface CandidateRejected {
1647
+ domains: string[];
1648
+ at: string;
1649
+ source: "local" | "remote";
1541
1650
  }
1542
1651
  /** §cost/usage 面板(service `GET /v1/usage`,实测形态已按源审计)—— per-principal 成本配额 + 单任务上限。
1543
1652
  * CLI `/cost` `/usage` 面板 + 门B 用量条据此渲染真数据(取代静态占位)。🔴 owner-scoped:worker 据 request principal 自算。
@@ -2326,6 +2435,7 @@ export interface RunReplayRecord extends RunRecord {
2326
2435
  * **提交在 SSE 已开流之后被拒**时的 `done.result`(`POST /v1/tasks/stream`)—— 状态行已经发出,拒绝只能编码成终帧的三键 `{ status: "failed", errorCode, errorMessage }`
2327
2436
  * (码与句取自 JSON 拒绝体本会带的那一对;server `routes/tasks.ts`)。两个生产者:
2328
2437
  * · **server ≥7.125.0** —— 同键重放只在建行那一刻才被发现(另一副本先落了行),而那条行调用方读不到 / 指向别的 run ⇒ `errorCode: "conflict.run_exists"`(契约 §0.7;该帧同时带 `replay: true`);
2438
+ * **server ≥7.126.0** 再加一个码:同键异体(建行那一刻才撞上、而绑定它的请求体与这次不同)⇒ `errorCode: "conflict.idempotency_payload_mismatch"`(与 `conflict.run_exists` 同一只投影);
2329
2439
  * · device 放置拒(placement 错误体的码与句;此前在型面上没有这一臂)。
2330
2440
  * 不是引擎结果(没有 `taskId` / `stats`),也不是 {@link ActiveRunConflictDoneResult}(那一臂码恒为 `conflict.session_active_run` 且必带 `activeTaskId`)。
2331
2441
  * **按 `errorCode` 分支,句子只给人看。** `replay` 在 `result` 上恒缺席(帧上的 `replay: true` 是另一回事)。
@@ -3598,7 +3708,7 @@ export interface McpToolFace {
3598
3708
  activity?: string;
3599
3709
  summaryParams?: string[];
3600
3710
  resultCards?: string[];
3601
- approvalCard?: "file-edit" | "file-write" | "notebook-edit" | "shell" | "fetch" | "plan" | "question" | "generic" | (string & {});
3711
+ approvalCard?: ToolApprovalCardWord | (string & {});
3602
3712
  };
3603
3713
  ruleFace?: {
3604
3714
  primaryParams?: string[];
@@ -4478,15 +4588,18 @@ export interface Capabilities {
4478
4588
  * 🔴 **每台宿主一份**:保管店在 `<数据根>/sealed-key/`;多副本不共享这个目录时各副本答的公钥不同,对着 A 副本公钥封的密文在
4479
4589
  * B 副本上是 `stale_ciphertext`(逐模型响亮失败)。出路 = 共享保管目录,或走中心形。 */
4480
4590
  sealedKey?: SealedKeyCapability;
4481
- /** **工作区跨轮保留**(server ≥7.125.0;铸点 `routes/capabilities.ts` 的能力对象成员 `workspaceSync`,值 = 能力事实 `workspaceSpace` 的见证 `{ persist, keep }`;契约附录 B.1 / B.1a)——
4591
+ /** **工作区跨轮保留 + 按空间的构建缓存卷**(server ≥7.125.0;铸点 `routes/capabilities.ts` 的能力对象成员 `workspaceSync`;**server ≥7.126.0 起成员各自在场**:`persist` / `keep` / `timeoutMs` = 能力事实 `workspaceSpace` 的见证,
4592
+ * present-iff 快照存储;`cache` = 能力事实 `workspaceCache` 的见证,present-iff 构建缓存卷;对象 present-iff 任一成员在场,见 {@link WorkspaceSyncCapability};契约附录 B.1 / B.1a)——
4482
4593
  * k8s 车道的 `/workspace` 按**会话住客**(会话化身;会话删掉后同一 id 重新登记 = 新空间、从空目录开始)存进对象存储:每条 run 结束把工作区快照进 `<前缀>/<化身>/space/`(这条车道独占的子前缀;停驻挂起快照在它外面、从不被删旧)、
4483
4594
  * 移动 `space/latest` 指针、只留最近 {@link WorkspaceSyncCapability.keep} 份;下一条 run 开始(连上沙箱时)按 `latest` 恢复;本副本读不到会话住客 ⇒ 该 run 既不恢复也不保存(运维行),不按会话 id 兜底。
4484
- * 🔴 **缺省 `off`**(持久化是 opt-in):壳 / 中心只在 `persist:"space"` 时渲「工作文件跨轮保留」。
4485
- * 🔴 **present-iff**(能力面三个逐键例外之一,与 {@link sealedKey} / {@link centerWiring} 同册,契约附录 B.1):设施 = **k8s 车道 ∧ 快照存储**(`MINIO_ENDPOINT` / `MINIO_ACCESS_KEY` / `MINIO_SECRET_KEY` 三键齐)。
4486
- * 缺席是**键不在**,不是 `false` / `null` / `{}`(判 `caps.workspaceSync !== undefined`);缺席有**两种含义、同一个动作**:① 老 server(< 7.125.0,不认识这一位);② 这台部署不是 k8s 车道,或 k8s 车道没配快照存储
4595
+ * 🔴 **`persist` 缺省 `space`**(server ≥7.126.0;7.125.0 缺省 `off`):壳 / 中心只在 `persist:"space"` 时渲「工作文件跨轮保留」(读 `persist`,别读「对象在」)。
4596
+ * 🔴 **present-iff**(能力面三个逐键例外之一,与 {@link sealedKey} / {@link centerWiring} 同册,契约附录 B.1):设施 = **k8s 车道 ∧ 快照存储**(`MINIO_ENDPOINT` / `MINIO_ACCESS_KEY` / `MINIO_SECRET_KEY` 三键齐),
4597
+ * **或** k8s 车道 ∧ 构建缓存卷开着(server ≥7.126.0;只开卷而没配快照存储的部署,对象只有 `cache`)。
4598
+ * 缺席是**键不在**,不是 `false` / `null` / `{}`(判 `caps.workspaceSync !== undefined`);缺席有**两种含义、同一个动作**:① 老 server(< 7.125.0,不认识这一位);② 这台部署不是 k8s 车道,或 k8s 车道既没配快照存储也没开缓存卷
4487
4599
  * (起服一行 `workspace_persist_unavailable` 点名缺键)—— 同一体的 `version` 能分。不论哪种:**别**承诺「上一轮的文件还在」,每条 run 的工作区按空目录对待。
4488
- * `persist:"off"` = 存储在、但没开(缺省,或运维显式关;能力在、今天不保留),**与缺席不同义**。
4489
- * 只盖 `/workspace`(进程 / 内存态不跨轮)。**失败是响亮的**:读 `latest` 或提交标记失败、`latest` 指向的快照对象不在、或恢复中途失败 ⇒ 该 run 连沙箱失败(不静默给空目录,残缺目录不给工具用也不会被快照回去);
4600
+ * `persist:"off"` = 存储在、但运维显式关了(能力在、今天不保留),**与成员缺席不同义**。
4601
+ * 只盖 `/workspace`(进程 / 内存态不跨轮)。**失败是响亮的**:读 `latest` 或提交标记失败、或恢复中途失败(`latest` 指向的快照在、却下载 / 解包 / 超时失败,拒句点名两条出路 —— 调大 `WORKSPACE_SNAPSHOT_TIMEOUT_MS`,或 `WORKSPACE_PERSIST=off` 一轮)⇒ 该 run 连沙箱失败
4602
+ * (不静默给空目录,残缺目录不给工具用也不会被快照回去);**`latest` 指向的快照对象不在**(被桶生命周期规则清走)⇒ server ≥7.126.0 起运维行 + 删掉悬空指针、该 run 从空目录开始(7.125.0 是连沙箱失败);
4490
4603
  * run 末快照失败 ⇒ 舰队终态 `task` 帧带残局键 `workspaceSnapshot: "failed"`({@link import("./resources/fleet.js").FleetTaskRow.workspaceSnapshot}),下一条 run 恢复的是**上一份** `latest`。 */
4491
4604
  workspaceSync?: WorkspaceSyncCapability;
4492
4605
  /** **会话后台任务两口的在场位**(server ≥7.102.0 / S-745 / core 7.32.0 #1107;铸点 `routes/capabilities.ts:308` =
@@ -4769,11 +4882,10 @@ export interface LivePendingRow {
4769
4882
  /** S-52 C2(server ≥7.52,A-075.87)—— 子代 taskId(= core runSourceTaskId,uuid):把这行 ask 关联到
4770
4883
  * 发起它的子代 run 行。与 `fromSubagent` 恒同生同缺(server `listLivePending` 单条件 spread 铸两键)。 */
4771
4884
  originTaskId?: string;
4772
- /** S-62(server ≥7.6x;铸点 `tool-approval.ts` 的 `listLivePending` 条件 spread,词属主
4773
- * `approval-content-kind.ts`)—— **内容问句分型**:被门的工具是 AskUserQuestion 时为 `"content_ask"`。
4774
- * 与 durable 两读面 / core summarize 面**同一个词**。缺席 = 普通工具 ask。
4775
- * ⚠️ 展示/分诊分型用,**永不参与决议路由**(决议口仍是 respond)。 */
4776
- contentKind?: "content_ask" | (string & {});
4885
+ /** server ≥7.126.0(core 7.49.0 #1414;铸点 `tool-approval.ts` 的 `listLivePending` 条件 spread,读帧上同名那一格)—— **这一问渲在哪张卡上**:引擎铸的卡词({@link ToolApprovalCardWord} 八词),
4886
+ * 与活卡帧 {@link import("./resources/tool-approvals.js").ToolApprovalFrame.approvalCard} **同一个值**(行读帧上那一格,不另读一遍),与运维队列行 {@link PendingCheckpoint.approvalCard} 同层同形。
4887
+ * 取代 ≤7.125.x 的 `contentKind`(server 按工具名回推的第二个卡词,7.126.0 删、零别名)。缺席 = 引擎没铸(宿主自建 ask / 老引擎);展示 / 分诊用,**永不参与决议路由**(决议口仍是 respond)。 */
4888
+ approvalCard?: ToolApprovalCardWord;
4777
4889
  /**
4778
4890
  * 🔴 **这只 ask 本来会 emit 的那只活卡帧**(server ≥7.87.0 / S-454 P1;cli L-397)。
4779
4891
  *
@@ -4883,6 +4995,10 @@ export interface PendingCheckpoint {
4883
4995
  * 经 `readClosedWordSeat(…, "origin")` = core `isAskOrigin` 筛)。与活卡帧 / inbox 行同名同义同值;缺席 = 老行
4884
4996
  * (core 7.5.0 之前 park 的)/ 集外词,**不是** `"policy"`。按开集读(见 {@link AskOrigin})。 */
4885
4997
  origin?: AskOrigin;
4998
+ /** server ≥7.126.0(core 7.49.0 #1414)—— **这一行渲在哪张卡上**:门上引擎铸的 `gate.approvalCard`(闭集 {@link ToolApprovalCardWord} 八词;park 行孪生座读 core `summarizeCheckpoint` 投给 `CheckpointSummary.approvalCard` 的同一个词,集外词读作缺席并计数),
4999
+ * 与活卡帧 / `livePending` 行同名同义。取代 ≤7.125.x 的 `contentKind`(7.126.0 删、零别名)。**缺席 = 引擎没铸**:7.49.0 之前 park 的存量行(core 不从工具名回推,**无卡 = 不是一问** —— 旧问答行在队列上不带卡词,到期被 SLA 拒扫)/ 非审批门 /
5000
+ * 老引擎。展示 / 分诊用,**永不参与 resume / gate / CAS**;`/v1/assistant/inbox` 行不带。 */
5001
+ approvalCard?: ToolApprovalCardWord;
4886
5002
  /** server ≥7.100.0(S-700)—— park 行上的 `ruleOffers` 缺席因由(与活卡帧 / `card_json` 同一只窄读、同一个闭三词集)。
4887
5003
  * 读法见 {@link import("./resources/tool-approvals.js").RuleOffersAbsence}。 */
4888
5004
  ruleOffersAbsence?: RuleOffersAbsence;
@@ -5798,10 +5914,6 @@ export interface CheckpointSummary {
5798
5914
  scope: string;
5799
5915
  /** 哪种暂停(6-arm 开集)。开放联合留 `(string & {})` 容未来新 arm。 */
5800
5916
  gateKind: "human" | "irreversible_ask" | "resource_limit" | "needs_review" | "plan_review" | "task_done" | (string & {});
5801
- /** MF-14 contentKind passthrough(@sema-agent/server 1.6.0 / core 1.150 checkpoint-store.d.ts:765)—— `needs_review`/
5802
- * `suspended` gate 上 core 透传的内容类型;`"content_ask"` = 被 gate 的工具是 AskUserQuestion(让 shell 渲染问答式 UI
5803
- * 而非普通审批)。开放联合容未来新 kind。缺省 = 普通 gate。 */
5804
- contentKind?: "content_ask" | (string & {});
5805
5917
  /** 确定性风险层 = inbox 排序键。**仅 human/irreversible_ask 有**; 其余无 → 排序须容 undefined。 */
5806
5918
  severity?: 1 | 2 | 3 | 4 | 5;
5807
5919
  /** suspend 链上累计花费(资源账本附着时出现)。 */
@@ -5829,7 +5941,7 @@ export interface CheckpointSummary {
5829
5941
  * 🔴 收窄留档(2026-07-30,黑板 [2027]→[2029]→server 3.4.0):本类型曾 `extends Omit<CheckpointSummary,"token">`
5830
5942
  * 并额外声明 toolName/toolCallId/boundCallId/boundInputHash —— 其中 decide 两绑定在 inbox wire 上**从未
5831
5943
  * 出现过**(它们只住 `/v1/approvals` 富行,声明属虚增);其余富行键(toolName/toolCallId/preview/principal/
5832
- * sourceTaskId/contentKind)在 server <3.4.0 因 handler 整行展开而真在 wire 上、但四客户端仓结构性零消费
5944
+ * sourceTaskId 等)在 server <3.4.0 因 handler 整行展开而真在 wire 上、但四客户端仓结构性零消费
5833
5945
  * ([2029] 取证),server 3.4.0 收成显式投影后 wire 上不再出现。按「老的直接删」纪律本类型同步收窄——
5834
5946
  * 一个仍读 `row.toolName` 的消费端会在编译期看见,而不是运行时拿 undefined。
5835
5947
  * 要工具面/decide 绑定 → 用 `/v1/approvals`(`PendingCheckpoint`);要任务归因 → `/v1/assistant/tasks`。
@@ -6008,6 +6120,13 @@ export interface PlanReviewRequest {
6008
6120
  * ⚠️ 键名定谳 `permissionModeAfter`(任务书曾写 `nextPermissionMode`,从未上过发布版,**零别名**)。
6009
6121
  */
6010
6122
  permissionModeAfter?: "default" | "acceptEdits";
6123
+ /**
6124
+ * 🔴 **决定体的出处位**(server ≥7.126.0 起 `plan_review` 同收;引擎 7.49.0 给计划审阅的结局加了必填的决策事实位,与工具审批同一只座)—— 这个决定**是谁做的**:`"person"` / `"policy"`,闭集见 {@link ApprovalDecidedBy},
6125
+ * 与三条工具审批决定口(live `respond`、耐久 ask 账、耐久 `decide`)**同一只读法、同一句拒**:缺席 ⇒ `person`;`policy` 照收;闭集外(含 `"sla_timeout"` —— 只有服务端自己的截止扫说得出)⇒ 400 `request.field_invalid`;
6126
+ * 直连门(D-G)部署上带它(不论值)⇒ 400 `decided_by_not_in_proof`(不在决策证明的签名载荷里);归属 = 本门验过的主体。**回体不回显**。结算记录的出处词是 `plan_review`(`AskOrigin` 新词)。
6127
+ * 🔴 **没有能力位可探,按 server 版本发**:`capabilities().approvalDecidedBy`(≥7.118.0)**不覆盖这一口** —— ≤7.125.x 的 `plan_review` 对它答 `400 request.body_shape` 并在 `unsupportedKeys` 里列名;缺席时照老形发(不带这只键)。
6128
+ */
6129
+ decidedBy?: ApprovalDecidedBy;
6011
6130
  }
6012
6131
  /** §4b/§4c/§4d 决策端点的返回。status 形如 "completed"|"failed"|"suspended"|"needs_review"|"preempting"|…
6013
6132
  * —— 开放串, 不窄化。🔴 facade 审计(2026-07-24,SDK 全量核查批次②-9):此前只声明 `{status}` 一个字段,