@sema-agent/sdk 6.8.0 → 6.9.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.
- package/README.md +84 -22
- package/dist/client.d.ts +1 -1
- package/dist/client.js +1 -1
- package/dist/errors.d.ts +22 -8
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +38 -19
- package/dist/errors.js.map +1 -1
- package/dist/events.d.ts +130 -23
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/resources/assistant.d.ts +1 -1
- package/dist/resources/elicitations.d.ts +14 -4
- package/dist/resources/elicitations.d.ts.map +1 -1
- package/dist/resources/elicitations.js.map +1 -1
- package/dist/resources/questions.d.ts +34 -9
- package/dist/resources/questions.d.ts.map +1 -1
- package/dist/resources/questions.js.map +1 -1
- package/dist/resources/tool-approvals.d.ts +93 -18
- package/dist/resources/tool-approvals.d.ts.map +1 -1
- package/dist/resources/tool-approvals.js +12 -3
- package/dist/resources/tool-approvals.js.map +1 -1
- package/dist/resources/workflows.d.ts +1 -1
- package/dist/resources/workflows.js +1 -1
- package/dist/types.d.ts +115 -48
- package/dist/types.d.ts.map +1 -1
- package/openapi.yaml +436 -230
- package/package.json +1 -1
package/openapi.yaml
CHANGED
|
@@ -56,8 +56,17 @@ openapi: 3.1.0
|
|
|
56
56
|
# live — implemented & verified server-side; in the contract-test assertion set.
|
|
57
57
|
# draft — verb exists but the response shape is not fully pinned; co-design pending (do not over-assert).
|
|
58
58
|
# planned — NOT yet implemented server-side; documented for SDK/producer alignment; EXCLUDED from
|
|
59
|
-
# contract-test assertions until it ships.
|
|
60
|
-
#
|
|
59
|
+
# contract-test assertions until it ships. ⚠️ It is a claim about the SERVER, and it EXPIRES:
|
|
60
|
+
# once the face ships, move it to `live`/`gated` the same day. Two gates now police that —
|
|
61
|
+
# `spec-path-drift-gate` (planned ∩ paths the SDK actually calls must be empty) and
|
|
62
|
+
# `test/live/route-existence.test.ts` (a planned path must have NO handler in the pinned
|
|
63
|
+
# server artifact). Both exist because `POST /v1/tasks/{taskId}/asks/{askId}/decision` kept
|
|
64
|
+
# this label for two server releases after it went live.
|
|
65
|
+
# gated — implemented but off by a server deploy flag (e.g. leader, STREAM_APPROVAL_ENABLED); answers
|
|
66
|
+
# 501 where the flag/deps are unmet. Says nothing about the flag's DEFAULT — that can differ
|
|
67
|
+
# per server version, so read the matching `capabilities` bit, never this label.
|
|
68
|
+
# retired — the face was DELETED server-side; the entry is a tombstone kept so consumers generated from
|
|
69
|
+
# an older spec can find out where it went. No deployment serves it.
|
|
61
70
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
62
71
|
|
|
63
72
|
info:
|
|
@@ -907,7 +916,7 @@ paths:
|
|
|
907
916
|
responses:
|
|
908
917
|
'200':
|
|
909
918
|
# 🔴 census 批2 第三段(2026-07-30)spec 谎修正:这条 200 此前只有一句 description、**零 content
|
|
910
|
-
# 声明**(机器视角=「无 body」),而 server 真发 JSON(`routes/runs.ts
|
|
919
|
+
# 声明**(机器视角=「无 body」),而 server 真发 JSON(`routes/runs.ts`,与 output 面同一个
|
|
911
920
|
# sendJson,含 g14 的条件 `cursorSemantics`)。补接同一个 schema。
|
|
912
921
|
description: 'Stopped — same projection shape as the output verb.'
|
|
913
922
|
content:
|
|
@@ -1077,8 +1086,8 @@ paths:
|
|
|
1077
1086
|
schema:
|
|
1078
1087
|
type: object
|
|
1079
1088
|
# 封闭(census 批2 第二段):三个 200 铸造点都是单键字面量 —— `{deleted:false}` 两处
|
|
1080
|
-
# (未知会话 / 外租户,`routes/sessions.ts
|
|
1081
|
-
# (`http/server.ts
|
|
1089
|
+
# (未知会话 / 外租户,`routes/sessions.ts`)+ purgeSession 的 `{deleted}` 返回
|
|
1090
|
+
# (`http/server.ts` 的签名就是这一个键;它的另一臂 `{active}` 走 409)。
|
|
1082
1091
|
additionalProperties: false
|
|
1083
1092
|
required: [deleted]
|
|
1084
1093
|
properties:
|
|
@@ -1115,7 +1124,7 @@ paths:
|
|
|
1115
1124
|
application/json:
|
|
1116
1125
|
schema:
|
|
1117
1126
|
type: object
|
|
1118
|
-
# 封闭:铸造点 `routes/sessions.ts
|
|
1127
|
+
# 封闭:铸造点 `routes/sessions.ts` 是单键字面量 `{ sessionId: newId }`。
|
|
1119
1128
|
additionalProperties: false
|
|
1120
1129
|
required: [sessionId]
|
|
1121
1130
|
properties:
|
|
@@ -1157,7 +1166,7 @@ paths:
|
|
|
1157
1166
|
application/json:
|
|
1158
1167
|
schema:
|
|
1159
1168
|
type: object
|
|
1160
|
-
# 封闭:铸造点 `routes/sessions.ts
|
|
1169
|
+
# 封闭:铸造点 `routes/sessions.ts` 是两键字面量;版本号本身走 ETag 响应头,不进体。
|
|
1161
1170
|
additionalProperties: false
|
|
1162
1171
|
required: [sessionId, leafId]
|
|
1163
1172
|
properties:
|
|
@@ -1295,7 +1304,7 @@ paths:
|
|
|
1295
1304
|
description: Delivered onto the live stream.
|
|
1296
1305
|
content:
|
|
1297
1306
|
application/json:
|
|
1298
|
-
# 封闭(census 批2 第三段,2026-07-30):live 臂铸造点 `routes/notify-wake.ts
|
|
1307
|
+
# 封闭(census 批2 第三段,2026-07-30):live 臂铸造点 `routes/notify-wake.ts` 是两键字面量。
|
|
1299
1308
|
# 4.3.0:形提成具名 `SessionNotifyResult` 的 live 臂(SDK 同批给了判别联合返回型)。
|
|
1300
1309
|
schema:
|
|
1301
1310
|
type: object
|
|
@@ -1308,7 +1317,7 @@ paths:
|
|
|
1308
1317
|
description: No live stream — parked in the session inbox, drained on the next stream open.
|
|
1309
1318
|
content:
|
|
1310
1319
|
application/json:
|
|
1311
|
-
# 封闭 + note 补 required:parked 臂铸造点 `routes/notify-wake.ts
|
|
1320
|
+
# 封闭 + note 补 required:parked 臂铸造点 `routes/notify-wake.ts` 是三键字面量,note 无条件。
|
|
1312
1321
|
schema:
|
|
1313
1322
|
type: object
|
|
1314
1323
|
additionalProperties: false
|
|
@@ -1352,7 +1361,7 @@ paths:
|
|
|
1352
1361
|
responses:
|
|
1353
1362
|
'200':
|
|
1354
1363
|
# 🔴 census 批2 第三段(2026-07-30)spec 谎修正:此前这里写的是 **202** + required [taskId,…]。
|
|
1355
|
-
# 亲读真码:wake 的成功腿是 `driveResumeIntoRunLog` 的返回(`server.ts
|
|
1364
|
+
# 亲读真码:wake 的成功腿是 `driveResumeIntoRunLog` 的返回(`server.ts`,成功腿与取消臂两处铸造点),
|
|
1356
1365
|
# **恒为 200**(wake 是同步驱动到终局/再挂起,不是 accepted 回执),且 `taskId` 有条件
|
|
1357
1366
|
# (无活跃行即省略——ApprovalDecisionResult 同一铸造点的同一注)。旧 202+required taskId 双谎。
|
|
1358
1367
|
description: Woken — the resumed leg ran to its next settle (terminal, re-suspended, or needs_review).
|
|
@@ -1405,8 +1414,7 @@ paths:
|
|
|
1405
1414
|
description: The snapshot listing.
|
|
1406
1415
|
content:
|
|
1407
1416
|
application/json:
|
|
1408
|
-
# 封闭两层(census 批2 第三段,2026-07-30):铸造点 `routes/sessions.ts
|
|
1409
|
-
# `:620`(行)。条件键=信封 `latest`(零快照即省略)、行 `bytes`(blobSizes 面缺席=诚实省略)。
|
|
1417
|
+
# 封闭两层(census 批2 第三段,2026-07-30):铸造点 `routes/sessions.ts`(信封与行两处)。条件键=信封 `latest`(零快照即省略)、行 `bytes`(blobSizes 面缺席=诚实省略)。
|
|
1410
1418
|
# 4.3.0:形提成具名 `WorkspaceSnapshotPage`(SDK 同批把返回位的内联字面量也提成了 exported type,
|
|
1411
1419
|
# 让 spec-resource-schema-gate 罩得住 —— CAPS-OPS-8)。
|
|
1412
1420
|
schema: { $ref: '#/components/schemas/WorkspaceSnapshotPage' }
|
|
@@ -1450,8 +1458,7 @@ paths:
|
|
|
1450
1458
|
description: One page of the tree.
|
|
1451
1459
|
content:
|
|
1452
1460
|
application/json:
|
|
1453
|
-
# 封闭两层(census 批2 第三段,2026-07-30):铸造点 `routes/sessions.ts
|
|
1454
|
-
# `:654`(行)。条件键=信封 `nextOffset`(尾页省略)、行 `size`(blobSizes 面缺席省略)。
|
|
1461
|
+
# 封闭两层(census 批2 第三段,2026-07-30):铸造点 `routes/sessions.ts`(信封与行两处)。条件键=信封 `nextOffset`(尾页省略)、行 `size`(blobSizes 面缺席省略)。
|
|
1455
1462
|
# 4.3.0:形提成具名 `WorkspaceTreePage`(理由同 list 腿 —— CAPS-OPS-8)。
|
|
1456
1463
|
schema: { $ref: '#/components/schemas/WorkspaceTreePage' }
|
|
1457
1464
|
'400': { $ref: '#/components/responses/BadRequest' }
|
|
@@ -1571,7 +1578,7 @@ paths:
|
|
|
1571
1578
|
application/json:
|
|
1572
1579
|
schema:
|
|
1573
1580
|
type: object
|
|
1574
|
-
# 封闭:铸造点 `routes/sessions.ts
|
|
1581
|
+
# 封闭:铸造点 `routes/sessions.ts` 是单键字面量。BC-3 保证 `rules` 恒非 null
|
|
1575
1582
|
# (无策略的已属会话回 `{rev:0}` 空记录,绝不回 `{rules:null}`)。
|
|
1576
1583
|
additionalProperties: false
|
|
1577
1584
|
required: [rules]
|
|
@@ -1612,7 +1619,7 @@ paths:
|
|
|
1612
1619
|
application/json:
|
|
1613
1620
|
schema:
|
|
1614
1621
|
type: object
|
|
1615
|
-
# 封闭:铸造点 `routes/sessions.ts
|
|
1622
|
+
# 封闭:铸造点 `routes/sessions.ts` 是单键字面量 `{ rules: stored }`。
|
|
1616
1623
|
additionalProperties: false
|
|
1617
1624
|
required: [rules]
|
|
1618
1625
|
properties:
|
|
@@ -1656,8 +1663,11 @@ paths:
|
|
|
1656
1663
|
|
|
1657
1664
|
# ── 2c session-sync (P1d) — the cloud as a SYNC PEER ──────────────────────────────────────────────────────────
|
|
1658
1665
|
# The local shell's local backend ⇄ this cloud service. PULL a session's whole state out, or PUSH the local
|
|
1659
|
-
# peer's in. Gate the whole surface off `capabilities.sessionSync`
|
|
1660
|
-
# file-snapshot store).
|
|
1666
|
+
# peer's in. Gate the whole surface off `capabilities.sessionSync` — a FOUR-way conjunction (durable backend
|
|
1667
|
+
# AND entry export AND import STAGING AND a file-snapshot store). The staging conjunct is not decorative: a
|
|
1668
|
+
# three-conjunct predicate was disproven in the field ([2024]) when a warm-cache wrapper store forwarded the
|
|
1669
|
+
# other three and dropped the staging family, so caps said true while PUSH Phase A 501'd forever.
|
|
1670
|
+
# Owner-gated like fork/delete (§9): a PULL 404s a non-owner; a PUSH is own-or-FRESH.
|
|
1661
1671
|
/v1/sessions/{sessionId}/sync/manifest:
|
|
1662
1672
|
parameters:
|
|
1663
1673
|
- $ref: '#/components/parameters/PrincipalHeader'
|
|
@@ -1675,7 +1685,7 @@ paths:
|
|
|
1675
1685
|
`/sync/entries`) + per-snapshot relPath→blobHash + policy + anchors + leaf. The local peer feeds `entryIds`
|
|
1676
1686
|
to the §7 classifier to decide fast-forward/fork BEFORE pulling the entry stream + only the blob hashes it
|
|
1677
1687
|
lacks. Owner-scoped (non-owner → 404, no oracle); 400 on an id that is not uuid-SHAPED — 🔴 the sync family's
|
|
1678
|
-
gate is `isUuidShape` (ANY uuid version), NOT `isUuidV7`: server `routes/session-sync.ts
|
|
1688
|
+
gate is `isUuidShape` (ANY uuid version), NOT `isUuidV7`: server `routes/session-sync.ts` deliberately
|
|
1679
1689
|
keeps a v4-keyed legacy shell session pushable (it was creatable via the lenient submit face), while
|
|
1680
1690
|
crafted-id classes stay shut out. `fork`/`delete`/`policy` DO use `isUuidV7` — only this family is lenient;
|
|
1681
1691
|
501 without a durable session store.
|
|
@@ -1686,7 +1696,7 @@ paths:
|
|
|
1686
1696
|
application/json:
|
|
1687
1697
|
schema:
|
|
1688
1698
|
type: object
|
|
1689
|
-
# 封闭(census 批2 第三段,2026-07-30):铸造点 `routes/session-sync.ts
|
|
1699
|
+
# 封闭(census 批2 第三段,2026-07-30):铸造点 `routes/session-sync.ts` 是单键字面量。
|
|
1690
1700
|
additionalProperties: false
|
|
1691
1701
|
required: [manifest]
|
|
1692
1702
|
properties:
|
|
@@ -1889,7 +1899,7 @@ paths:
|
|
|
1889
1899
|
description: >
|
|
1890
1900
|
🔴 OPTIONAL content digest of the SOURCE's whole entry log (core `sessionLogDigest`, scheme
|
|
1891
1901
|
`sema-log-v3`; this leg's core floor is ^1.416.0). Server producer/consumer:
|
|
1892
|
-
`routes/session-sync.ts
|
|
1902
|
+
`routes/session-sync.ts`. This is THE key that makes `ImportStaged.payloadVerified:true`
|
|
1893
1903
|
reachable — until 4.3.0 the response schema promised a `payloadVerified`/`entry-ids+digest` pair
|
|
1894
1904
|
that the request side had no way to trigger. Rationale: `identical` is classified from entry-id
|
|
1895
1905
|
SETS only, and an entry id is a uuidv7 (NOT content-addressed), so "same ids, different payloads"
|
|
@@ -2086,7 +2096,7 @@ paths:
|
|
|
2086
2096
|
Owner-gate / unknown session (no existence oracle), OR — [2400] CB-2, declared 2026-08-02 — the core
|
|
2087
2097
|
code `checkpoint.not_found`: the pending checkpoint this decide addressed is gone. It is the ONE
|
|
2088
2098
|
member of the mirrored `checkpoint.*` family the server sends as a 404 rather than a 409
|
|
2089
|
-
(`src/http/server.ts
|
|
2099
|
+
(`src/http/server.ts`: `e.code === "checkpoint.not_found" ? 404 : 409`), so the SDK maps it to
|
|
2090
2100
|
NotFoundError while the rest of the family maps to ConflictError. Client action: refetch the inbox —
|
|
2091
2101
|
do not retry this decide.
|
|
2092
2102
|
content:
|
|
@@ -2101,14 +2111,14 @@ paths:
|
|
|
2101
2111
|
ConflictError vs ApprovalBindingMismatchError. binding_mismatch = SAFETY signal: refetch + re-present
|
|
2102
2112
|
to the human, NEVER auto-retry.
|
|
2103
2113
|
FOURTH member ([2400] CB-2, declared 2026-08-02): `gate_not_tool_approval` — the suspension this
|
|
2104
|
-
sessionId is parked on is NOT a tool-approval gate (`src/http/server.ts
|
|
2114
|
+
sessionId is parked on is NOT a tool-approval gate (`src/http/server.ts` rejects pre-CAS when the
|
|
2105
2115
|
gate kind is neither `human` nor `irreversible_ask`: nothing is consumed, no model leg burns). It is
|
|
2106
2116
|
the THIRD member of the wrong-door guard family alongside `gate_not_resumable` (§4b) and
|
|
2107
2117
|
`gate_not_plan_review` (§4c) → SDK `GateNotToolApprovalError`. Client action: route by the row's
|
|
2108
2118
|
`gateKind` — `plan_review` → `POST /v1/assistant/tasks/{taskId}/plan_review`, `resource_limit` →
|
|
2109
2119
|
`POST /v1/assistant/tasks/{taskId}/resume`. Retrying the same body never succeeds.
|
|
2110
2120
|
FIFTH group ([2400] CB-2): the core `checkpoint.*` family the server mirrors verbatim
|
|
2111
|
-
(`src/http/server.ts
|
|
2121
|
+
(`src/http/server.ts`) — `checkpoint.gate_mismatch` / `checkpoint.reopen_failed` /
|
|
2112
2122
|
`checkpoint.reopen_revote` / `checkpoint.already_exists` / `checkpoint.resume_aborted` /
|
|
2113
2123
|
`checkpoint.unsupported_version` all arrive as 409 and fall on the SDK's `checkpoint.` PREFIX family
|
|
2114
2124
|
(→ ConflictError, `.errorCode` carried verbatim; an OPEN set, so a future core code degrades with
|
|
@@ -2246,7 +2256,7 @@ paths:
|
|
|
2246
2256
|
application/json:
|
|
2247
2257
|
schema:
|
|
2248
2258
|
type: object
|
|
2249
|
-
# 封闭:铸造点 `routes/approvals-assistant.ts
|
|
2259
|
+
# 封闭:铸造点 `routes/approvals-assistant.ts` 的 200 臂是单键字面量
|
|
2250
2260
|
# `{ revoked: true }`(404 臂是另一个字面量,走 NotFound 信封)。
|
|
2251
2261
|
additionalProperties: false
|
|
2252
2262
|
required: [revoked]
|
|
@@ -2475,7 +2485,7 @@ paths:
|
|
|
2475
2485
|
application/json:
|
|
2476
2486
|
schema:
|
|
2477
2487
|
type: object
|
|
2478
|
-
# 🔴 封闭 + 两处 spec 谎修正(census 批2 第三段,2026-07-30),铸造点 `routes/trace-usage.ts
|
|
2488
|
+
# 🔴 封闭 + 两处 spec 谎修正(census 批2 第三段,2026-07-30),铸造点 `routes/trace-usage.ts`:
|
|
2479
2489
|
# ① 顶层信封 server 真发 `{sinceSec, rows}` —— `sinceSec`(生效的窗口秒数,默认 86400)
|
|
2480
2490
|
# 此前整键不在 spec 里;
|
|
2481
2491
|
# ② 行 `source` 三个 store 实现(sql/pg/local 的 sourceSummary)签名都是 `string | null`
|
|
@@ -2495,7 +2505,7 @@ paths:
|
|
|
2495
2505
|
status: { type: string }
|
|
2496
2506
|
count: { type: integer }
|
|
2497
2507
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
2498
|
-
'501': { $ref: '#/components/responses/NotImplemented' } # 无 durable run store(capability.run_store_required)——`routes/trace-usage.ts
|
|
2508
|
+
'501': { $ref: '#/components/responses/NotImplemented' } # 无 durable run store(capability.run_store_required)——`routes/trace-usage.ts`,此前漏登记
|
|
2499
2509
|
|
|
2500
2510
|
/v1/tasks/{taskId}/artifacts:
|
|
2501
2511
|
parameters:
|
|
@@ -2536,7 +2546,7 @@ paths:
|
|
|
2536
2546
|
# 🔴 修正(2026-07-25):此处原先 $ref 到 `AgentEvent`,是真错 —— 而且本文件自己就矛盾:专门为这条路写的
|
|
2537
2547
|
# `TraceStreamEvent` schema 的描述里明写「A DISTINCT vocabulary from AgentEvent」,却没有任何地方引用它
|
|
2538
2548
|
# (它是本文件里的一个孤儿 schema)。按 server 真码两侧取证后确定 TraceStreamEvent 才是对的:
|
|
2539
|
-
# `streamTaskTrace` 每帧走 `mapTraceEvent`(`trace/project.ts
|
|
2549
|
+
# `streamTaskTrace` 每帧走 `mapTraceEvent`(`trace/project.ts`),发的是 SSE **event 名**
|
|
2540
2550
|
# `block-thinking-delta` / `block-content-delta` / `tool-call` / `tool-result` / `turn` /
|
|
2541
2551
|
# `prompt-assembled` / `done` / `error`,帧里**没有** `type` 字段;SDK 的 `trace.stream()` 注释逐字同款。
|
|
2542
2552
|
# 照旧声明生成的客户端会去 switch 一个不存在的 `type` ⇒ 这条流路对它完全不可用。
|
|
@@ -2680,7 +2690,7 @@ paths:
|
|
|
2680
2690
|
schema:
|
|
2681
2691
|
type: object
|
|
2682
2692
|
# 🔴 封闭 + `defaultModel` 补登记(census 批2 第三段,2026-07-30):铸造点
|
|
2683
|
-
# `routes/capabilities.ts
|
|
2693
|
+
# `routes/capabilities.ts` 三键字面量。`defaultModel`([865]③ id/name 撕裂消解,server
|
|
2684
2694
|
# 已发多版)SDK `models.list()` 的返回类型早就带,**spec 是唯一没登记的一侧** —— 生成式
|
|
2685
2695
|
# 消费方对它全瞎。`name` 条件(目录无命中即省略),`id` 恒在。
|
|
2686
2696
|
additionalProperties: false
|
|
@@ -2817,7 +2827,7 @@ paths:
|
|
|
2817
2827
|
post:
|
|
2818
2828
|
tags: [questions]
|
|
2819
2829
|
operationId: askDecision
|
|
2820
|
-
x-status:
|
|
2830
|
+
x-status: gated # design/172 §3.2 (#151 车4) — SHIPPED in server 7.3.0 (7.3.0/7.4.0 both on npm); off-by-flag (STREAM_APPROVAL_ENABLED, default OFF ≤7.4.0 / ON ≥7.5.0) ⇒ 501 feature.approval_ask_disabled when the five-way gate is unmet. SDK toolApprovals.decideAsk() 消费。
|
|
2821
2831
|
summary: Settle an IN-STREAM approval card (design/172 streaming approval protocol).
|
|
2822
2832
|
description: >
|
|
2823
2833
|
The in-stream sibling of POST /v1/tool-approvals/{id}/respond: the approver is live on the SSE stream, so
|
|
@@ -3123,7 +3133,7 @@ paths:
|
|
|
3123
3133
|
POST-MERGE FULL row — replace by `row.id`, NOT a sparse patch) + `event: task_remove`/`event:
|
|
3124
3134
|
workflow_remove` `{id, ts}` departures.
|
|
3125
3135
|
🔴 Keep-alive is a REAL NAMED FRAME — `event: heartbeat` + `data: {}` every 15 s
|
|
3126
|
-
(`src/http/routes/fleet.ts
|
|
3136
|
+
(`src/http/routes/fleet.ts`), NOT an SSE `: hb` comment (the旁注 says why: a per-frame-parsing BFF
|
|
3127
3137
|
drops comments, so downstream saw a zero-frame window). Do NOT implement the reader as "skip lines
|
|
3128
3138
|
starting with `:`" — swallow the heartbeat BY NAME. (Corrected 2026-08-02; the `: hb` shape belongs to
|
|
3129
3139
|
`GET /v1/sessions/{sessionId}/events` alone, and beats at a tunable ~25 s.)
|
|
@@ -3279,7 +3289,7 @@ paths:
|
|
|
3279
3289
|
summary: 'Newest PUBLISHED entry for a profile → { image }.'
|
|
3280
3290
|
responses:
|
|
3281
3291
|
# 🔴 census 批2 四段:this arm was a bare open `{}` (no `image` key even declared) — the handler's real
|
|
3282
|
-
# body is `{ image: entry }` (images.ts
|
|
3292
|
+
# body is `{ image: entry }` (images.ts), entry = the SAME ImageIndexEntry as the list route.
|
|
3283
3293
|
'200': { description: '{ image: entry }.', content: { application/json: { schema: { type: object, required: [image], additionalProperties: false, properties: { image: { $ref: '#/components/schemas/ImageIndexEntry' } } } } } }
|
|
3284
3294
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
3285
3295
|
|
|
@@ -3293,7 +3303,7 @@ paths:
|
|
|
3293
3303
|
x-status: live
|
|
3294
3304
|
summary: 'Entry by immutable digest → { image }.'
|
|
3295
3305
|
responses:
|
|
3296
|
-
# 🔴 census 批2 四段:same open-`{}` gap as imagesByProfile — real body `{ image: entry }` (images.ts
|
|
3306
|
+
# 🔴 census 批2 四段:same open-`{}` gap as imagesByProfile — real body `{ image: entry }` (images.ts).
|
|
3297
3307
|
'200': { description: '{ image: entry }.', content: { application/json: { schema: { type: object, required: [image], additionalProperties: false, properties: { image: { $ref: '#/components/schemas/ImageIndexEntry' } } } } } }
|
|
3298
3308
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
3299
3309
|
|
|
@@ -3568,7 +3578,7 @@ paths:
|
|
|
3568
3578
|
schema:
|
|
3569
3579
|
type: object
|
|
3570
3580
|
# 🔴 census 批2 五段:CLOSED — exact literal `{ scope, exportedAt, entries }`
|
|
3571
|
-
# (memory-policy.ts
|
|
3581
|
+
# (memory-policy.ts), no fourth key.
|
|
3572
3582
|
required: [scope, exportedAt, entries]
|
|
3573
3583
|
additionalProperties: false
|
|
3574
3584
|
properties:
|
|
@@ -3649,7 +3659,7 @@ paths:
|
|
|
3649
3659
|
schema:
|
|
3650
3660
|
type: object
|
|
3651
3661
|
# 🔴 census 批2 五段:path↔schema 脱钩修(same class as the earlier BakeClaim/usage-triplet
|
|
3652
|
-
# finds) — `OutcomeRow` already existed named+correct (observability.ts
|
|
3662
|
+
# finds) — `OutcomeRow` already existed named+correct (observability.ts's exact
|
|
3653
3663
|
# `{ outcomes: rows }`) but this path never `$ref`'d it, declaring a bare open `{}` instead.
|
|
3654
3664
|
required: [outcomes]
|
|
3655
3665
|
additionalProperties: false
|
|
@@ -3819,7 +3829,7 @@ paths:
|
|
|
3819
3829
|
description: 'Injected. Body `{ runId, label, status: "running", delivery: "applied", marker }`.'
|
|
3820
3830
|
# 🔴 census 批2 五段:spec-谎修——this 200 declared a bare `description` with NO `content`/`schema`
|
|
3821
3831
|
# at all (classify() reads it as "no-json", invisible to both the open- and closed-op ledgers)
|
|
3822
|
-
# while the server genuinely sends a JSON body (workflows.ts
|
|
3832
|
+
# while the server genuinely sends a JSON body (workflows.ts). The named schema
|
|
3823
3833
|
# `WorkflowAgentSteerReceipt` already existed (path↔schema decoupling, same class as the earlier
|
|
3824
3834
|
# BakeClaim/usage-triplet finds) — wiring it up here, not inventing a new one.
|
|
3825
3835
|
content:
|
|
@@ -3863,7 +3873,7 @@ paths:
|
|
|
3863
3873
|
content:
|
|
3864
3874
|
application/json:
|
|
3865
3875
|
# 🔴 census 批2 五段:CLOSED against the real emitter — `sendJson(res, 200, { model,
|
|
3866
|
-
# ...deps.metrics.summarize() })` (server.ts
|
|
3876
|
+
# ...deps.metrics.summarize() })` (server.ts) is a fixed key set (server observability/
|
|
3867
3877
|
# metrics.ts `MetricsSummary`), not an ops free-for-all. Left `x-status: draft` / `x-sdk: none`
|
|
3868
3878
|
# untouched (still deliberately outside the SDK's wrapped surface) — closing the SHAPE and
|
|
3869
3879
|
# keeping it un-wrapped are independent axes.
|
|
@@ -4054,8 +4064,8 @@ components:
|
|
|
4054
4064
|
`Capabilities.scenarios` instead. `source`/`builtin` = builtin vs center-config overlay; `toolset` names
|
|
4055
4065
|
the tool bundle while `tools` are the resolved tool names; `promptSummary` is a human-readable prompt
|
|
4056
4066
|
DIGEST (never the full prompt); `enabled` = a center scenario can be declared-but-disabled.
|
|
4057
|
-
# 封闭(census 批2 第三段,2026-07-30):路由 `routes/capabilities.ts
|
|
4058
|
-
# 其类型 `ScenarioDetail`(capabilities/scenarios.ts
|
|
4067
|
+
# 封闭(census 批2 第三段,2026-07-30):路由 `routes/capabilities.ts` 原样发 `deps.scenarioDetails[name]`,
|
|
4068
|
+
# 其类型 `ScenarioDetail`(capabilities/scenarios.ts)恰是这 8 个必填键;builtin 工厂 `mk` 与
|
|
4059
4069
|
# center overlay 都按该接口铸,无第 9 键来源。
|
|
4060
4070
|
required: [name, source, builtin, summary, toolset, tools, promptSummary, enabled]
|
|
4061
4071
|
additionalProperties: false
|
|
@@ -4200,7 +4210,7 @@ components:
|
|
|
4200
4210
|
type: string
|
|
4201
4211
|
description: >-
|
|
4202
4212
|
[2400] TR-16 (declared 2026-08-02) — CALLER-MINTED uuidv7 task id: the DURABLE second tier of
|
|
4203
|
-
idempotency on POST /v1/runs (`src/http/routes/runs.ts
|
|
4213
|
+
idempotency on POST /v1/runs (`src/http/routes/runs.ts`). The `Idempotency-Key` header's
|
|
4204
4214
|
cache is in-memory and PER-POD, so a dispatch gateway that re-routes a retry to ANOTHER instance
|
|
4205
4215
|
after a network error would start a SECOND run; THIS replay reads the durable run store, so it
|
|
4206
4216
|
survives the re-route and a restart — it is the prerequisite for gateway failover. A hit replays the
|
|
@@ -4390,7 +4400,7 @@ components:
|
|
|
4390
4400
|
description: Quality-gate cascade (cheap→strong). Mutually exclusive with `verify`. Not on the stream.
|
|
4391
4401
|
suggestNextPrompts:
|
|
4392
4402
|
description: >
|
|
4393
|
-
E12 (shell-host; service spec-fields.ts
|
|
4403
|
+
E12 (shell-host; service spec-fields.ts / runs.ts, SHIPPED) — opt-in post-completion "what to ask
|
|
4394
4404
|
next" suggestions. After a COMPLETED run, core runs an LLM pass and the service appends a `suggestions`
|
|
4395
4405
|
event to the durable run-events tail. `true` = core defaults; the object form tunes count / generating
|
|
4396
4406
|
role. 🔴 Mutually exclusive with `verify`/`cascade` (those return a result, not a streamed run → 400).
|
|
@@ -4421,8 +4431,12 @@ components:
|
|
|
4421
4431
|
callability; the advertised schema stays the empty object); `swap` advertises the REAL schema on the
|
|
4422
4432
|
next request. A provider whose decoding is CONSTRAINED by the advertised schema loops UNBOUNDED under
|
|
4423
4433
|
`static` (every round emits `{}` and the next round still advertises an empty schema), which is why
|
|
4424
|
-
this is a per-task knob. OMIT to inherit the engine chain
|
|
4425
|
-
|
|
4434
|
+
this is a per-task knob. OMIT to inherit the engine chain,
|
|
4435
|
+
`spec ?? env(SEMA_TOOL_MATERIALIZE_STRATEGY) ?? "swap"` — sending an explicit value takes that
|
|
4436
|
+
decision away from the deployment env lane. 🔴 The chain-tail default is **`swap`** (this text used
|
|
4437
|
+
to say `static`): it defaulted to `static` for exactly one core release window and core 5.15.0
|
|
4438
|
+
(BREAKING) put it back to `swap`; the server floor is core >= 5.16.0, so every supported deployment
|
|
4439
|
+
resolves an omitted value to `swap`. Unknown value => 400 fail-loud.
|
|
4426
4440
|
clientContext:
|
|
4427
4441
|
type: object
|
|
4428
4442
|
description: Non-authoritative client hints (never trusted for authz).
|
|
@@ -4465,7 +4479,7 @@ components:
|
|
|
4465
4479
|
type: boolean
|
|
4466
4480
|
description: >
|
|
4467
4481
|
🔴 PER-TASK opt-in for forwarding subagent CONTENT onto the parent's event stream (server
|
|
4468
|
-
`src/http/wire-types.ts
|
|
4482
|
+
`src/http/wire-types.ts`, consumed at `boot/resolve-spec.ts` — read STRICTLY as `=== true`).
|
|
4469
4483
|
⚠️ The capability bit of the same name says "this body key is ACCEPTED", NOT "forwarding is on":
|
|
4470
4484
|
it is hard-coded true, while forwarding itself is OFF unless this key is sent. Without it the parent
|
|
4471
4485
|
stream carries progress-only frames and a subagent-transcript view stays empty forever.
|
|
@@ -4476,11 +4490,11 @@ components:
|
|
|
4476
4490
|
- type: object
|
|
4477
4491
|
additionalProperties: false
|
|
4478
4492
|
properties:
|
|
4479
|
-
ttlMs: { type: integer, description: 'Retention window; server CLAMPS to ≤ 24 h (task-workflow.ts
|
|
4493
|
+
ttlMs: { type: integer, description: 'Retention window; server CLAMPS to ≤ 24 h (task-workflow.ts).' }
|
|
4480
4494
|
max: { type: integer, description: 'Retained session count; server CLAMPS to ≤ 64.' }
|
|
4481
4495
|
description: >
|
|
4482
4496
|
🔴 PER-TASK opt-in to RETAIN finished subagent sessions so they can be resumed (server
|
|
4483
|
-
`src/http/wire-types.ts
|
|
4497
|
+
`src/http/wire-types.ts`, normalized at `boot/resolve-spec.ts`). This is the OTHER HALF of
|
|
4484
4498
|
`POST /v1/runs/{runId}/subagents/{handle}/resume`: the capability bit `subagentResume` can be true and
|
|
4485
4499
|
the route mounted, and the call still 409s `resume.retain_off` — retention is per-run and OFF by default.
|
|
4486
4500
|
An over-large ask is CLAMPED, not rejected. (Declared 2026-08-02; the error code and the capability bit
|
|
@@ -4572,7 +4586,7 @@ components:
|
|
|
4572
4586
|
# 🔴 **刻意不封闭**(census 轴一裁定,2026-07-30)。此前是「没写」= JSON Schema 默认开放,分不清
|
|
4573
4587
|
# 「决定了要开」还是「忘了」;现在显式写成 true,让这条决定可读、可复审。理由:server 对引擎
|
|
4574
4588
|
# `TaskResult` 是**整体透传**(runs.ts `withModelUsage` 只做 `{...result, stats:{...}}` 的加法),
|
|
4575
|
-
# 而 SDK 的 `TaskResult`/`TaskStats` 两侧都带 `[key: string]: unknown` 开集(types.ts
|
|
4589
|
+
# 而 SDK 的 `TaskResult`/`TaskStats` 两侧都带 `[key: string]: unknown` 开集(types.ts)——把
|
|
4576
4590
|
# 这里改成 false 会让 spec 与本仓自己的类型面互相打脸,并且把「引擎加字段」判成 wire 违约(它不是)。
|
|
4577
4591
|
# 收紧这一面的正解不是 additionalProperties,是把引擎真发的键**逐个登记**(字段级 drift 门的活)。
|
|
4578
4592
|
additionalProperties: true
|
|
@@ -4684,7 +4698,7 @@ components:
|
|
|
4684
4698
|
|
|
4685
4699
|
RunReceipt:
|
|
4686
4700
|
type: object
|
|
4687
|
-
# 封闭(census 轴一,2026-07-30):producer 铸造点 routes/runs.ts
|
|
4701
|
+
# 封闭(census 轴一,2026-07-30):producer 铸造点 routes/runs.ts 与 idem 重放臂各自逐字写死
|
|
4688
4702
|
# `{taskId, sessionId, status}` —— 三键全在场、无第四键 ⇒ required 已完整,additionalProperties 收紧到
|
|
4689
4703
|
# false 后「server 多发一个 spec 没登记的键」当场红(此前 ①档只校已声明键的类型,多键完全不可见)。
|
|
4690
4704
|
additionalProperties: false
|
|
@@ -4701,7 +4715,7 @@ components:
|
|
|
4701
4715
|
Run state (`GET /v1/runs/:id`) — live shape per the pinned wire contract Drift 2: `result` is the NESTED TaskResult
|
|
4702
4716
|
object (output text in result.result, stats in result.stats; NO top-level stats), and the error text
|
|
4703
4717
|
field is `error` (not errorMessage; errorCode is floated up from result.errorCode).
|
|
4704
|
-
# 封闭(census 轴一,2026-07-30):铸造点 routes/runs.ts
|
|
4718
|
+
# 封闭(census 轴一,2026-07-30):铸造点 routes/runs.ts 是一个逐键写死的字面量,恰好 10 键
|
|
4705
4719
|
# (taskId/sessionId/status/result/supervisorCost/suggestions/errorCode/error/jobId/source),与本
|
|
4706
4720
|
# properties 一一对上;只有前三键无条件在场(其余走 `?? undefined` ⇒ JSON 丢键)⇒ required 维持 3 键。
|
|
4707
4721
|
additionalProperties: false
|
|
@@ -4765,7 +4779,7 @@ components:
|
|
|
4765
4779
|
description: >
|
|
4766
4780
|
Synchronous ack for `POST /v1/runs/:id/cancel`. `status` is "cancelling" (accepted) or a terminal status
|
|
4767
4781
|
(idempotent no-op). NOTE: "cancelling" is NOT a RunStatus enum member — it only appears here.
|
|
4768
|
-
# 封闭(census 轴一,2026-07-30):cancel 面的 7 个 sendJson 铸造点(routes/runs.ts
|
|
4782
|
+
# 封闭(census 轴一,2026-07-30):cancel 面的 7 个 sendJson 铸造点(routes/runs.ts
|
|
4769
4783
|
# 495/505/512)键集的并集恰好 = {taskId, status, note?, errorCode?};taskId/status 无条件在场。
|
|
4770
4784
|
additionalProperties: false
|
|
4771
4785
|
required: [taskId, status]
|
|
@@ -4866,7 +4880,7 @@ components:
|
|
|
4866
4880
|
securityContext: { type: object, additionalProperties: true, description: 'k8s-shaped, genuinely arbitrary — Record<string,unknown> server-side.' }
|
|
4867
4881
|
|
|
4868
4882
|
ImageSelectResult:
|
|
4869
|
-
# 新增(2026-07-25 回填批)。🔴 census 批2 四段:closed against the real handler (images.ts
|
|
4883
|
+
# 新增(2026-07-25 回填批)。🔴 census 批2 四段:closed against the real handler (images.ts) — ALL
|
|
4870
4884
|
# seven keys are unconditionally assigned every 200 (required tightened from none); `manifestSha` can be
|
|
4871
4885
|
# null (ImageIndexEntry.manifestSha is `string | null`, this was typed non-nullable — a spec lie); and
|
|
4872
4886
|
# `podContract`/`capabilities` now share the SAME closed schemas as ImageIndexEntry (no more drift/no
|
|
@@ -4943,7 +4957,7 @@ components:
|
|
|
4943
4957
|
description: >
|
|
4944
4958
|
Turn trace envelope (`GET /v1/tasks/:id/turns`). Key is `turns` (resource-named). `retainedFrom` marks
|
|
4945
4959
|
the lowest retained seq. Turn ITEM shape is draft (co-design with artifacts, Q7).
|
|
4946
|
-
# 封闭 + required 补全(census 轴一,2026-07-30):铸造点 routes/trace-usage.ts
|
|
4960
|
+
# 封闭 + required 补全(census 轴一,2026-07-30):铸造点 routes/trace-usage.ts
|
|
4947
4961
|
# `{ turns, ...(nextCursor?{nextCursor}:{}) , retainedFrom }` —— `retainedFrom` 是**无条件**键
|
|
4948
4962
|
# (`RunStore.retainedFrom(): Promise<number>`,四个实现都返回数字),此前只 required 了 `turns`,
|
|
4949
4963
|
# 于是「server 少发 retainedFrom」这种断页判据丢失对本门不可见。
|
|
@@ -4959,7 +4973,7 @@ components:
|
|
|
4959
4973
|
TaskList:
|
|
4960
4974
|
type: object
|
|
4961
4975
|
description: Paginated run summaries (`GET /v1/tasks`). Envelope key is `tasks` (resource-named, NOT `items`).
|
|
4962
|
-
# 封闭(census 轴一,2026-07-30):信封铸造点 routes/trace-usage.ts
|
|
4976
|
+
# 封闭(census 轴一,2026-07-30):信封铸造点 routes/trace-usage.ts 只有 tasks + 条件 nextCursor。
|
|
4963
4977
|
# 行本身(`TaskSummary`)保持开集 —— 它的 TS 侧有索引签名(引擎透传),那份「开」是真的。
|
|
4964
4978
|
additionalProperties: false
|
|
4965
4979
|
required: [tasks]
|
|
@@ -5020,7 +5034,7 @@ components:
|
|
|
5020
5034
|
|
|
5021
5035
|
ArtifactList:
|
|
5022
5036
|
type: object
|
|
5023
|
-
# 封闭(census 轴一,2026-07-30):铸造点 routes/trace-usage.ts
|
|
5037
|
+
# 封闭(census 轴一,2026-07-30):铸造点 routes/trace-usage.ts 只有 artifacts 一键(无分页)。
|
|
5024
5038
|
# 行本身(`Artifact`)保持开集(TS 侧索引签名)。
|
|
5025
5039
|
additionalProperties: false
|
|
5026
5040
|
required: [artifacts]
|
|
@@ -5032,7 +5046,7 @@ components:
|
|
|
5032
5046
|
LeaderReceipt:
|
|
5033
5047
|
type: object
|
|
5034
5048
|
description: >
|
|
5035
|
-
202 receipt of POST /v1/leader (server leader/endpoint.ts
|
|
5049
|
+
202 receipt of POST /v1/leader (server leader/endpoint.ts — exact literal
|
|
5036
5050
|
`{ leaderRunId, status: "running" }`; the POST ack is always the "running" value, the other
|
|
5037
5051
|
`status` enum members only ever appear on the GET twin below).
|
|
5038
5052
|
# 🔴 census 批2 五段:CLOSED — the POST handler's literal never carries a third key.
|
|
@@ -5045,12 +5059,12 @@ components:
|
|
|
5045
5059
|
LeaderRecord:
|
|
5046
5060
|
type: object
|
|
5047
5061
|
description: >
|
|
5048
|
-
200 body of GET /v1/leader/{leaderRunId} (server leader/endpoint.ts
|
|
5062
|
+
200 body of GET /v1/leader/{leaderRunId} (server leader/endpoint.ts — exact literal
|
|
5049
5063
|
`{ id, status, ...(result?{result}:{}), ...(error?{error}:{}) }`).
|
|
5050
5064
|
# 🔴 census 批2 五段:两处修——① CLOSED(result/error 是 OMIT-when-absent 的可选键,不是额外键);
|
|
5051
5065
|
# ② `status` 的第四值 `needs_human`(LEADER-REPAIRLOOP-INTEGRATION §5/§10.6 的第三终态,
|
|
5052
5066
|
# `statusForLeaderResult` 在 candidate_only/needs_human_oracle/conflict 三个 repairTerminal 上产出)
|
|
5053
|
-
# 此前 SPEC LIES BY OMISSION——TS 侧 `LeaderRecord.status` 早就带这个第四值(types.ts
|
|
5067
|
+
# 此前 SPEC LIES BY OMISSION——TS 侧 `LeaderRecord.status` 早就带这个第四值(types.ts,亲验
|
|
5054
5068
|
# 已在场),只有 spec 的 enum 一直缺它,是个只有场景真触发才会现形的假红洞(一个真实合法帧被判违约)。
|
|
5055
5069
|
required: [id, status]
|
|
5056
5070
|
additionalProperties: false
|
|
@@ -5113,7 +5127,7 @@ components:
|
|
|
5113
5127
|
type: object
|
|
5114
5128
|
description: >
|
|
5115
5129
|
The legacy D-lane approval row of GET /v1/approvals/{approvalId} (server `ApprovalRow`,
|
|
5116
|
-
plugins/approval-store-sql.ts
|
|
5130
|
+
plugins/approval-store-sql.ts — the row is `sendJson`'d verbatim, approvals-assistant.ts).
|
|
5117
5131
|
Present only on deployments running the legacy `approvalStore` leg (no `checkpointStore` wired);
|
|
5118
5132
|
the durable F4 lane has no by-id GET (only list + decide).
|
|
5119
5133
|
# 🔴 census 批2 五段:CLOSED — byte-identical to the server row type, no extra keys.
|
|
@@ -5167,7 +5181,7 @@ components:
|
|
|
5167
5181
|
legacy verbs in 1.0.0; the live face is `client.memory.exportScope` / `.sync`
|
|
5168
5182
|
(`GET /v1/memory/export`, `POST /v1/memory/sync/{scope}`), which this flag does NOT gate.
|
|
5169
5183
|
Kept on the wire so an older shell that still reads it honestly hides the dead affordances.
|
|
5170
|
-
workflows: { type: boolean, description: "S8 self-orchestration
|
|
5184
|
+
workflows: { type: boolean, description: "ENGINE-CAN: this worker's engine can orchestrate S8 self-orchestration workflows (server: `workflowsCapable ?? Boolean(workflowRunStore)`). The MOUNTING of the durable /v1/workflows read routes is the separate `workflowsList` bit below; the two coincide in today's wiring but are declared as orthogonal axes." }
|
|
5171
5185
|
workflowsList: { type: boolean, description: "`GET /v1/workflows` list face (separate from the per-run reads)." }
|
|
5172
5186
|
resumeAt: { type: boolean, description: "E18 resume-at-message anchors are resolvable." }
|
|
5173
5187
|
rewindFiles: { type: boolean, description: "E19 working-tree snapshot/restore is wired." }
|
|
@@ -5178,7 +5192,7 @@ components:
|
|
|
5178
5192
|
sessionSearch: { type: boolean, description: "Server-side session search." }
|
|
5179
5193
|
sessionFork: { type: boolean, description: "Session fork verb." }
|
|
5180
5194
|
sessionDelete: { type: boolean, description: "Session delete verb." }
|
|
5181
|
-
sessionInit: { type: boolean, description: "
|
|
5195
|
+
sessionInit: { type: boolean, description: "`GET /v1/sessions/{sessionId}/init` startup bundle (E11 shell-host contract) is available. Pure config assembly (model + mode), always served — the server hard-codes true. NOTE: this advertises an ENDPOINT, not a `session_init` stream frame; no such frame exists on any leg." }
|
|
5182
5196
|
sessionPolicy: { type: boolean, description: "E6 per-session operator-tightened tool rules are durable." }
|
|
5183
5197
|
usage: { type: boolean, description: "QUOTA face wired (server costQuota dep — cost/token budget enforcement + per-principal accounting). NOT an analytics-availability probe ([1871] B15): per-turn analytics (turn_end.usage, model_usage frames) are engine-side and unconditional, and GET /v1/usage always answers 200 (with `enabled: false` when the quota face is off). Gate quota UI on this key; never gate analytics on it." }
|
|
5184
5198
|
fleet:
|
|
@@ -5219,7 +5233,7 @@ components:
|
|
|
5219
5233
|
sessionEvents:
|
|
5220
5234
|
type: boolean
|
|
5221
5235
|
description: >
|
|
5222
|
-
🔴 契约调和车1 H② (2026-08-02): server HAS been emitting this key (`src/http/routes/capabilities.ts
|
|
5236
|
+
🔴 契约调和车1 H② (2026-08-02): server HAS been emitting this key (the `sessionEvents` bit in `src/http/routes/capabilities.ts`)
|
|
5223
5237
|
while both this spec and the SDK type were missing it. Gates `GET /v1/sessions/{sessionId}/events`
|
|
5224
5238
|
(the session-level SSE head subscription). Predicate is a THREE-way AND: a durable session-watch seam
|
|
5225
5239
|
plus a session store exposing BOTH `getLeafId` and `ownerOf` — the route's 501 uses the same
|
|
@@ -5253,8 +5267,8 @@ components:
|
|
|
5253
5267
|
streamApproval:
|
|
5254
5268
|
type: boolean
|
|
5255
5269
|
description: >
|
|
5256
|
-
design/172 IN-STREAM approval protocol is on this worker (server >=7.3.0,
|
|
5257
|
-
`src/http/routes/capabilities.ts
|
|
5270
|
+
design/172 IN-STREAM approval protocol is on this worker (server >=7.3.0, the `streamApproval` bit in
|
|
5271
|
+
`src/http/routes/capabilities.ts` — `resolveStreamApprovalGate(...).active`). TRUE ⇒ the live
|
|
5258
5272
|
stream may carry `approval_request` / `approval_revoke` frames and `POST
|
|
5259
5273
|
/v1/tasks/{taskId}/asks/{askId}/decision` settles them. FALSE/absent ⇒ that endpoint answers **501
|
|
5260
5274
|
`feature.approval_ask_disabled`** on every call and the two frames never appear — the SAME predicate
|
|
@@ -5264,15 +5278,22 @@ components:
|
|
|
5264
5278
|
`backend.kind != "local"` (the ask ledger must be DURABLE — an in-memory ledger loses accepted
|
|
5265
5279
|
decisions on restart) AND the park facility is present (checkpoint store + DURABLE_APPROVAL, the
|
|
5266
5280
|
degradation target when a window expires; without it the outcome would be a fail-closed deny, worse
|
|
5267
|
-
than today's live card).
|
|
5268
|
-
|
|
5269
|
-
|
|
5270
|
-
|
|
5281
|
+
than today's live card). The deployment default for `STREAM_APPROVAL_ENABLED` reads in TWO
|
|
5282
|
+
SEGMENTS: on server **<= 7.4.0 it is default OFF**, so on virtually every deployment of those
|
|
5283
|
+
versions this bit is `false` and the legacy `tool_approval` live-card leg is the only approval face;
|
|
5284
|
+
on server **>= 7.5.0 it is default ON** (published to npm 2026-08-07, disclosed as BREAKING in the
|
|
5285
|
+
server CHANGELOG together with the ask window default 60s -> 300s), so a deployment meeting the
|
|
5286
|
+
other four conjuncts serves the frames and the decision endpoint out of the box. BOTH segments are
|
|
5287
|
+
live deployment realities — the first is not a historical footnote, it still describes every running
|
|
5288
|
+
7.3.x/7.4.x install, and a consumer that reads only one of them is wrong about half the fleet.
|
|
5289
|
+
`STREAM_APPROVAL_ENABLED=false` is the clean revert key. Do NOT infer from the version number or
|
|
5290
|
+
from this prose — READ THIS BIT; it is the conjunction's actual value. Orthogonal to `toolApproval`
|
|
5291
|
+
(the live-card leg) and to `approvals` (the durable checkpoint leg) — all three can differ.
|
|
5271
5292
|
promptSuggestions: { type: boolean, description: "Follow-up prompt suggestions are generated." }
|
|
5272
5293
|
modelUsage:
|
|
5273
5294
|
type: boolean
|
|
5274
5295
|
description: >
|
|
5275
|
-
Per-model usage echo is available (server `src/http/routes/capabilities.ts
|
|
5296
|
+
Per-model usage echo is available (server: the `modelUsage` bit in `src/http/routes/capabilities.ts`,
|
|
5276
5297
|
`Boolean(runStore && modelUsage)` — BOTH the durable run store and the tracker that feeds it;
|
|
5277
5298
|
absent either, a consumer only gets aggregate cost).
|
|
5278
5299
|
🔴 CORRECTED (契约调和车1 H③, 2026-08-02): this bit does NOT gate a read route — the route this
|
|
@@ -5288,21 +5309,25 @@ components:
|
|
|
5288
5309
|
s3PublicEndpoint:
|
|
5289
5310
|
type: ["string", "null"]
|
|
5290
5311
|
description: >
|
|
5291
|
-
|
|
5292
|
-
|
|
5312
|
+
SendUserFile's S3 public-link base (`config.sendUserFile.publicEndpoint`), when the deployment
|
|
5313
|
+
configures one. `null` = not configured. 🔴 CORRECTED: it has NOTHING to do with artifact/snapshot
|
|
5314
|
+
links, and there is no "links are then worker-relative" fallback — an unconfigured endpoint makes
|
|
5315
|
+
SendUserFile fail loudly and the sibling `sendUserFile` bit report false. A NON-boolean capability
|
|
5316
|
+
value (there are several — see `taskSettings`, `fleet`, `workspace`, `version`, `scenarios`).
|
|
5293
5317
|
taskSettings:
|
|
5294
5318
|
type: object
|
|
5295
5319
|
description: >
|
|
5296
5320
|
Which `settings.json` sub-faces this worker honours (CC-parity v1). OPEN object — unknown keys may
|
|
5297
|
-
appear.
|
|
5321
|
+
appear. One of the NON-boolean capability values (not "the other one": `fleet`, `workspace`,
|
|
5322
|
+
`s3PublicEndpoint`, `version` and `scenarios` are non-boolean too — read each key's own shape).
|
|
5298
5323
|
additionalProperties: true
|
|
5299
5324
|
properties:
|
|
5300
5325
|
permissions: { type: boolean }
|
|
5301
5326
|
permissionMode: { type: boolean }
|
|
5302
5327
|
model: { type: boolean }
|
|
5303
5328
|
outputStyle: { type: boolean }
|
|
5304
|
-
env: { type: boolean }
|
|
5305
|
-
hooks: { type: boolean }
|
|
5329
|
+
env: { type: boolean, description: 'TRUE on the single-user host lane (server emits `cwdHonored(config)`). It is NOT hard-coded false any more — the old always-false value predated the per-task shellEnv seam and hid a live capability.' }
|
|
5330
|
+
hooks: { type: boolean, description: 'Single-user deployments only (`requirePrincipal !== true`).' }
|
|
5306
5331
|
memoryWrite:
|
|
5307
5332
|
type: boolean
|
|
5308
5333
|
description: >
|
|
@@ -5388,7 +5413,7 @@ components:
|
|
|
5388
5413
|
description: >
|
|
5389
5414
|
core `MemoryEntry` (@sema-agent/core memory-engine/types.d.ts) — one memory-engine (DB twins)
|
|
5390
5415
|
note. Used verbatim by both GET /v1/memory/export's `entries` and POST /v1/memory/sync/{scope}'s
|
|
5391
|
-
`serverEntries` (server never re-shapes it — memory-policy.ts
|
|
5416
|
+
`serverEntries` (server never re-shapes it — memory-policy.ts / memory-sync.ts pass the core
|
|
5392
5417
|
array straight to `sendJson`).
|
|
5393
5418
|
required: [id, slug, frontmatter, body, rev, scope]
|
|
5394
5419
|
additionalProperties: false
|
|
@@ -5403,8 +5428,8 @@ components:
|
|
|
5403
5428
|
MemorySyncResponse:
|
|
5404
5429
|
type: object
|
|
5405
5430
|
description: >
|
|
5406
|
-
200 body of POST /v1/memory/sync/{scope} — core `MemorySyncResponse` (server memory-sync.ts
|
|
5407
|
-
`sendJson`'d verbatim (memory-policy.ts
|
|
5431
|
+
200 body of POST /v1/memory/sync/{scope} — core `MemorySyncResponse` (server memory-sync.ts),
|
|
5432
|
+
`sendJson`'d verbatim (memory-policy.ts). `pullTruncated` is OMIT-when-absent (present+`true`
|
|
5408
5433
|
only when `serverEntries` was cut by `?pull.limit`).
|
|
5409
5434
|
required: [applied, conflicts, serverEntries, serverDeletes, cursor]
|
|
5410
5435
|
additionalProperties: false
|
|
@@ -5457,7 +5482,7 @@ components:
|
|
|
5457
5482
|
MetricsSummaryOps:
|
|
5458
5483
|
type: object
|
|
5459
5484
|
description: >
|
|
5460
|
-
200 body of GET /metrics/summary — `{ model, ...MetricsSummary }` (server.ts
|
|
5485
|
+
200 body of GET /metrics/summary — `{ model, ...MetricsSummary }` (server.ts; server
|
|
5461
5486
|
observability/metrics.ts `MetricsSummary` interface + `summarize()`, all keys unconditional).
|
|
5462
5487
|
Ops/observability face (`x-sdk: none` on the path) — closed here for census fidelity, but this
|
|
5463
5488
|
does NOT change its SDK-wrapping status.
|
|
@@ -5508,7 +5533,7 @@ components:
|
|
|
5508
5533
|
A non-secret `@model` catalog entry (GET /v1/models; service src/http/routes/capabilities.ts). `name` = the `@handle` the
|
|
5509
5534
|
user types in the objective body to pick this model per-task. 🔴 NON-SECRET — name/capabilities only, never
|
|
5510
5535
|
baseUrl/apiKey/headers (the service strips them).
|
|
5511
|
-
# 🔴 封闭 + required 补铸造点(census 批2 第三段,2026-07-30):铸造点 `routes/capabilities.ts
|
|
5536
|
+
# 🔴 封闭 + required 补铸造点(census 批2 第三段,2026-07-30):铸造点 `routes/capabilities.ts`
|
|
5512
5537
|
# 是逐键字面量投影(白名单,不是透传——「open set」旧注不成立,新键要先过这道 spec)。core Model 类型
|
|
5513
5538
|
# 里 id/provider/reasoning 都是必填、`vision` 由 `input` 恒算 ⇒ 五键无条件;contextWindow/maxOutputTokens
|
|
5514
5539
|
# 0/缺省即省略,supportedEffortLevels 仅 reasoning 模型。
|
|
@@ -5548,7 +5573,7 @@ components:
|
|
|
5548
5573
|
|
|
5549
5574
|
ElicitRespondAck:
|
|
5550
5575
|
type: object
|
|
5551
|
-
description: The 200 ack from a successful elicitation respond (service elicitation.ts
|
|
5576
|
+
description: The 200 ack from a successful elicitation respond (service elicitation.ts).
|
|
5552
5577
|
# 封闭(census 批2 第三段,2026-07-30):铸造点是三键字面量,三键全部无条件。
|
|
5553
5578
|
additionalProperties: false
|
|
5554
5579
|
required: [elicitationId, delivery, action]
|
|
@@ -5560,7 +5585,7 @@ components:
|
|
|
5560
5585
|
QuestionAnswer:
|
|
5561
5586
|
type: object
|
|
5562
5587
|
description: >
|
|
5563
|
-
The shell's answer to a live `question` frame (= core QuestionAnswer, ask-question.ts
|
|
5588
|
+
The shell's answer to a live `question` frame (= core QuestionAnswer, ask-question.ts). The service validates
|
|
5564
5589
|
only this OUTER shape (`answers[]` of `{header, selected:string[], note?}`); core owns the semantic fence
|
|
5565
5590
|
(`selected ⊆ the offered options`, `note` wrapped in an untrusted-DATA fence).
|
|
5566
5591
|
required: [answers]
|
|
@@ -5582,7 +5607,7 @@ components:
|
|
|
5582
5607
|
|
|
5583
5608
|
QuestionRespondAck:
|
|
5584
5609
|
type: object
|
|
5585
|
-
description: The 200 ack from a successful question respond (service question.ts
|
|
5610
|
+
description: The 200 ack from a successful question respond (service question.ts).
|
|
5586
5611
|
# 封闭(census 批2 第三段,2026-07-30):铸造点是两键字面量。
|
|
5587
5612
|
additionalProperties: false
|
|
5588
5613
|
required: [questionId, delivery]
|
|
@@ -5597,7 +5622,7 @@ components:
|
|
|
5597
5622
|
the REQUEST principal. When no quota window is configured → enabled=false + ONLY windowSec/maxTask*
|
|
5598
5623
|
(the amount/limit fields are ABSENT) — render must tolerate the gap.
|
|
5599
5624
|
# 🔴 封闭 + required 补铸造点(census 批2 第二段,2026-07-30)。两条腿都是逐字字面量
|
|
5600
|
-
# (`routes/observability.ts
|
|
5625
|
+
# (`routes/observability.ts` —— 无配额臂 4 键 / 有配额臂 11 键),11 个属性就是并集。
|
|
5601
5626
|
# required 从 `[enabled]` 抬到四键:`windowSec`/`maxTaskCostUsd`/`maxTaskTokens` 在**两条腿上都**
|
|
5602
5627
|
# 无条件发送(config 直读),只列 `enabled` 是把恒在键写成了可缺 —— 消费方因此得写永远为真的判空。
|
|
5603
5628
|
required: [enabled, windowSec, maxTaskCostUsd, maxTaskTokens]
|
|
@@ -5623,7 +5648,7 @@ components:
|
|
|
5623
5648
|
admission + approval enforcement is 100% server-side). Top level CLOSED; the two pass-through
|
|
5624
5649
|
collections (`commandPolicy` rows, `approvalRequire` entries) stay permissive — they are operator config
|
|
5625
5650
|
echoed verbatim, not a service-minted shape.
|
|
5626
|
-
# 🔴 封闭 + required(census 批2 第二段,2026-07-30):铸造点 `routes/memory-policy.ts
|
|
5651
|
+
# 🔴 封闭 + required(census 批2 第二段,2026-07-30):铸造点 `routes/memory-policy.ts` 是一个
|
|
5627
5652
|
# 四键字面量,四个键**全部无条件**发送(`autonomy` 走 `?? null`,`commandPolicy` 走 `?? []`)——
|
|
5628
5653
|
# 此前 required 是空的,于是「一个丢了三个键的响应」也能干干净净通过。
|
|
5629
5654
|
required: [autonomy, commandPolicy, approvalRequire, limits]
|
|
@@ -5647,7 +5672,7 @@ components:
|
|
|
5647
5672
|
type: object
|
|
5648
5673
|
description: >
|
|
5649
5674
|
Effective ceilings (single-task + principal-level + quota window). CLOSED (the literal at
|
|
5650
|
-
`routes/memory-policy.ts
|
|
5675
|
+
`routes/memory-policy.ts` has exactly these four keys); the two `maxPrincipal*`/`costQuota*`
|
|
5651
5676
|
entries stay OUT of `required` — they are optional config and are omitted when unset.
|
|
5652
5677
|
additionalProperties: false
|
|
5653
5678
|
required: [maxTaskCostUsd, maxTaskTokens]
|
|
@@ -5670,7 +5695,7 @@ components:
|
|
|
5670
5695
|
GET /v1/workflows list row = core summarizeWorkflowRun projection (owner-scoped; scope = the creating
|
|
5671
5696
|
principal). All times are epoch MS.
|
|
5672
5697
|
🔴 census 批2 四段(2026-07-30):CLOSED against core's real `summarizeWorkflowRun` (sema-core
|
|
5673
|
-
src/core/workflow-run-store.ts
|
|
5698
|
+
src/core/workflow-run-store.ts) — `originatingSessionId`/`agentFailures` were emitted on the
|
|
5674
5699
|
wire (both conditional-spread, present only when defined) but absent from this schema (two-side same-gap).
|
|
5675
5700
|
required: [id, scope, status, phaseCount, agentCount, tokens, startedAt, createdAt]
|
|
5676
5701
|
additionalProperties: false
|
|
@@ -5700,7 +5725,7 @@ components:
|
|
|
5700
5725
|
🔴 `arg` is a SHORT primary-arg SUMMARY (command→name, path→basename, url→origin+path), secret-scrubbed
|
|
5701
5726
|
and truncated (~80 code points) by core. It exists for the monitor's `Read(path)` / `Bash(grep …)`
|
|
5702
5727
|
display — it is NOT the full args. RENDER it; NEVER re-feed it to a model.
|
|
5703
|
-
🔴 census 批2 四段:CLOSED against core's real `ToolActivity` (sema-core src/core/types.ts
|
|
5728
|
+
🔴 census 批2 四段:CLOSED against core's real `ToolActivity` (sema-core src/core/types.ts) —
|
|
5704
5729
|
`at` (the [843]④a epoch-ms stamp, carried verbatim by both the start and end beat) was on the wire
|
|
5705
5730
|
but absent from this schema.
|
|
5706
5731
|
required: [phase, toolCallId, toolName]
|
|
@@ -5716,7 +5741,7 @@ components:
|
|
|
5716
5741
|
WorkflowAgentRow:
|
|
5717
5742
|
# 新增(2026-07-25 回填批)—— 取代 `WorkflowRun.agents` 的 `items: {}`(零形状)。
|
|
5718
5743
|
# 🔴 census 批2 四段:CLOSED against the REAL wire projection — server's `summarizeWorkflowDetail`
|
|
5719
|
-
# (src/http/routes/workflows.ts
|
|
5744
|
+
# (src/http/routes/workflows.ts), not core's raw `WorkflowAgentRun`. The two differ: the server
|
|
5720
5745
|
# ADDS `displayStatus`/`callKey`/`groupId`/`lastActivityAt`/`durationMs`/`queuedAt`/`startedAt`/`endedAt`/
|
|
5721
5746
|
# `replayed` (all present on the wire but previously undeclared — same-side gap, no server change needed)
|
|
5722
5747
|
# and DROPS core's `errorCode`/`errorMessage`/`attempts`/`lastAttemptReason`/`sessionId` (never projected
|
|
@@ -5753,7 +5778,7 @@ components:
|
|
|
5753
5778
|
|
|
5754
5779
|
WorkflowPhaseProgress:
|
|
5755
5780
|
# 新(census 批2 四段):此前 `WorkflowRun.phases` 是 `items: {}`(零形状)。真形 = server
|
|
5756
|
-
# `summarizeWorkflowDetail`'s phases.map projection (workflows.ts
|
|
5781
|
+
# `summarizeWorkflowDetail`'s phases.map projection (workflows.ts) — a DERIVED progress view,
|
|
5757
5782
|
# not core's raw `WorkflowPhase` (drops `detail`/`model`/(phase-level) `agentFailures`; adds `done`/`total`).
|
|
5758
5783
|
type: object
|
|
5759
5784
|
description: One phase's progress in a workflow's detail (server-derived — done/total of the agents grouped under it).
|
|
@@ -5770,7 +5795,7 @@ components:
|
|
|
5770
5795
|
|
|
5771
5796
|
WorkflowGroupNode:
|
|
5772
5797
|
# 新(census 批2 四段):`WorkflowRun.groups` was undeclared entirely. Real shape = server's rebuilt nested
|
|
5773
|
-
# tree (workflows.ts
|
|
5798
|
+
# tree (workflows.ts, GroupNode) — recursive, acyclic (a dangling/cyclic parentGroupId is grafted
|
|
5774
5799
|
# onto the root by the server, so this shape never actually cycles on the wire).
|
|
5775
5800
|
type: object
|
|
5776
5801
|
description: One node of the workflow's nested `ctx.workflow` group tree (rebuilt server-side from `parentGroupId`).
|
|
@@ -5788,7 +5813,7 @@ components:
|
|
|
5788
5813
|
|
|
5789
5814
|
WorkflowRunStats:
|
|
5790
5815
|
# 新(census 批2 四段):此前 inline `stats` 只钉了 `tokens`/`nested.tokens` 两键;真形 = core
|
|
5791
|
-
# `WorkflowRunStats`(sema-core src/orchestration/workflow-types.ts
|
|
5816
|
+
# `WorkflowRunStats`(sema-core src/orchestration/workflow-types.ts)——own/nested 各自还有
|
|
5792
5817
|
# `turns`/`costMicroUsd`,nested 另有 `tasks`。四键(own turns/costMicroUsd + nested 两键)此前两侧同缺。
|
|
5793
5818
|
type: object
|
|
5794
5819
|
description: 'Cumulative workflow usage. `own` (top-level) and `nested` (delegated sub-agents) are kept SEPARATE (R-5) — total spend = tokens + nested.tokens.'
|
|
@@ -5810,7 +5835,7 @@ components:
|
|
|
5810
5835
|
|
|
5811
5836
|
WorkflowRun:
|
|
5812
5837
|
# 🔴 census 批2 四段:CLOSED against the REAL wire projection — server's `summarizeWorkflowDetail`
|
|
5813
|
-
# (src/http/routes/workflows.ts
|
|
5838
|
+
# (src/http/routes/workflows.ts), which is a DERIVED view over core's `WorkflowRun`, not the raw
|
|
5814
5839
|
# record. This schema previously mirrored (a stale subset of) the core type; the actual wire adds
|
|
5815
5840
|
# `durationMs`/`unphased`/`groups` and drops core's `sourceTaskId`/`originatingSessionId`/`effectiveArgs`/
|
|
5816
5841
|
# `resultFull`/`completionId`/`resume`/`journalSkips` (never projected by this route — genuinely absent
|
|
@@ -5933,7 +5958,7 @@ components:
|
|
|
5933
5958
|
SessionNotifyResult:
|
|
5934
5959
|
# 4.3.0(SM-9):把 notify 的两态提成**具名** schema —— 此前只有 path 内联的两个匿名 200/202 形,
|
|
5935
5960
|
# SDK 侧的返回型则是裸 `Record<string, unknown>`,`delivery` 这条承重语义(已送达 vs 排队)在类型面
|
|
5936
|
-
# 整个丢失。铸造点 `routes/notify-wake.ts
|
|
5961
|
+
# 整个丢失。铸造点 `routes/notify-wake.ts`(live / parked 两臂),都是字面量。
|
|
5937
5962
|
description: >
|
|
5938
5963
|
POST /v1/sessions/{sessionId}/notify 的判别联合。分支 `delivery`:`live` = 会话有活流、通知已送达
|
|
5939
5964
|
(HTTP 200);`parked` = 无活流,排队到下次开流才 drain(HTTP 202)。消费方不得把两者都渲染成"已通知"。
|
|
@@ -5984,7 +6009,7 @@ components:
|
|
|
5984
6009
|
nextOffset: { type: integer, description: 'Pagination cursor; present only when the page is exactly `limit` rows.' }
|
|
5985
6010
|
WorkflowJournalEntry:
|
|
5986
6011
|
# 新(census 批2 四段):GET /v1/workflows/:id/journal row, the non-truncated arm (server `projectResult`,
|
|
5987
|
-
# workflows.ts
|
|
6012
|
+
# workflows.ts) — one agent()-call's cached TaskResult, bounded + redacted.
|
|
5988
6013
|
type: object
|
|
5989
6014
|
description: One journal entry — a completed agent() call's projected TaskResult (bounded + redacted).
|
|
5990
6015
|
required: [callKey, ordinal, status]
|
|
@@ -5999,7 +6024,7 @@ components:
|
|
|
5999
6024
|
turns: { type: integer, description: 'present only when the result carried stats.' }
|
|
6000
6025
|
|
|
6001
6026
|
WorkflowJournalEntryTruncated:
|
|
6002
|
-
# 新(census 批2 四段):the truncated arm (workflows.ts
|
|
6027
|
+
# 新(census 批2 四段):the truncated arm (workflows.ts) — an honest stub for a row whose
|
|
6003
6028
|
# stored TaskResult exceeded the per-row 64KiB gate (SQL stores) or byte length (file/in-memory
|
|
6004
6029
|
# fallback): the server never pulls the oversized payload into process memory.
|
|
6005
6030
|
type: object
|
|
@@ -6016,17 +6041,17 @@ components:
|
|
|
6016
6041
|
type: object
|
|
6017
6042
|
description: >
|
|
6018
6043
|
One frame of GET /v1/workflows/:id/stream (streamWorkflowRun). FIRST frame is `event:meta` with
|
|
6019
|
-
`data: {type:"meta", version, runId}` (`src/http/routes/workflows.ts
|
|
6044
|
+
`data: {type:"meta", version, runId}` (`src/http/routes/workflows.ts` — the `type` is double-emitted
|
|
6020
6045
|
on purpose: a proxy that forwards only `data:` lines would otherwise leave a `data.type`-dispatching
|
|
6021
6046
|
consumer unable to recognise the opener). Subsequent frames carry a core WorkflowEvent verbatim (its
|
|
6022
6047
|
`type` is the SSE event name). NOT resumable (replica-local, in-process; no id/Last-Event-ID).
|
|
6023
6048
|
`data` is permissive (core-internal, evolves).
|
|
6024
6049
|
🔴 There IS exactly one TERMINAL frame and it means FAILURE: `event: error` with
|
|
6025
6050
|
`data: {type:"error", errorCode:"workflow.stream_error", message:"workflow stream error"}`
|
|
6026
|
-
(`routes/workflows.ts
|
|
6051
|
+
(`routes/workflows.ts`). Branch on `errorCode` — NEVER anchor on `message`; the errorCode was added
|
|
6027
6052
|
precisely because consumers were otherwise forced to anchor prose or to conflate "the stream broke" with
|
|
6028
6053
|
"the stream ended normally", i.e. to report a FAILED workflow as finished. (Declared 2026-08-02.)
|
|
6029
|
-
Keep-alive is a REAL NAMED FRAME `event: heartbeat` / `data: {}` @15 s (
|
|
6054
|
+
Keep-alive is a REAL NAMED FRAME `event: heartbeat` / `data: {}` @15 s (`routes/workflows.ts`), not an SSE comment.
|
|
6030
6055
|
NOTE: on the wire this is SSE framing (event name + JSON data), not a JSON body — schema describes one
|
|
6031
6056
|
decoded frame.
|
|
6032
6057
|
required: [event, data]
|
|
@@ -6039,7 +6064,7 @@ components:
|
|
|
6039
6064
|
FleetTaskStatus:
|
|
6040
6065
|
type: string
|
|
6041
6066
|
description: >
|
|
6042
|
-
The fleet vocabulary the shell renders (service FleetTaskStatus, fleet-bus.ts
|
|
6067
|
+
The fleet vocabulary the shell renders (service FleetTaskStatus, fleet-bus.ts). The service maps its
|
|
6043
6068
|
run/workflow status onto this NEUTRAL set: `awaiting approval` = a needs-review/plan-approval park,
|
|
6044
6069
|
`waiting` = a durable suspend. CLOSED on the wire; render OPEN (branch known, fall back generically).
|
|
6045
6070
|
enum: [queued, running, waiting, stopping, 'awaiting approval', idle, completed, failed, killed]
|
|
@@ -6047,7 +6072,7 @@ components:
|
|
|
6047
6072
|
type: object
|
|
6048
6073
|
description: 'Upload receipt (POST /v1/attachments 201). `name` is the SANITIZED basename the server will materialize under `attachments/`.'
|
|
6049
6074
|
# 🔴 census 批2 五段(2026-07-30):CLOSED against the real emitter — `sendJson(res, 201, { id, name,
|
|
6050
|
-
# mime, sha256, sizeBytes })` (server attachments.ts
|
|
6075
|
+
# mime, sha256, sizeBytes })` (server attachments.ts) is an EXACT 5-key object literal, never a
|
|
6051
6076
|
# superset.
|
|
6052
6077
|
required: [id, name, mime, sha256, sizeBytes]
|
|
6053
6078
|
additionalProperties: false
|
|
@@ -6060,7 +6085,7 @@ components:
|
|
|
6060
6085
|
FleetTaskRow:
|
|
6061
6086
|
type: object
|
|
6062
6087
|
description: >
|
|
6063
|
-
One active task row (service FleetTaskRow fleet-bus.ts
|
|
6088
|
+
One active task row (service FleetTaskRow fleet-bus.ts) — MINUS the wire-STRIPPED `scope` (a
|
|
6064
6089
|
tenant-isolation field the service removes AFTER the owner-gate; never rendered, never on this wire). A
|
|
6065
6090
|
`task` frame carries the POST-MERGE FULL row → replace by `id`, NOT a sparse patch. A subagent child row
|
|
6066
6091
|
sets `parentId` (E2 parentToolCallId) + an id of `"<runId> <taskId>"`.
|
|
@@ -6125,14 +6150,14 @@ components:
|
|
|
6125
6150
|
FleetWorkflowRow:
|
|
6126
6151
|
type: object
|
|
6127
6152
|
description: >
|
|
6128
|
-
One workflow row (service FleetWorkflowRow fleet-bus.ts
|
|
6153
|
+
One workflow row (service FleetWorkflowRow fleet-bus.ts) — MINUS the wire-stripped `scope`. `status`
|
|
6129
6154
|
is the NEUTRAL workflow run status (running|completed|failed), open on read.
|
|
6130
6155
|
required: [id, name, status]
|
|
6131
6156
|
additionalProperties: true
|
|
6132
6157
|
properties:
|
|
6133
6158
|
# 🔴 FW-6(2026-08-02):这里此前有一个 `sourceLane` —— **幻影键,已删**。`sourceLane` 只在
|
|
6134
|
-
# `FleetTaskRow`(`src/fleet/fleet-bus.ts
|
|
6135
|
-
# `publishWorkflow`
|
|
6159
|
+
# `FleetTaskRow`(`src/fleet/fleet-bus.ts`)上,`FleetWorkflowRow` 全文没有它,
|
|
6160
|
+
# 同文件的 `publishWorkflow` 也从不写它;SDK 侧同样没有(SDK 是对的那一边)。
|
|
6136
6161
|
# 按它 codegen 的第三方会得到一个永远 undefined 的 `workflowRow.sourceLane`,并照 FleetTaskRow 那条
|
|
6137
6162
|
# 「run-leg composite rows only」的描述写出一个**永不触发**的 workflow 行去重分支。
|
|
6138
6163
|
id: { type: string }
|
|
@@ -6141,7 +6166,7 @@ components:
|
|
|
6141
6166
|
status: { type: string, description: 'Neutral workflow run status (running|completed|failed; open).' }
|
|
6142
6167
|
doneCount: { type: integer }
|
|
6143
6168
|
# 🔴 FW-6(2026-08-02):补上一个 server 真发、SDK 真声明、只有 spec 漏了的键。
|
|
6144
|
-
# `src/fleet/fleet-bus.ts
|
|
6169
|
+
# `src/fleet/fleet-bus.ts` 声明,`src/orchestration/workflow-notify-journal.ts` 真发。
|
|
6145
6170
|
startedCount: { type: integer, description: 'Agents actually STARTED (vs `totalCount` = planned, queued included). CC 2.1.220 的 `⚠ Large workflow` 规模告警用它当分母 —— 漏了它那条告警根本渲染不出来。' }
|
|
6146
6171
|
totalCount: { type: integer }
|
|
6147
6172
|
failedCount: { type: integer }
|
|
@@ -6179,7 +6204,7 @@ components:
|
|
|
6179
6204
|
hook_notice: '#/components/schemas/FleetFrame_hook_notice'
|
|
6180
6205
|
FleetFrame_meta:
|
|
6181
6206
|
type: object
|
|
6182
|
-
# 🔴 FW-10(2026-08-02):此前只声明三键,而铸造点 `src/http/routes/fleet.ts
|
|
6207
|
+
# 🔴 FW-10(2026-08-02):此前只声明三键,而铸造点 `src/http/routes/fleet.ts` **无条件**发五键 ——
|
|
6183
6208
|
# `sessionScoped` / `bgNotifyFailClosed` 不在任何条件分支里。这两个键正是「server 契约方复审 F1
|
|
6184
6209
|
# (行为错·最高)」的当事键:它们曾被一次白名单重构静默剥掉,导致 cli 的让位臂全程死代码。
|
|
6185
6210
|
# SDK 侧已上锁(`test/fleet.test.ts` 有专门的透传回归钉),spec 侧一直空白 —— 按 spec 生成的客户端
|
|
@@ -6334,8 +6359,8 @@ components:
|
|
|
6334
6359
|
type:
|
|
6335
6360
|
type: string
|
|
6336
6361
|
description: >
|
|
6337
|
-
契约调和车1 G(2026-08-02;server [2373]C-12, `src/trace/project.ts
|
|
6338
|
-
`routes/trace-usage.ts
|
|
6362
|
+
契约调和车1 G(2026-08-02;server [2373]C-12, `src/trace/project.ts` + the meta frame at
|
|
6363
|
+
`routes/trace-usage.ts`): the frame's own event name, DOUBLE-EMITTED inside `data`. Always
|
|
6339
6364
|
present on server >= 5.0.0; OPTIONAL here because the SDK's supported floor is server 3.0.0
|
|
6340
6365
|
(where only the `error` frame carried it). Equal to the SSE `event:` line verbatim — its reason
|
|
6341
6366
|
to exist is the proxy/relay case that strips the `event:` line and forwards only the data JSON,
|
|
@@ -6344,7 +6369,7 @@ components:
|
|
|
6344
6369
|
PendingList:
|
|
6345
6370
|
type: object
|
|
6346
6371
|
description: Envelope for pending HITL checkpoints (key `pending`, NOT a bare array — the pinned wire contract).
|
|
6347
|
-
# 封闭(census 轴一,2026-07-30):三个铸造点(routes/approvals-assistant.ts
|
|
6372
|
+
# 封闭(census 轴一,2026-07-30):三个铸造点(routes/approvals-assistant.ts)都只发
|
|
6348
6373
|
# `{ pending }`。行本身(`PendingCheckpoint`)保持开集(TS 侧索引签名)。
|
|
6349
6374
|
additionalProperties: false
|
|
6350
6375
|
required: [pending]
|
|
@@ -6357,7 +6382,7 @@ components:
|
|
|
6357
6382
|
type: object
|
|
6358
6383
|
description: Envelope for a session's approval exemptions (; key `exemptions`, NOT a bare array).
|
|
6359
6384
|
required: [exemptions]
|
|
6360
|
-
# 封闭:铸造点 `routes/approvals-assistant.ts
|
|
6385
|
+
# 封闭:铸造点 `routes/approvals-assistant.ts` 是单键字面量。
|
|
6361
6386
|
additionalProperties: false
|
|
6362
6387
|
properties:
|
|
6363
6388
|
exemptions:
|
|
@@ -6373,7 +6398,7 @@ components:
|
|
|
6373
6398
|
· the RESUMED-TASK shape (`http/server.ts` driveResumeIntoRunLog return) — `{taskId?, sessionId, status,
|
|
6374
6399
|
errorCode?, errorMessage?, retriable?}`, plus `rememberApplied` when the request carried
|
|
6375
6400
|
`remember:"session"` AND the worker has an exemption store;
|
|
6376
|
-
· the PARKED-BACKGROUND-AGENT shape (`parked-decide.ts
|
|
6401
|
+
· the PARKED-BACKGROUND-AGENT shape (`parked-decide.ts`, server >=1.267) — `{taskId, status:"resuming",
|
|
6377
6402
|
decision}`, an ACCEPTED (not completed) receipt; the revive drives asynchronously.
|
|
6378
6403
|
`status` is the only key BOTH shapes guarantee: `taskId` rides `getActiveTaskId` on the resumed leg (omitted
|
|
6379
6404
|
when there is no active row) and `sessionId` is absent from the parked shape.
|
|
@@ -6415,7 +6440,7 @@ components:
|
|
|
6415
6440
|
MEMORY only — deny/neverAuto always outrank it; it never loosens the session-policy layer.
|
|
6416
6441
|
required: [toolName, grantedBy, createdAt]
|
|
6417
6442
|
# 封闭:三个 store 实现(sql/pg/local)的 `list()` 都逐字铸这三键
|
|
6418
|
-
# (`plugins/approval-exemption-store.ts
|
|
6443
|
+
# (`plugins/approval-exemption-store.ts`),行不是原样透传的 DB 行。
|
|
6419
6444
|
additionalProperties: false
|
|
6420
6445
|
properties:
|
|
6421
6446
|
toolName: { type: string, description: Canonical tool name the exemption covers. }
|
|
@@ -6430,7 +6455,7 @@ components:
|
|
|
6430
6455
|
The `GET /v1/approvals` operator queue row (true shape). NEVER includes a capability token.
|
|
6431
6456
|
⚠️ `createdAt`/`deadline` are EPOCH MILLISECONDS (numbers), not ISO strings.
|
|
6432
6457
|
🔴 真矛盾撞获+纠正(2026-07-25,core [1640] 审计撞获 + server 复核确认 src/http/routes/approvals-assistant.ts→
|
|
6433
|
-
listPending() 真实实现 `src/plugins/tidb-checkpoint-store.ts
|
|
6458
|
+
listPending() 真实实现 `src/plugins/tidb-checkpoint-store.ts`):这份 schema 此前声称
|
|
6434
6459
|
"MIRRORS core CheckpointSummary,顶层 gateKind/severity,NEVER a riskDescriptor object"——
|
|
6435
6460
|
与真实实现完全相反。真实的 `PendingCheckpoint`(service 自定义类型,不是 core 的
|
|
6436
6461
|
`CheckpointSummary`)**没有 token 字段**(store 层注释:"deliberately NO token")、**没有
|
|
@@ -6559,7 +6584,7 @@ components:
|
|
|
6559
6584
|
type: object
|
|
6560
6585
|
description: 'ASSISTANT-WIRE-CONTRACT §2 — `GET /v1/assistant/inbox` envelope. Already severity-sorted by core.'
|
|
6561
6586
|
required: [inbox]
|
|
6562
|
-
# 封闭:铸造点 `routes/approvals-assistant.ts
|
|
6587
|
+
# 封闭:铸造点 `routes/approvals-assistant.ts` 是单键字面量(行本身 InboxRow 已封闭)。
|
|
6563
6588
|
additionalProperties: false
|
|
6564
6589
|
properties:
|
|
6565
6590
|
inbox:
|
|
@@ -6663,7 +6688,7 @@ components:
|
|
|
6663
6688
|
ASSISTANT-WIRE-CONTRACT §3 — `GET /v1/assistant/tasks` envelope. Triage-ordered by core (needs-attention
|
|
6664
6689
|
first, then severity DESC, then spend DESC). Empty `{tasks:[]}` when no TiDB run store.
|
|
6665
6690
|
required: [tasks]
|
|
6666
|
-
# 封闭:两个铸造点(`routes/approvals-assistant.ts
|
|
6691
|
+
# 封闭:两个铸造点(`routes/approvals-assistant.ts` 的无 run-store 空臂 + 正常臂)都是单键字面量。
|
|
6667
6692
|
additionalProperties: false
|
|
6668
6693
|
properties:
|
|
6669
6694
|
tasks:
|
|
@@ -6754,12 +6779,12 @@ components:
|
|
|
6754
6779
|
SessionSummary:
|
|
6755
6780
|
type: object
|
|
6756
6781
|
description: >
|
|
6757
|
-
E16 (shell-host sessionPicker; service SessionSummary tidb-run-store.ts
|
|
6782
|
+
E16 (shell-host sessionPicker; service SessionSummary tidb-run-store.ts) — a `GET /v1/sessions` list row
|
|
6758
6783
|
aggregating a session's run ledger (last activity + most-recent objective preview + status). owner-scoped.
|
|
6759
6784
|
All timestamps ISO. `objectivePreview` is service-redacted + truncated (genuinely `null` when no run).
|
|
6760
6785
|
required: [sessionId, owner, lastActivityAt, firstActivityAt, runCount, objectivePreview, lastStatus]
|
|
6761
|
-
# 🔴 封闭(census 批2 第二段,2026-07-30)。铸造点=`security.ts
|
|
6762
|
-
# 路由 `routes/sessions-list.ts
|
|
6786
|
+
# 🔴 封闭(census 批2 第二段,2026-07-30)。铸造点=`security.ts SessionListItem`,9 键逐字对上;
|
|
6787
|
+
# 路由 `routes/sessions-list.ts` 把 store 行**原样**放进 `sessions[]`(零投影),所以「多键」
|
|
6763
6788
|
# 只能来自 store 实现自己加字段 —— 那正是要抓的漂。`lastRunId`/`title` 刻意**不进 required**:
|
|
6764
6789
|
# 两者由 store 侧 SQL 投影(legacy `task_run` 聚合腿的 lister 不一定发),required 会把一条
|
|
6765
6790
|
# 合法的退化面响应判红。
|
|
@@ -6833,7 +6858,7 @@ components:
|
|
|
6833
6858
|
type: object
|
|
6834
6859
|
description: Keyset page envelope for `GET /v1/sessions`. `nextCursor` absent = last page.
|
|
6835
6860
|
required: [sessions]
|
|
6836
|
-
# 封闭:铸造点 `routes/sessions-list.ts
|
|
6861
|
+
# 封闭:铸造点 `routes/sessions-list.ts` 是逐字两键字面量(`nextCursor` 条件在场)。
|
|
6837
6862
|
additionalProperties: false
|
|
6838
6863
|
properties:
|
|
6839
6864
|
sessions:
|
|
@@ -6844,7 +6869,7 @@ components:
|
|
|
6844
6869
|
SessionPermissionRules:
|
|
6845
6870
|
type: object
|
|
6846
6871
|
description: >
|
|
6847
|
-
E6 (shell-host permissionMode; core SessionPermissionRules session-policy-store.ts
|
|
6872
|
+
E6 (shell-host permissionMode; core SessionPermissionRules session-policy-store.ts) — operator-tightened
|
|
6848
6873
|
per-session tool-permission rules (core reads them at prepare-time, SUBTRACT-only). 5 optional `string[]`
|
|
6849
6874
|
fields. tighten-only invariant is core-enforced (a loosen needs an operator).
|
|
6850
6875
|
properties:
|
|
@@ -6868,7 +6893,7 @@ components:
|
|
|
6868
6893
|
# SessionPermissionRules + 内联的 `rev`)声明的键不在它作用域内 ⇒ 只写 `false` 会把合法的
|
|
6869
6894
|
# `toolAllow`/`rev` 判成违约。镜像的一致性由 spec.test.ts 的通用「封闭 allOf 臂必须镜像被引
|
|
6870
6895
|
# schema 全部键」门看守(以后往 SessionPermissionRules 加键,忘了同步镜像就当场红)。
|
|
6871
|
-
# 为什么值得封闭:PUT 腿 `routes/sessions.ts
|
|
6896
|
+
# 为什么值得封闭:PUT 腿 `routes/sessions.ts` 只挑这 5 个已知字段落店,GET 腿回的是 store
|
|
6872
6897
|
# 原样 —— 「store 多回一个键」正是本门要抓的那类漂(消费方按 spec 生成的类型会漏掉它)。
|
|
6873
6898
|
additionalProperties: false
|
|
6874
6899
|
properties:
|
|
@@ -6882,10 +6907,10 @@ components:
|
|
|
6882
6907
|
McpServerStatus:
|
|
6883
6908
|
type: object
|
|
6884
6909
|
description: >
|
|
6885
|
-
E9 (shell-host mcpStatus; core McpServerStatus core/mcp.ts
|
|
6910
|
+
E9 (shell-host mcpStatus; core McpServerStatus core/mcp.ts) — one MCP server's status at materialization
|
|
6886
6911
|
time. `status` is connected | failed (core never emits disabled). `error` (failed only) is service-redacted
|
|
6887
6912
|
+ length-bounded.
|
|
6888
|
-
# 封闭三层(census 批2 第三段,2026-07-30):行铸造点 `routes/sessions.ts
|
|
6913
|
+
# 封闭三层(census 批2 第三段,2026-07-30):行铸造点 `routes/sessions.ts` 逐键条件展开这 5 键;
|
|
6889
6914
|
# `serverInfo` 不是透传——core 自己投影成两键字面量(core dist mcp.js:986 `{name, version}`)。
|
|
6890
6915
|
required: [name, status]
|
|
6891
6916
|
additionalProperties: false
|
|
@@ -6907,8 +6932,7 @@ components:
|
|
|
6907
6932
|
description: >
|
|
6908
6933
|
`GET /v1/sessions/:id/mcp` envelope. `asOf` = THIS materialization moment (ISO). `degraded:true` (servers
|
|
6909
6934
|
empty) ⇒ materialize timed out/failed (NOT "no MCP"). No MCP configured ⇒ `servers:[]` without `degraded`.
|
|
6910
|
-
# 封闭(census 批2 第三段,2026-07-30):三个铸造臂(`routes/sessions.ts
|
|
6911
|
-
# degraded / `:155-166` 正常)键集并集恰是这 3 键;degraded 只在超时臂铸。
|
|
6935
|
+
# 封闭(census 批2 第三段,2026-07-30):三个铸造臂(`routes/sessions.ts` 的空面板 / 超时 degraded / 正常)键集并集恰是这 3 键;degraded 只在超时臂铸。
|
|
6912
6936
|
required: [asOf, servers]
|
|
6913
6937
|
additionalProperties: false
|
|
6914
6938
|
properties:
|
|
@@ -6937,8 +6961,8 @@ components:
|
|
|
6937
6961
|
description: >
|
|
6938
6962
|
One E19 file snapshot keyed by a `SessionTreeEntry.id`. `manifest` = `[relPath, blobHash]` tuples; the blob
|
|
6939
6963
|
BYTES are NOT inlined (they ride the content-addressed blob routes).
|
|
6940
|
-
# 封闭(census 批2 第三段,2026-07-30):server 侧类型+铸造点(`session-sync.ts
|
|
6941
|
-
# `routes/session-sync.ts
|
|
6964
|
+
# 封闭(census 批2 第三段,2026-07-30):server 侧类型+铸造点(`session-sync.ts` PULL 出 /
|
|
6965
|
+
# `routes/session-sync.ts` PUSH 校验形)都恰是这两键。
|
|
6942
6966
|
additionalProperties: false
|
|
6943
6967
|
required: [key, manifest]
|
|
6944
6968
|
properties:
|
|
@@ -6955,7 +6979,7 @@ components:
|
|
|
6955
6979
|
SyncAnchor:
|
|
6956
6980
|
type: object
|
|
6957
6981
|
description: One E18 resume-at anchor. `owner` is RE-KEYED to the importing principal on a PUSH (§9).
|
|
6958
|
-
# 封闭(census 批2 第三段,2026-07-30):server 侧行类型 `session-sync.ts
|
|
6982
|
+
# 封闭(census 批2 第三段,2026-07-30):server 侧行类型 `session-sync.ts` 恰是这三键(owner 可 null 不可缺)。
|
|
6959
6983
|
additionalProperties: false
|
|
6960
6984
|
required: [eventId, entryId, owner]
|
|
6961
6985
|
properties:
|
|
@@ -6966,7 +6990,7 @@ components:
|
|
|
6966
6990
|
SessionRulesRecord:
|
|
6967
6991
|
type: object
|
|
6968
6992
|
description: A (principal, rules) policy record — one row across ALL principals (E6 `listBySession`). Replayed verbatim on import (the cloud applies the tighten-only gate).
|
|
6969
|
-
# 封闭(census 批2 第三段,2026-07-30):core `SessionRulesRecord`(session-policy-store.d.ts
|
|
6993
|
+
# 封闭(census 批2 第三段,2026-07-30):core `SessionRulesRecord`(session-policy-store.d.ts)恰是
|
|
6970
6994
|
# 这两键;`principal: undefined`(会话默认规则)在 JSON 里=整键省略。
|
|
6971
6995
|
additionalProperties: false
|
|
6972
6996
|
required: [rules]
|
|
@@ -6979,7 +7003,7 @@ components:
|
|
|
6979
7003
|
description: >
|
|
6980
7004
|
2c session-sync `GET …/sync/manifest` payload (wrapped server-side as `{ manifest }`). The THIN cross-backend
|
|
6981
7005
|
snapshot: entry IDS (oldest-first, NOT payloads) + per-snapshot relPath→blobHash + policy + anchors + leaf.
|
|
6982
|
-
# 封闭(census 批2 第三段,2026-07-30):铸造点 `session-sync.ts
|
|
7006
|
+
# 封闭(census 批2 第三段,2026-07-30):铸造点 `session-sync.ts`(exportSessionManifest 尾部
|
|
6983
7007
|
# 字面量)恰是这 7 键,全部无条件(leafId 缺席位=null 不省略)。
|
|
6984
7008
|
additionalProperties: false
|
|
6985
7009
|
required: [sessionId, entryIds, entryCount, leafId, snapshots, policy, anchors]
|
|
@@ -7011,7 +7035,7 @@ components:
|
|
|
7011
7035
|
§7 — how a SOURCE log relates to a DESTINATION log, decided over the entry-ID SETS. A discriminated union on
|
|
7012
7036
|
`relation`. `fresh`/`identical` carry nothing else; `fast_forward` the appended tail; `stale` the dst entries
|
|
7013
7037
|
the src lacks; `fork` the common ancestor + each side's exclusive ids.
|
|
7014
|
-
# 五臂全封闭(census 批2 第三段,2026-07-30):铸造点=分类器 `session-sync-kernel.ts
|
|
7038
|
+
# 五臂全封闭(census 批2 第三段,2026-07-30):铸造点=分类器 `session-sync-kernel.ts`,
|
|
7015
7039
|
# 五个 return 全是字面量,臂形与 core 导出的 `SyncRelation` 判别联合逐键一致。
|
|
7016
7040
|
oneOf:
|
|
7017
7041
|
- type: object
|
|
@@ -7056,8 +7080,8 @@ components:
|
|
|
7056
7080
|
description: >
|
|
7057
7081
|
`POST …/sync/import` Phase-A result. `identical` → no `stagingId` (skip Phase B); `fresh`/`fast_forward` →
|
|
7058
7082
|
`{ stagingId, relation }`. `relation` is the BARE classifier tag (not the full object).
|
|
7059
|
-
# 封闭(census 批2 第三段,2026-07-30):两个铸造臂——identical 臂 `routes/session-sync.ts
|
|
7060
|
-
# (relation+basis+payloadVerified,无 stagingId)/ staged 臂
|
|
7083
|
+
# 封闭(census 批2 第三段,2026-07-30):两个铸造臂——identical 臂 `routes/session-sync.ts`
|
|
7084
|
+
# (relation+basis+payloadVerified,无 stagingId)/ 同文件的 staged 臂(stagingId+relation)。
|
|
7061
7085
|
additionalProperties: false
|
|
7062
7086
|
required: [relation]
|
|
7063
7087
|
properties:
|
|
@@ -7068,7 +7092,7 @@ components:
|
|
|
7068
7092
|
type: string
|
|
7069
7093
|
# 🔴 census 批2 第三段(2026-07-30)spec 谎修正:`entry-ids+digest` 不是"将来值"——1.277.0 落
|
|
7070
7094
|
# digest 半场的**同一车**里铸造点就是 `basis: payloadVerified ? "entry-ids+digest" : "entry-ids"`
|
|
7071
|
-
# (routes/session-sync.ts
|
|
7095
|
+
# (routes/session-sync.ts),旧注却把它写成 x-open-enum 的假想例。补进闭集;x-open-enum 保留
|
|
7072
7096
|
# (真正的将来值仍按未知值降级)。
|
|
7073
7097
|
enum: [entry-ids, entry-ids+digest]
|
|
7074
7098
|
x-open-enum: true
|
|
@@ -7090,7 +7114,7 @@ components:
|
|
|
7090
7114
|
ImportCommitted:
|
|
7091
7115
|
type: object
|
|
7092
7116
|
description: '`POST …/sync/import/:stagingId/entries` (Phase B) commit result — the AUTHORITATIVE in-txn re-classify tag.'
|
|
7093
|
-
# 封闭(census 批2 第三段,2026-07-30):铸造点 `routes/session-sync.ts
|
|
7117
|
+
# 封闭(census 批2 第三段,2026-07-30):铸造点 `routes/session-sync.ts`(`{ relation: committed.relation }`)单键字面量。
|
|
7094
7118
|
additionalProperties: false
|
|
7095
7119
|
required: [relation]
|
|
7096
7120
|
properties:
|
|
@@ -7129,10 +7153,13 @@ components:
|
|
|
7129
7153
|
`quota_exhausted` (429 — the E4 fleet quota-LEASE budget, distinct from the cost quota).
|
|
7130
7154
|
NOTE: budget (`budget.precall`/`budget.exceeded`) and `cancelled` are RESULT-level codes on
|
|
7131
7155
|
TaskResult/RunRecord, NOT HTTP errors (pinned wire contract).
|
|
7132
|
-
🔴 STABLE PREFIX FAMILIES (wire-contract Appendix A, criterion 3) —
|
|
7156
|
+
🔴 STABLE PREFIX FAMILIES (wire-contract Appendix A, criterion 3) — ELEVEN prefixes are a stable
|
|
7133
7157
|
COARSE branch surface, so falling back on the prefix (unknown code → look at its prefix → only then
|
|
7134
|
-
at the status) is always safe: `auth.` `request.` `not_found.` `conflict.` `
|
|
7135
|
-
`feature.` `internal.` `state.`.
|
|
7158
|
+
at the status) is always safe: `auth.` `request.` `not_found.` `conflict.` `gone.` `parking.`
|
|
7159
|
+
`limit.` `capability.` `feature.` `internal.` `state.`. (`gone.` = 410, "the channel closed, switch
|
|
7160
|
+
channels"; `parking.` = 425, "intermediate state — you retry to learn the landing, not to re-submit".
|
|
7161
|
+
Both families, and both status codes, first reached the wire with server 7.3.0's in-stream approval
|
|
7162
|
+
decision endpoint.) The SDK maps each family to a typed class, so a code this SDK has
|
|
7136
7163
|
never seen still degrades INFORMATIVELY (e.g. a future `capability.xyz_required` already lands on
|
|
7137
7164
|
CapabilityUnavailableError). Family examples not named elsewhere in this document:
|
|
7138
7165
|
`request.payload_too_large` (413 — a field or the whole body is over the server cap; shorten and
|
|
@@ -7148,11 +7175,18 @@ components:
|
|
|
7148
7175
|
description: On a 409 — the task currently holding the session lock (see the Conflict response note).
|
|
7149
7176
|
|
|
7150
7177
|
# ── Streaming event taxonomy (the UX 命脉). Each SSE `data:` line is one JSON-serialized AgentEvent. ──
|
|
7151
|
-
# TWO vocabularies (the pinned wire contract Drift 3)
|
|
7178
|
+
# TWO vocabularies (the pinned wire contract Drift 3). ⚠️ The two lines below are the SHAPE-DEFINING
|
|
7179
|
+
# contrast (per-token deltas vs turn-aggregated), NOT an enumeration of either leg's arm set — the union
|
|
7180
|
+
# under `AgentEvent` below is the authoritative list, and each `Event_*` schema states its own legs.
|
|
7152
7181
|
# live (POST /v1/tasks/stream): text_delta / reasoning_delta (delta = string fragment, core-native)
|
|
7153
|
-
# +
|
|
7182
|
+
# + the lifecycle/tool/observation arms + the out-of-band NAMED frames
|
|
7183
|
+
# (question / elicitation / tool_approval / approval_request), which
|
|
7184
|
+
# interleave on the same connection but are NOT AgentEvent arms
|
|
7154
7185
|
# durable (GET /v1/runs/:id/events): text / reasoning (turn-AGGREGATED, no deltas)
|
|
7155
|
-
# +
|
|
7186
|
+
# + the same lifecycle/tool arms + the durable-only appends
|
|
7187
|
+
# (prompt_assembled / config_assembled / model_usage / suggestions /
|
|
7188
|
+
# needs_review / task_notification / diagnostics / workflow_complete)
|
|
7189
|
+
# + suspended/failed
|
|
7156
7190
|
AgentEvent:
|
|
7157
7191
|
oneOf:
|
|
7158
7192
|
- $ref: '#/components/schemas/Event_meta'
|
|
@@ -7198,6 +7232,16 @@ components:
|
|
|
7198
7232
|
# [2854] core 5.14.0 TaskEvent 16->18 (server 7.3.0 pickup): both new arms, projected.
|
|
7199
7233
|
- $ref: '#/components/schemas/Event_human_input'
|
|
7200
7234
|
- $ref: '#/components/schemas/Event_wiring_manifest'
|
|
7235
|
+
# 🔴 #185a (2026-08-08): the three APPROVAL arms of the DURABLE leg. They were replayed by
|
|
7236
|
+
# GET /v1/runs/:id/events all along (the server appends them and the read boundary re-emits
|
|
7237
|
+
# `{type, ...data}`) but neither this union nor the SDK's declared them, so a generated client
|
|
7238
|
+
# had no arm to switch on and dropped approval cards. Each arm is `allOf: [<the frame schema>, the
|
|
7239
|
+
# narrowed discriminant]` — the key set stays owned by ToolApprovalFrame / ApprovalRequestFrame,
|
|
7240
|
+
# so a frame gaining a key (7.5.0's governanceForced) needs no edit here.
|
|
7241
|
+
# `approval_revoke` is deliberately ABSENT: it is live-only and never appended.
|
|
7242
|
+
- $ref: '#/components/schemas/Event_tool_approval'
|
|
7243
|
+
- $ref: '#/components/schemas/Event_tool_approval_complete'
|
|
7244
|
+
- $ref: '#/components/schemas/Event_approval_request'
|
|
7201
7245
|
discriminator:
|
|
7202
7246
|
propertyName: type
|
|
7203
7247
|
mapping:
|
|
@@ -7236,15 +7280,18 @@ components:
|
|
|
7236
7280
|
workflow_complete: '#/components/schemas/Event_workflow_complete'
|
|
7237
7281
|
human_input: '#/components/schemas/Event_human_input'
|
|
7238
7282
|
wiring_manifest: '#/components/schemas/Event_wiring_manifest'
|
|
7283
|
+
tool_approval: '#/components/schemas/Event_tool_approval'
|
|
7284
|
+
tool_approval_complete: '#/components/schemas/Event_tool_approval_complete'
|
|
7285
|
+
approval_request: '#/components/schemas/Event_approval_request'
|
|
7239
7286
|
|
|
7240
7287
|
# design/99 §E2 (SHIPPED, core TaskEventIdentity) — additive per-event identity on every CONTENT event (NOT on
|
|
7241
7288
|
# the lifecycle arms turn_end/compacted/suspended/done/failed). eventId = uuidv7 dedup/resume handle (the durable
|
|
7242
|
-
# `text` re-stamps the turn's first text_delta eventId, runs.ts
|
|
7289
|
+
# `text` re-stamps the turn's first text_delta eventId, runs.ts); parentToolCallId = sub-agent attribution.
|
|
7243
7290
|
EventIdentity:
|
|
7244
7291
|
type: object
|
|
7245
7292
|
# 🔴 census 轴一(2026-07-30)亲读铸造点补的两键:LIVE 腿的白名单化 catch-all
|
|
7246
|
-
# (server `routes/tasks.ts
|
|
7247
|
-
# 传的是**四个** identity 键,而 durable 腿的 `identityFields`(trace/project.ts
|
|
7293
|
+
# (server `routes/tasks.ts`,text_delta / turn_end / message_committed / context_usage 四臂)
|
|
7294
|
+
# 传的是**四个** identity 键,而 durable 腿的 `identityFields`(trace/project.ts)只传前两个
|
|
7248
7295
|
# ——「两腿两策」是那段代码自己写下的口径。此前 spec 只声明两键 ⇒ 在封闭这些臂时会把真键判成违约。
|
|
7249
7296
|
# 声明面取两腿并集(逐臂再收窄不值当),缺席即缺席。
|
|
7250
7297
|
properties:
|
|
@@ -7260,7 +7307,7 @@ components:
|
|
|
7260
7307
|
condition: durable-ledger leg only (no ledger => neither header nor frame). sessionId rides along
|
|
7261
7308
|
(needed to bind subsequent turns when the server minted a fresh session). Always precedes any content
|
|
7262
7309
|
frame. NOT an engine event — server-minted, no EventIdentity.
|
|
7263
|
-
# 封闭:铸造点 routes/tasks.ts
|
|
7310
|
+
# 封闭:铸造点 routes/tasks.ts 是逐字写死的三键字面量(sessionId 条件在场)。
|
|
7264
7311
|
additionalProperties: false
|
|
7265
7312
|
required: [type, taskId]
|
|
7266
7313
|
properties:
|
|
@@ -7275,7 +7322,7 @@ components:
|
|
|
7275
7322
|
# `additionalProperties` 只认**同一个 subschema** 的 `properties`,`allOf` 分支($ref EventIdentity)
|
|
7276
7323
|
# 声明的键不在它的作用域内 —— 只写 `additionalProperties: false` 会把合法的 eventId 判成违约
|
|
7277
7324
|
# (draft-07 的 ajv 也不支持能跨 allOf 结算的 `unevaluatedProperties`,写了会被静默忽略 = 假绿)。
|
|
7278
|
-
# 镜像取两腿并集(超集,宁可漏抓不可假红);`$ref` 保留(spec.test.ts
|
|
7325
|
+
# 镜像取两腿并集(超集,宁可漏抓不可假红);`$ref` 保留(spec.test.ts 的 §E2 门要它)。
|
|
7279
7326
|
# 镜像与 EventIdentity 的一致性由 spec.test.ts 的「封闭臂必须镜像全部 identity 键」门看守。
|
|
7280
7327
|
additionalProperties: false
|
|
7281
7328
|
required: [type, text]
|
|
@@ -7334,7 +7381,7 @@ components:
|
|
|
7334
7381
|
type: { const: tool_start }
|
|
7335
7382
|
toolCallId: { type: string }
|
|
7336
7383
|
toolName: { type: string }
|
|
7337
|
-
# 🔴 census 轴一(2026-07-30)回填:server 白名单 builder `toolStartEventData`(trace/project.ts
|
|
7384
|
+
# 🔴 census 轴一(2026-07-30)回填:server 白名单 builder `toolStartEventData`(trace/project.ts)
|
|
7338
7385
|
# 真发 `label`(core 展示名,与 tool_end 同待遇),spec 此前漏声明 —— 封闭前必须先补,否则真帧变假红。
|
|
7339
7386
|
label: { type: string, description: 'core 展示名(缺席 ⇒ 用 toolName 渲染)。' }
|
|
7340
7387
|
args: {}
|
|
@@ -7356,7 +7403,7 @@ components:
|
|
|
7356
7403
|
type: { const: tool_end }
|
|
7357
7404
|
toolCallId: { type: string }
|
|
7358
7405
|
toolName: { type: string }
|
|
7359
|
-
# 🔴 census 轴一(2026-07-30)回填:`toolEndEventData`(trace/project.ts
|
|
7406
|
+
# 🔴 census 轴一(2026-07-30)回填:`toolEndEventData`(trace/project.ts)真发 `label` 与
|
|
7360
7407
|
# `structured`,spec 此前两者都漏 —— SDK 的 events.ts 早已声明,漂移只在 spec 这一侧。
|
|
7361
7408
|
label: { type: string, description: 'core 展示名(同 tool_start.label)。' }
|
|
7362
7409
|
structured: {} # core 1.203 CC 卡片明细;与 output 同一 UNTRUSTED RAW 待遇(已 redactDeep),形状开放
|
|
@@ -7370,7 +7417,7 @@ components:
|
|
|
7370
7417
|
bgAgentId: { type: string }
|
|
7371
7418
|
Event_turn_end:
|
|
7372
7419
|
type: object
|
|
7373
|
-
# 🔴 census 轴一(2026-07-30):`turn_end` 走 LIVE 腿的白名单 catch-all(routes/tasks.ts
|
|
7420
|
+
# 🔴 census 轴一(2026-07-30):`turn_end` 走 LIVE 腿的白名单 catch-all(routes/tasks.ts),该分支
|
|
7374
7421
|
# 对四个 identity 键做条件 spread —— 即「core 若真在 turn_end 上盖了 identity,它会上 wire」。
|
|
7375
7422
|
# 处置:**不** allOf EventIdentity(契约面继续不承诺生命周期臂带 identity,spec.test.ts §E2 那条钉
|
|
7376
7423
|
# 保持有效),但把四键作为本地可选属性声明出来,好让下面的封闭对那条真实代码路径不产生假红。
|
|
@@ -7399,7 +7446,7 @@ components:
|
|
|
7399
7446
|
cacheReadTokens: { type: integer }
|
|
7400
7447
|
cacheWriteTokens: { type: integer }
|
|
7401
7448
|
costMicroUsd: { type: integer }
|
|
7402
|
-
# 🔴 census 轴一(2026-07-30)回填:`turnEndEventData`(trace/project.ts
|
|
7449
|
+
# 🔴 census 轴一(2026-07-30)回填:`turnEndEventData`(trace/project.ts)是 2026-07-25 才补的
|
|
7403
7450
|
# builder,它带上来的这两键 spec 从未声明过 —— 而它们恰恰是**诚实缺席**语义的载体:
|
|
7404
7451
|
# `usageMissing` 缺了,「没有 usage」会被读成「用量是 0」而不是「未知」。
|
|
7405
7452
|
usageMissing: { const: true, description: '本轮用量不可信/缺失的诚实标记。缺席 ⇒ usage 可信。' }
|
|
@@ -7411,14 +7458,14 @@ components:
|
|
|
7411
7458
|
Event_compacted:
|
|
7412
7459
|
type: object
|
|
7413
7460
|
# 🔴 **刻意不封闭**(SDK events.ts 的 compacted 臂带 `[k: string]: unknown`),但 census 轴一
|
|
7414
|
-
# (2026-07-30)把 `compactedEventData`(trace/project.ts
|
|
7461
|
+
# (2026-07-30)把 `compactedEventData`(trace/project.ts)真发的键**全部登记**了一遍 ——
|
|
7415
7462
|
# 此前 spec 只有 tokensBefore 一键,连 fixture 天天在喂的 `trigger` 都不在声明面上。
|
|
7416
7463
|
additionalProperties: true
|
|
7417
7464
|
required: [type]
|
|
7418
7465
|
properties:
|
|
7419
7466
|
type: { const: compacted }
|
|
7420
7467
|
tokensBefore: { type: integer }
|
|
7421
|
-
trigger: { type: string, description: 'auto(逼近窗口上限)
|
|
7468
|
+
trigger: { type: string, description: '开集(engine-shaped,别当闭合枚举):`auto`(逼近窗口上限)/ `manual`(`POST /v1/runs/:id/compact`,发在该 run 自己的流上)/ `forced`(core ≥5.16.0 的 prompt-too-long 恢复腿)。缺席按 auto 渲染;未知值也按 auto 渲染,别崩。' }
|
|
7422
7469
|
preserved_segment:
|
|
7423
7470
|
type: object
|
|
7424
7471
|
required: [firstKeptEntryId]
|
|
@@ -7453,7 +7500,7 @@ components:
|
|
|
7453
7500
|
Event_suggestions:
|
|
7454
7501
|
type: object
|
|
7455
7502
|
description: >
|
|
7456
|
-
E12 (shell-host; service runs.ts
|
|
7503
|
+
E12 (shell-host; service runs.ts + src/http/routes/runs.ts, opt-in via `TaskRequest.suggestNextPrompts`) —
|
|
7457
7504
|
post-completion "what to ask next" prompt suggestions. Appended to the DURABLE run-events tail AFTER a
|
|
7458
7505
|
`done` with `status:"completed"` (core's fire-and-forget LLM pass). 🔴 UNTRUSTED model text, service-
|
|
7459
7506
|
redacted, UI-ONLY — render as clickable next-prompt chips; NEVER re-feed to a model. Empty/absent ⇒ none.
|
|
@@ -7499,7 +7546,7 @@ components:
|
|
|
7499
7546
|
CLIENT wire」已是 doc-rot,SDK events.ts 早已改口):server **确实**在三条腿上转发本臂
|
|
7500
7547
|
(`taskProgressEventData`,bg runs.ts append / resume append / 同步 live SSE),此外才是 fleet 子行。
|
|
7501
7548
|
allOf: [{ $ref: '#/components/schemas/EventIdentity' }]
|
|
7502
|
-
# 🔴 census 轴一(2026-07-30)三处纠正,依据=亲读 `taskProgressEventData`(trace/project.ts
|
|
7549
|
+
# 🔴 census 轴一(2026-07-30)三处纠正,依据=亲读 `taskProgressEventData`(trace/project.ts):
|
|
7503
7550
|
# ① required 过严 —— builder 里 `usage`/`status` 都是**条件 spread**,只有 `taskId` 无条件在场;
|
|
7504
7551
|
# spec 却把它们列进 required ⇒ 一个没带 usage 的真 tick 会被判违约(方向反了的假红)。
|
|
7505
7552
|
# ② `status` 写成 `const: running` 太窄 —— core [1414]#3 的 settle 终态 tick("completed"/"failed")
|
|
@@ -7741,8 +7788,8 @@ components:
|
|
|
7741
7788
|
Event_suspended:
|
|
7742
7789
|
type: object
|
|
7743
7790
|
description: HITL — the run paused on an F4 gate or AskUserQuestion. Resolve via approvals.decide, then resume.
|
|
7744
|
-
# 封闭(census 轴一,2026-07-30)。两个铸造点都是写死的字面量:server.ts
|
|
7745
|
-
# server.ts
|
|
7791
|
+
# 封闭(census 轴一,2026-07-30)。两个铸造点都是写死的字面量:server.ts `{gate}`、
|
|
7792
|
+
# server.ts `{gate:null, reopened}` —— 后者的 `reopened` 此前 spec 完全没有,是本次亲读补上的。
|
|
7746
7793
|
additionalProperties: false
|
|
7747
7794
|
required: [type]
|
|
7748
7795
|
properties:
|
|
@@ -7755,7 +7802,7 @@ components:
|
|
|
7755
7802
|
reopened:
|
|
7756
7803
|
type: ['string', 'null']
|
|
7757
7804
|
description: >
|
|
7758
|
-
server.ts
|
|
7805
|
+
server.ts —— 一条 resume 腿把 run 重新挂回 suspended 时,带上「为什么重开」的 errorCode
|
|
7759
7806
|
(无则显式 null)。只出现在这条重开臂上;普通挂起帧不带此键。
|
|
7760
7807
|
ModelUsageDelta:
|
|
7761
7808
|
# 新增(2026-07-25 回填批)。SDK 的 facade 审计把这个形状命名了一次(此前是在两个使用点各写一遍的匿名内联形:
|
|
@@ -7897,7 +7944,7 @@ components:
|
|
|
7897
7944
|
description: >
|
|
7898
7945
|
Per-model usage delta (live-verified on canary). `usage` is keyed BY MODEL NAME — same source as
|
|
7899
7946
|
`done.result.stats.modelUsage` (lets a multi-model / role-routed run attribute spend per model).
|
|
7900
|
-
# 封闭:铸造点 trace/project.ts
|
|
7947
|
+
# 封闭:铸造点 trace/project.ts `append("model_usage", { usage: delta })` 只有这一键
|
|
7901
7948
|
#(map 的**值**仍是开集 ModelUsageDelta —— 那层的「开」是真的,不动)。
|
|
7902
7949
|
additionalProperties: false
|
|
7903
7950
|
required: [type, usage]
|
|
@@ -7997,9 +8044,16 @@ components:
|
|
|
7997
8044
|
ToolApprovalFrame:
|
|
7998
8045
|
type: object
|
|
7999
8046
|
description: >
|
|
8000
|
-
|
|
8001
|
-
|
|
8002
|
-
|
|
8047
|
+
Tool-approval frame (SSE, `type` IS the event name). On the LIVE stream it interleaves out-of-band when
|
|
8048
|
+
TOOL_APPROVAL_ENABLED and is NOT an AgentEvent arm there (the live leg dispatches by SSE `event:` name).
|
|
8049
|
+
On the BACKGROUND/durable leg the server appends it to the events tail so it also replays through
|
|
8050
|
+
GET /v1/runs/:id/events — and there it IS a declared arm as of #185a, via `Event_tool_approval` /
|
|
8051
|
+
`Event_tool_approval_complete` (each = THIS schema plus the narrowed discriminant, so the keys live
|
|
8052
|
+
here only). Before #185a the durable response was typed solely as `AgentEvent` with no such arm: the
|
|
8053
|
+
payload carried `type` (the read boundary emits `{type, ...data}`) so runtime discrimination worked,
|
|
8054
|
+
but a generated client had nothing to switch on and dropped approval cards. That gap is closed.
|
|
8055
|
+
The shell renders `tool_approval` as the three-choice card and dismisses it on `tool_approval_complete`.
|
|
8056
|
+
Respond via POST /v1/tool-approvals/{approvalId}/respond.
|
|
8003
8057
|
required: [type, approvalId]
|
|
8004
8058
|
additionalProperties: true
|
|
8005
8059
|
properties:
|
|
@@ -8021,6 +8075,25 @@ components:
|
|
|
8021
8075
|
args:
|
|
8022
8076
|
description: '"tool_approval" only: the call''s args, secret-redacted. UNTRUSTED for display. Absent (with argsOmitted) when over the byte cap or unserializable.'
|
|
8023
8077
|
argsOmitted: { type: boolean, enum: [true] }
|
|
8078
|
+
governanceForced:
|
|
8079
|
+
type: boolean
|
|
8080
|
+
enum: [true]
|
|
8081
|
+
description: >
|
|
8082
|
+
"tool_approval" only, ADDITIVE, two-stage presence: ABSENT on server <= 7.4.0; from server >= 7.5.0
|
|
8083
|
+
([2942]/[2943]) present with value `true` when this ask's gate comes from the OPERATOR GOVERNANCE
|
|
8084
|
+
layer (the deployment-side AUTONOMY / commandPolicy / MANUAL_MODE_SHELL_GATE / SENSITIVE_WRITE_PATTERNS
|
|
8085
|
+
knobs) rather than from a model default gate or the request's own client permission posture.
|
|
8086
|
+
The only authority on presence is an observed frame, never a version string.
|
|
8087
|
+
|
|
8088
|
+
Use it to render a "forced by governance" badge: such a gate CANNOT be removed by a client posture,
|
|
8089
|
+
so the shell must present it as non-bypassable instead of pointing the user at `permissionMode`.
|
|
8090
|
+
|
|
8091
|
+
🔴 ABSENT != false (same discipline as the risk axes): the key is present ONLY when true. Absence
|
|
8092
|
+
means "no evidence of a governance origin" — it covers both genuinely non-governance asks (e.g. a tool
|
|
8093
|
+
listed in the deployment's APPROVAL_REQUIRE) AND shapes the server cannot discriminate (e.g. when the
|
|
8094
|
+
governance shell gate sits at the "classify" tier, a shell ask may come from the classifier or from
|
|
8095
|
+
another gate; the server leaves the key absent rather than guessing). Never render absence as
|
|
8096
|
+
"this gate can be bypassed by a posture".
|
|
8024
8097
|
fromSubagent:
|
|
8025
8098
|
type: boolean
|
|
8026
8099
|
enum: [true]
|
|
@@ -8029,20 +8102,36 @@ components:
|
|
|
8029
8102
|
type: string
|
|
8030
8103
|
description: 'Child''s core session id (same id domain as task_progress.taskId) — row-join value + fallback discriminator against a server predating fromSubagent.'
|
|
8031
8104
|
sourceAgentName: { type: string, description: 'Display name of the child agent, redacted. UNTRUSTED.' }
|
|
8105
|
+
delegation:
|
|
8106
|
+
type: object
|
|
8107
|
+
description: >
|
|
8108
|
+
core >= 5.9.0 W1 ([2535]), "tool_approval" only, ADDITIVE: the ask's DELEGATION provenance chain
|
|
8109
|
+
(the innermost grandchild frame wins). Present on the same door as `fromSubagent`. Read-only display
|
|
8110
|
+
enrichment; `agentName` is UNTRUSTED for display like `sourceAgentName`.
|
|
8111
|
+
additionalProperties: true
|
|
8112
|
+
required: [parentToolCallId, depth]
|
|
8113
|
+
properties:
|
|
8114
|
+
parentToolCallId: { type: string }
|
|
8115
|
+
depth: { type: integer }
|
|
8116
|
+
agentName: { type: string }
|
|
8032
8117
|
outcome:
|
|
8033
8118
|
type: string
|
|
8034
8119
|
enum: [allowed, denied, expired]
|
|
8035
|
-
description: '"tool_approval_complete" only. `expired` = TTL/abort/disconnect
|
|
8120
|
+
description: '"tool_approval_complete" only. Cosmetic dismiss reason. `expired` = TTL/abort/disconnect; what the ENGINE received for it DEPENDS on the deployment: where the design/172 ask ledger is on (server >= 7.3.0 under STREAM_APPROVAL_ENABLED) the server''s expireAsk CAS re-adjudicates the outcome to "unavailable" and the run PARKS; without that ledger the historical fail-closed DENY stands. Never derive the run''s fate from this frame.'
|
|
8036
8121
|
|
|
8037
|
-
# ── design/172 流内审批协议(#151
|
|
8122
|
+
# ── design/172 流内审批协议(#151)—— 已随 server 7.3.0 上线;开关 STREAM_APPROVAL_ENABLED 的默认值
|
|
8123
|
+
# 分两段:server ≤7.4.0 默认 OFF,≥7.5.0 默认 ON(BREAKING,见 server CHANGELOG)。──
|
|
8038
8124
|
# 与上面的 ToolApprovalFrame 是**并行加帧,不替换**:开关打开时同一只 ask 出两帧(先 tool_approval,
|
|
8039
8125
|
# 后 approval_request),两帧同带 `approvalId` ⇒ 消费端按它去重、优先渲染新帧。
|
|
8040
8126
|
ApprovalRequestFrame:
|
|
8041
8127
|
type: object
|
|
8042
8128
|
description: >
|
|
8043
|
-
IN-STREAM approval card (SSE, `type` IS the event name; design/172 §3.1).
|
|
8044
|
-
|
|
8045
|
-
|
|
8129
|
+
IN-STREAM approval card (SSE, `type` IS the event name; design/172 §3.1). TWO LEGS: on the LIVE token
|
|
8130
|
+
stream it is an out-of-band named frame (NOT an AgentEvent arm) interleaved like
|
|
8131
|
+
tool_approval/question/elicitation; on the DURABLE leg the server appends it, so the same frame replays
|
|
8132
|
+
through GET /v1/runs/:id/events — and there it IS registered, as the `Event_approval_request` arm
|
|
8133
|
+
(#185a; that arm allOf-refs THIS schema, so the keys are never restated).
|
|
8134
|
+
Settle it via POST /v1/tasks/{taskId}/asks/{askId}/decision.
|
|
8046
8135
|
|
|
8047
8136
|
WINDOW: `expiresAtMs` is cast ONCE and never recomputed; `expiresInMs` = max(0, expiresAtMs - serverNowMs)
|
|
8048
8137
|
and is therefore MONOTONICALLY DECREASING across replays — a reconnect NEVER renews the window.
|
|
@@ -8115,6 +8204,15 @@ components:
|
|
|
8115
8204
|
argsOmitted: { type: boolean, enum: [true], description: 'Present (true) only when args exceeded the byte cap. Never false.' }
|
|
8116
8205
|
toolCallId: { type: string, description: 'The engine''s tool-call id (the `call_…` on the assistant message''s tool_use block) — same domain as ToolApprovalFrame.toolCallId.' }
|
|
8117
8206
|
risk: { $ref: '#/components/schemas/ApprovalRiskAxes' }
|
|
8207
|
+
governanceForced:
|
|
8208
|
+
type: boolean
|
|
8209
|
+
enum: [true]
|
|
8210
|
+
description: >
|
|
8211
|
+
ADDITIVE, two-stage presence (ABSENT on server <= 7.4.0; present with `true` from server >= 7.5.0):
|
|
8212
|
+
this ask's gate comes from the OPERATOR GOVERNANCE layer and cannot be removed by a client permission
|
|
8213
|
+
posture. Semantics, the ABSENT != false clause and the discrimination boundary are stated verbatim on
|
|
8214
|
+
ToolApprovalFrame.governanceForced. It sits at the card's top level rather than inside `risk` because
|
|
8215
|
+
`risk` describes the ENGINE's judgement of the call, while this key says WHO imposed the gate.
|
|
8118
8216
|
fromSubagent: { type: boolean, enum: [true], description: 'Present ⇔ the ask comes from a DELEGATED child — the explicit discriminator (a worker cannot forge it).' }
|
|
8119
8217
|
sourceTaskId: { type: string, description: 'The child''s core session id — row-join value + fallback discriminator.' }
|
|
8120
8218
|
sourceAgentName: { type: string, description: 'The child agent''s display name, redacted. UNTRUSTED.' }
|
|
@@ -8344,8 +8442,14 @@ components:
|
|
|
8344
8442
|
QuestionFrame:
|
|
8345
8443
|
type: object
|
|
8346
8444
|
description: >
|
|
8347
|
-
|
|
8348
|
-
|
|
8445
|
+
AskUserQuestion frame (SSE, `type` IS the event name). TWO LEGS: on the LIVE stream it is an out-of-band
|
|
8446
|
+
named frame (NOT an AgentEvent arm); on the DURABLE leg the server persists it, so the same frame replays
|
|
8447
|
+
through GET /v1/runs/:id/events — and there it IS registered, as the closed `Event_question` /
|
|
8448
|
+
`Event_question_complete` arms (keep the key sets mirrored; a gate enforces it).
|
|
8449
|
+
Respond via POST /v1/questions/{questionId}/respond. 🔴 An UNANSWERED ask does NOT "fall back to the headless
|
|
8450
|
+
default" (server 7.4.0 / #166): the deployment reports `unavailable` ("nobody was reachable") and CORE
|
|
8451
|
+
picks the landing — a DURABLE leg PARKS a checkpoint for an operator to answer later, a non-durable leg
|
|
8452
|
+
continues on the `declined_unavailable` synthetic-continuation card. The run never hangs either way.
|
|
8349
8453
|
required: [type, questionId]
|
|
8350
8454
|
additionalProperties: true
|
|
8351
8455
|
properties:
|
|
@@ -8354,11 +8458,14 @@ components:
|
|
|
8354
8458
|
questions:
|
|
8355
8459
|
type: array
|
|
8356
8460
|
items: { $ref: '#/components/schemas/AskQuestion' }
|
|
8357
|
-
description: '"question" only: the model''s structured questions, secret-redacted. UNTRUSTED — never re-feed to a model. Absent on an over-cap payload
|
|
8461
|
+
description: '"question" only: the model''s structured questions, secret-redacted. UNTRUSTED — never re-feed to a model. Absent on an over-cap payload — and then NO frame is emitted at all: the ask reports `unavailable` (see this schema''s description).'
|
|
8358
8462
|
outcome:
|
|
8359
8463
|
type: string
|
|
8360
8464
|
enum: [answered, unanswered]
|
|
8361
|
-
description: '"question_complete" only: `answered` = a human responded; `unanswered` = ttl/abort/throttle released it (
|
|
8465
|
+
description: '"question_complete" only: `answered` = a human responded; `unanswered` = ttl/abort/throttle released it and core was told NOBODY WAS REACHABLE (`unavailable`) — on a durable deployment that PARKS rather than handing the model a default. Cosmetic dismiss reason only; never derive the run''s fate from it.'
|
|
8466
|
+
serverNowMs:
|
|
8467
|
+
type: integer
|
|
8468
|
+
description: 'server >= 7.3.0, ADDITIVE: the server-signed emit timestamp. A server-minted side-frame has no core-stream eventId to carry, so this is its own time coordinate. Absent on older servers.'
|
|
8362
8469
|
|
|
8363
8470
|
AskQuestion:
|
|
8364
8471
|
type: object
|
|
@@ -8385,8 +8492,11 @@ components:
|
|
|
8385
8492
|
ElicitationFrame:
|
|
8386
8493
|
type: object
|
|
8387
8494
|
description: >
|
|
8388
|
-
|
|
8389
|
-
|
|
8495
|
+
MCP elicitation frame (SSE, `type` IS the event name). TWO LEGS: on the LIVE stream it is an
|
|
8496
|
+
out-of-band named frame (NOT an AgentEvent arm); on the DURABLE leg the server persists it, so the same
|
|
8497
|
+
frame replays through GET /v1/runs/:id/events — and there it IS registered, as the closed
|
|
8498
|
+
`Event_elicitation` / `Event_elicitation_complete` arms (keep the key sets mirrored; a gate enforces it).
|
|
8499
|
+
Respond via POST /v1/elicitations/{elicitationId}/respond.
|
|
8390
8500
|
required: [type, elicitationId, mcpServerName]
|
|
8391
8501
|
additionalProperties: true
|
|
8392
8502
|
properties:
|
|
@@ -8403,6 +8513,9 @@ components:
|
|
|
8403
8513
|
type: string
|
|
8404
8514
|
enum: [accept, decline, cancel]
|
|
8405
8515
|
description: '"elicitation_complete" only: how it resolved (dialog dismiss reason).'
|
|
8516
|
+
serverNowMs:
|
|
8517
|
+
type: integer
|
|
8518
|
+
description: 'server >= 7.3.0, ADDITIVE: the server-signed emit timestamp. A server-minted side-frame carries no core-stream `eventId`, so this is its own time coordinate. Absent on older servers.'
|
|
8406
8519
|
|
|
8407
8520
|
Event_steering_injected:
|
|
8408
8521
|
type: object
|
|
@@ -8427,7 +8540,7 @@ components:
|
|
|
8427
8540
|
2026-08-02) — do NOT assume the full TaskResult:
|
|
8428
8541
|
· `TaskResult` — the normal terminal (output string at `.result`, stats at `.stats`), service Drift 4;
|
|
8429
8542
|
· `ActiveRunConflictDoneResult` — the SSE lane's REJECTION terminal: when the session already has an
|
|
8430
|
-
active run, the submit's 409 is encoded as this done frame (`src/http/routes/tasks.ts
|
|
8543
|
+
active run, the submit's 409 is encoded as this done frame (`src/http/routes/tasks.ts`), and it
|
|
8431
8544
|
carries NO `taskId` / `sessionId` / `stats`.
|
|
8432
8545
|
Narrow on the presence of `stats` (required on TaskResult, absent from the conflict shape), or on
|
|
8433
8546
|
`errorCode === "conflict.session_active_run"`. `status` does NOT discriminate — both shapes carry it.
|
|
@@ -8442,17 +8555,17 @@ components:
|
|
|
8442
8555
|
replay:
|
|
8443
8556
|
type: boolean
|
|
8444
8557
|
description: >
|
|
8445
|
-
契约调和车1 F(2026-08-02;server `src/http/routes/tasks.ts
|
|
8558
|
+
契约调和车1 F(2026-08-02;server `src/http/routes/tasks.ts` 的两处铸造点)— `true`
|
|
8446
8559
|
marks the IDEMPOTENT-REPLAY leg: this terminal was NOT produced by a live run of your submit. Either
|
|
8447
|
-
the `Idempotency-Key` hit the in-flight/settled cache
|
|
8448
|
-
concurrent identical submit and received no live events at all
|
|
8560
|
+
the `Idempotency-Key` hit the in-flight/settled cache, or your call was deduplicated into a
|
|
8561
|
+
concurrent identical submit and received no live events at all. The `result` is the original
|
|
8449
8562
|
run's terminal, verbatim. ABSENT on every live leg (never `false`) — a UI can use it to say "replayed"
|
|
8450
8563
|
instead of implying the work just ran twice.
|
|
8451
8564
|
|
|
8452
8565
|
ActiveRunConflictDoneResult:
|
|
8453
8566
|
type: object
|
|
8454
8567
|
description: >
|
|
8455
|
-
The SSE lane's REJECTION `done.result` (server `src/http/active-run-conflict.ts
|
|
8568
|
+
The SSE lane's REJECTION `done.result` (server `src/http/active-run-conflict.ts` `toDoneFrameResult`,
|
|
8456
8569
|
server >= 3.21). Same material as the 409 `conflict.session_active_run` body, minus the token-free
|
|
8457
8570
|
addressing rule's exceptions: a checkpoint token NEVER appears on the wire. It is NOT a TaskResult —
|
|
8458
8571
|
there is no run to report on, so `taskId`/`sessionId`/`stats` are structurally absent.
|
|
@@ -8499,11 +8612,11 @@ components:
|
|
|
8499
8612
|
|
|
8500
8613
|
# ══════════════════════════════════════════════════════════════════════════════════════════════
|
|
8501
8614
|
# 🔴 census 轴一(2026-07-30)补的**四个未登记臂**。它们不是「将来会有」——**今天就在 wire 上**:
|
|
8502
|
-
# · `context_usage` LIVE(routes/tasks.ts
|
|
8503
|
-
# · `config_assembled` DURABLE(trace/project.ts
|
|
8504
|
-
# · `needs_review` DURABLE(http/server.ts
|
|
8505
|
-
# · `message_committed` LIVE(routes/tasks.ts
|
|
8506
|
-
# durable 腿的读边界(routes/runs.ts
|
|
8615
|
+
# · `context_usage` LIVE(routes/tasks.ts)+ DURABLE(trace/ledger-sink.ts / server.ts)
|
|
8616
|
+
# · `config_assembled` DURABLE(trace/project.ts)
|
|
8617
|
+
# · `needs_review` DURABLE(http/server.ts)
|
|
8618
|
+
# · `message_committed` LIVE(routes/tasks.ts)
|
|
8619
|
+
# durable 腿的读边界(routes/runs.ts `formatEvent`)对**每一条**落库事件原样下发 `{type, ...data}`
|
|
8507
8620
|
# (唯一归一是 brain_status→status),所以「本仓 append 了什么」= 「wire 上会出现什么」。而本文件的
|
|
8508
8621
|
# `AgentEvent` 是闭集 oneOf ⇒ 一个真实的 context_usage 帧对着 spec 校验**当场零臂命中**。
|
|
8509
8622
|
# ⚠️ 元教训:`spec-union-arm-gate` 比的是 spec ↔ SDK 两侧的臂集,这四个臂**两侧同缺**,所以那道门
|
|
@@ -8512,7 +8625,7 @@ components:
|
|
|
8512
8625
|
Event_context_usage:
|
|
8513
8626
|
type: object
|
|
8514
8627
|
description: >
|
|
8515
|
-
core 1.414 first-class arm, whitelisted by `contextUsageEventData` (server trace/project.ts
|
|
8628
|
+
core 1.414 first-class arm, whitelisted by `contextUsageEventData` (server trace/project.ts).
|
|
8516
8629
|
🔴 Two engine-stated conventions, pass them through, never re-derive: (a) `usedTokens > compactAtTokens`
|
|
8517
8630
|
IS the predicate the engine itself feeds `shouldCompact`; (b) `windowTokens` is the AUTOCOMPACT window,
|
|
8518
8631
|
NOT the model's context size (rendering it as "model context" gives the user a wrong denominator).
|
|
@@ -8526,7 +8639,7 @@ components:
|
|
|
8526
8639
|
usedTokens: { type: integer }
|
|
8527
8640
|
windowTokens: { type: integer, description: 'autocompact 窗,不是模型上下文大小。' }
|
|
8528
8641
|
compactAtTokens: { type: integer }
|
|
8529
|
-
# LIVE 腿(routes/tasks.ts
|
|
8642
|
+
# LIVE 腿(routes/tasks.ts)在这条臂上挂 identity;durable 腿不挂。同 turn_end 的处置:
|
|
8530
8643
|
# 本地可选声明,不 allOf(不把 identity 承诺进契约面)。
|
|
8531
8644
|
eventId: { type: string }
|
|
8532
8645
|
parentToolCallId: { type: string }
|
|
@@ -8536,7 +8649,7 @@ components:
|
|
|
8536
8649
|
type: object
|
|
8537
8650
|
description: >
|
|
8538
8651
|
Compaction result frame ([2373]A-2, server 5.0.0 three-leg parity batch: live SSE + durable bg append +
|
|
8539
|
-
durable resume append all share one builder, `compactionOutcomeEventData`, server trace/project.ts
|
|
8652
|
+
durable resume append all share one builder, `compactionOutcomeEventData`, server trace/project.ts —
|
|
8540
8653
|
replays no longer drop it). `outcome`/`trigger` are engine-shaped passthrough strings coerced via
|
|
8541
8654
|
String(); `reason` is optional, secret-redacted. Identity: TWO keys only (`eventId`,
|
|
8542
8655
|
`parentToolCallId`) — this arm is NOT on the live-leg four-key whitelist that `context_usage` sits on
|
|
@@ -8555,7 +8668,7 @@ components:
|
|
|
8555
8668
|
Event_config_assembled:
|
|
8556
8669
|
type: object
|
|
8557
8670
|
description: >
|
|
8558
|
-
DURABLE only ([1301]③, server trace/project.ts
|
|
8671
|
+
DURABLE only ([1301]③, server trace/project.ts) — the per-turn companion record of `prompt_assembled`:
|
|
8559
8672
|
which config catalog version produced this turn's effective fields, and why anything was overridden.
|
|
8560
8673
|
Bounded frame: the builder DROPS the whole record over 32 KiB rather than shipping a truncated half-shape.
|
|
8561
8674
|
`fields` / `overrideReasons` are engine/registry-shaped passthrough — treat as opaque display data.
|
|
@@ -8570,7 +8683,7 @@ components:
|
|
|
8570
8683
|
Event_needs_review:
|
|
8571
8684
|
type: object
|
|
8572
8685
|
description: >
|
|
8573
|
-
DURABLE only (design/80 D-B, server http/server.ts
|
|
8686
|
+
DURABLE only (design/80 D-B, server http/server.ts) — a RESUMED plan_review leg got re-gated into
|
|
8574
8687
|
another review pause. Same payload shape as `suspended`: the gate verbatim, or an explicit `null`.
|
|
8575
8688
|
NOTE `needs_review` is BOTH a `RunStatus` terminal and a `CheckpointGate.kind`; this arm is the third
|
|
8576
8689
|
use of the name — the stream frame announcing that pause.
|
|
@@ -8586,7 +8699,7 @@ components:
|
|
|
8586
8699
|
Event_message_committed:
|
|
8587
8700
|
type: object
|
|
8588
8701
|
description: >
|
|
8589
|
-
LIVE only (server routes/tasks.ts
|
|
8702
|
+
LIVE only (server routes/tasks.ts, whitelisted in the same catch-all as text_delta/turn_end/
|
|
8590
8703
|
context_usage) — a session-history entry was committed. `entryId` is the durable entry handle the
|
|
8591
8704
|
R8 rewind anchor is keyed on ("rewind to the prompt" targets a `role:"user"` entry).
|
|
8592
8705
|
additionalProperties: false
|
|
@@ -8609,8 +8722,8 @@ components:
|
|
|
8609
8722
|
Event_error:
|
|
8610
8723
|
type: object
|
|
8611
8724
|
description: >
|
|
8612
|
-
STREAM-CONTROL frame, NOT a run failure (server src/http/sse-log.ts
|
|
8613
|
-
shape at routes/trace-usage.ts
|
|
8725
|
+
STREAM-CONTROL frame, NOT a run failure (server src/http/sse-log.ts; the trace leg emits the same
|
|
8726
|
+
shape at routes/trace-usage.ts). The server writes it as a NAMED frame (`event: error`) whose payload
|
|
8614
8727
|
echoes `type`, so both an `event:`-dispatching client and a payload-dispatching one see it.
|
|
8615
8728
|
🔴 Its arrival means the RUN IS STILL ALIVE — the 15-minute stream cap fired. The correct handling is to
|
|
8616
8729
|
RECONNECT with `Last-Event-ID` and keep reading (the durable leg stamps `id:` on every frame); rendering
|
|
@@ -8626,12 +8739,15 @@ components:
|
|
|
8626
8739
|
Event_question:
|
|
8627
8740
|
type: object
|
|
8628
8741
|
description: >
|
|
8629
|
-
AskUserQuestion OPEN frame (server src/question.ts
|
|
8630
|
-
event name (routes/tasks.ts
|
|
8631
|
-
DURABLE leg persists it via `append(type, rest)` (src/runs.ts
|
|
8742
|
+
AskUserQuestion OPEN frame (server src/question.ts `QuestionFrame`). The live leg dispatches it by SSE
|
|
8743
|
+
event name (routes/tasks.ts, the same out-of-band channel as `elicitation`/`tool_approval`); the
|
|
8744
|
+
DURABLE leg persists it via `append(type, rest)` (src/runs.ts), so the same frame also replays on
|
|
8632
8745
|
GET /v1/runs/:id/events — that half is what this schema registers.
|
|
8633
8746
|
🔴 UNTRUSTED-for-display: `questions` is secret-redacted, render only, NEVER re-feed to a model.
|
|
8634
|
-
`questions` absent ⇒ the payload exceeded the 16 KiB cap and was dropped
|
|
8747
|
+
`questions` absent ⇒ the payload exceeded the 16 KiB cap and was dropped — and then NO frame is emitted
|
|
8748
|
+
at all: the ask reports `unavailable` (server 7.4.0 / #166), which on a DURABLE deployment PARKS a
|
|
8749
|
+
checkpoint for an operator and on a non-durable one continues via the `declined_unavailable`
|
|
8750
|
+
synthetic-continuation card. It does NOT "headless-default".
|
|
8635
8751
|
additionalProperties: false
|
|
8636
8752
|
required: [type, questionId]
|
|
8637
8753
|
properties:
|
|
@@ -8640,22 +8756,38 @@ components:
|
|
|
8640
8756
|
questions:
|
|
8641
8757
|
type: array
|
|
8642
8758
|
items: { $ref: '#/components/schemas/AskQuestion' }
|
|
8759
|
+
serverNowMs:
|
|
8760
|
+
type: integer
|
|
8761
|
+
description: >
|
|
8762
|
+
server >= 7.3.0, ADDITIVE: the server-signed emit timestamp. A server-minted side-frame carries no
|
|
8763
|
+
core-stream `eventId`, so this is its own time coordinate. 🔴 It MUST be declared here: this schema
|
|
8764
|
+
is `additionalProperties: false`, so omitting a key the server really sends makes a strict validator
|
|
8765
|
+
reject a legitimate frame. Absent on servers < 7.3.0.
|
|
8643
8766
|
Event_question_complete:
|
|
8644
8767
|
type: object
|
|
8645
8768
|
description: >
|
|
8646
8769
|
AskUserQuestion CLOSE frame (dialog-dismiss signal). `answered` = a human responded; `unanswered` =
|
|
8647
|
-
ttl / abort / throttle released it and
|
|
8648
|
-
the
|
|
8770
|
+
ttl / abort / throttle released it and core was told NOBODY WAS REACHABLE (`unavailable`) — on a durable
|
|
8771
|
+
deployment that PARKS rather than handing the model a default (server 7.4.0 / #166; the old "the model
|
|
8772
|
+
got the headless default" reading is wrong). Cosmetic dismiss reason — it does not itself change the
|
|
8773
|
+
run's status, and the run's fate must never be derived from it.
|
|
8649
8774
|
additionalProperties: false
|
|
8650
8775
|
required: [type, questionId]
|
|
8651
8776
|
properties:
|
|
8652
8777
|
type: { const: question_complete }
|
|
8653
8778
|
questionId: { type: string }
|
|
8654
8779
|
outcome: { type: string, enum: [answered, unanswered] }
|
|
8780
|
+
serverNowMs:
|
|
8781
|
+
type: integer
|
|
8782
|
+
description: >
|
|
8783
|
+
server >= 7.3.0, ADDITIVE: the server-signed emit timestamp. A server-minted side-frame carries no
|
|
8784
|
+
core-stream `eventId`, so this is its own time coordinate. 🔴 It MUST be declared here: this schema
|
|
8785
|
+
is `additionalProperties: false`, so omitting a key the server really sends makes a strict validator
|
|
8786
|
+
reject a legitimate frame. Absent on servers < 7.3.0.
|
|
8655
8787
|
Event_elicitation:
|
|
8656
8788
|
type: object
|
|
8657
8789
|
description: >
|
|
8658
|
-
Inbound-MCP elicitation OPEN frame (server src/elicitation.ts
|
|
8790
|
+
Inbound-MCP elicitation OPEN frame (server src/elicitation.ts `ElicitationFrame`). Same two legs as
|
|
8659
8791
|
`question`: live dispatches by event name, the durable leg persists + replays it.
|
|
8660
8792
|
🔴 UNTRUSTED: `message` is fenced + secret-redacted; `requestedSchema` is an OPAQUE passthrough (never
|
|
8661
8793
|
interpreted/validated) and must still be fenced on display. v1 is always `mode: "form"` (url-mode is
|
|
@@ -8669,6 +8801,13 @@ components:
|
|
|
8669
8801
|
message: { type: string }
|
|
8670
8802
|
requestedSchema: {}
|
|
8671
8803
|
mode: { type: string, enum: [form] }
|
|
8804
|
+
serverNowMs:
|
|
8805
|
+
type: integer
|
|
8806
|
+
description: >
|
|
8807
|
+
server >= 7.3.0, ADDITIVE: the server-signed emit timestamp. A server-minted side-frame carries no
|
|
8808
|
+
core-stream `eventId`, so this is its own time coordinate. 🔴 It MUST be declared here: this schema
|
|
8809
|
+
is `additionalProperties: false`, so omitting a key the server really sends makes a strict validator
|
|
8810
|
+
reject a legitimate frame. Absent on servers < 7.3.0.
|
|
8672
8811
|
Event_elicitation_complete:
|
|
8673
8812
|
type: object
|
|
8674
8813
|
description: 'Inbound-MCP elicitation CLOSE frame; `action` is how it settled (the dialog-dismiss reason).'
|
|
@@ -8679,11 +8818,18 @@ components:
|
|
|
8679
8818
|
elicitationId: { type: string }
|
|
8680
8819
|
mcpServerName: { type: string }
|
|
8681
8820
|
action: { type: string, enum: [accept, decline, cancel] }
|
|
8821
|
+
serverNowMs:
|
|
8822
|
+
type: integer
|
|
8823
|
+
description: >
|
|
8824
|
+
server >= 7.3.0, ADDITIVE: the server-signed emit timestamp. A server-minted side-frame carries no
|
|
8825
|
+
core-stream `eventId`, so this is its own time coordinate. 🔴 It MUST be declared here: this schema
|
|
8826
|
+
is `additionalProperties: false`, so omitting a key the server really sends makes a strict validator
|
|
8827
|
+
reject a legitimate frame. Absent on servers < 7.3.0.
|
|
8682
8828
|
Event_workflow_complete:
|
|
8683
8829
|
type: object
|
|
8684
8830
|
description: >
|
|
8685
8831
|
Out-of-band delivery of an async workflow's completion (server
|
|
8686
|
-
src/orchestration/workflow-completion-inbox.ts
|
|
8832
|
+
src/orchestration/workflow-completion-inbox.ts). Delivery is STREAM-OPEN driven: the session's inbox
|
|
8687
8833
|
is drained on its NEXT leg — the sync leg writes a live frame, the bg/resume legs `append` it as a durable
|
|
8688
8834
|
event the tailing client replays.
|
|
8689
8835
|
🔴 AT-LEAST-ONCE (two-phase: the entry is acked only after a successful emit, and two legs racing the same
|
|
@@ -8697,6 +8843,67 @@ components:
|
|
|
8697
8843
|
status: { type: string }
|
|
8698
8844
|
summary: { type: string }
|
|
8699
8845
|
|
|
8846
|
+
# ── 🔴 #185a (2026-08-08): the DURABLE leg's three APPROVAL arms ────────────────────────────────
|
|
8847
|
+
# Shape rule for all three: `allOf: [<frame schema>, {the narrowed discriminant}]`. The keys are NOT
|
|
8848
|
+
# restated here — ToolApprovalFrame / ApprovalRequestFrame stay their single owner, so an additive
|
|
8849
|
+
# frame key (7.5.0's `governanceForced`) lands on the arm for free. The arms stay OPEN
|
|
8850
|
+
# (the frame schemas are `additionalProperties: true`), which is also why they need no local mirror
|
|
8851
|
+
# of the allOf branch keys (that duty only binds closed schemas).
|
|
8852
|
+
# Presence is CONDITIONAL and differs per family — an arm being declared says the payload's SHAPE,
|
|
8853
|
+
# never that the frame will arrive: `tool_approval*` needs TOOL_APPROVAL_ENABLED, `approval_request`
|
|
8854
|
+
# needs the design/172 protocol (server >= 7.3.0; default OFF <= 7.4.0 / ON >= 7.5.0, and the only
|
|
8855
|
+
# authority is the measured `capabilities.streamApproval` bit, never a version string).
|
|
8856
|
+
Event_tool_approval:
|
|
8857
|
+
description: >
|
|
8858
|
+
DURABLE-leg replay of the legacy tool-approval OPEN frame. Same payload as ToolApprovalFrame with the
|
|
8859
|
+
discriminant narrowed to `tool_approval`. Settle it via POST /v1/tool-approvals/{approvalId}/respond.
|
|
8860
|
+
Anchor the card on `toolCallId` (NOT `approvalId`); render `governanceForced` as a non-bypassable
|
|
8861
|
+
"forced by governance" badge. UNTRUSTED for display: `message`/`args` are redacted but model-authored.
|
|
8862
|
+
allOf:
|
|
8863
|
+
- $ref: '#/components/schemas/ToolApprovalFrame'
|
|
8864
|
+
- type: object
|
|
8865
|
+
required: [type]
|
|
8866
|
+
properties:
|
|
8867
|
+
type: { type: string, enum: [tool_approval] }
|
|
8868
|
+
Event_tool_approval_complete:
|
|
8869
|
+
description: >
|
|
8870
|
+
DURABLE-leg replay of the legacy tool-approval CLOSE frame (ToolApprovalFrame with the discriminant
|
|
8871
|
+
narrowed to `tool_approval_complete`). `outcome` is a COSMETIC dismiss reason: for `expired`, a
|
|
8872
|
+
deployment carrying the design/172 ask ledger re-adjudicates to "unavailable" and the run PARKS, while
|
|
8873
|
+
one without it keeps the historical fail-closed DENY. NEVER derive the run's fate from this frame.
|
|
8874
|
+
allOf:
|
|
8875
|
+
- $ref: '#/components/schemas/ToolApprovalFrame'
|
|
8876
|
+
- type: object
|
|
8877
|
+
required: [type]
|
|
8878
|
+
properties:
|
|
8879
|
+
type: { type: string, enum: [tool_approval_complete] }
|
|
8880
|
+
Event_approval_request:
|
|
8881
|
+
description: >
|
|
8882
|
+
The design/172 in-stream approval card as an AgentEvent arm. PARALLEL to `tool_approval`, not a
|
|
8883
|
+
replacement: with the protocol on, one ask emits BOTH frames (legacy first) carrying the SAME
|
|
8884
|
+
`approvalId` — dedupe on it and prefer this arm. The decision key is `askId`; settle via
|
|
8885
|
+
POST /v1/tasks/{taskId}/asks/{askId}/decision.
|
|
8886
|
+
|
|
8887
|
+
🔴 THIS ARM IS THE OPEN ENVELOPE, NOT `ApprovalRequestFrame`, AND THAT IS DELIBERATE. The v1 frame
|
|
8888
|
+
schema pins `schemaVersion: 1` and `kind: permission`, but a stream carries whatever the server sends:
|
|
8889
|
+
binding the arm to v1 would (a) make a generated client REJECT a legitimate future-version frame at the
|
|
8890
|
+
`oneOf`, and (b) tell a TypeScript/codegen consumer that `card` and its risk axes are guaranteed present
|
|
8891
|
+
on a frame that never validated as v1 — the exact bypass of the "unknown shapes get a GENERIC card,
|
|
8892
|
+
NEVER auto-deny" rule stated on ApprovalRequestFrame and ApprovalFrameEnvelope.
|
|
8893
|
+
⇒ Read this arm as the envelope, THEN check `schemaVersion == 1 && kind == "permission"` (SDK:
|
|
8894
|
+
`isApprovalRequestFrameV1`) before touching `card`/`askId`/the window keys — the validated v1 payload is
|
|
8895
|
+
described by `ApprovalRequestFrame`. If it does not validate, render the generic card.
|
|
8896
|
+
|
|
8897
|
+
🔴 A frame replayed from the durable events tail is for TIMELINE RENDERING ONLY, never a card-set
|
|
8898
|
+
baseline: its `expiresInMs` is frozen at mint time, and the full reconciliation baseline is the
|
|
8899
|
+
open-stream preamble.
|
|
8900
|
+
allOf:
|
|
8901
|
+
- $ref: '#/components/schemas/ApprovalFrameEnvelope'
|
|
8902
|
+
- type: object
|
|
8903
|
+
required: [type]
|
|
8904
|
+
properties:
|
|
8905
|
+
type: { type: string, enum: [approval_request] }
|
|
8906
|
+
|
|
8700
8907
|
# ── resources/*.ts schema backfill, batch 2 (2026-07-28) — the 28-item WIRE_PENDING ratchet zeroed.
|
|
8701
8908
|
# Each schema below is cross-checked against the server source (file:line cited in its description
|
|
8702
8909
|
# or in the SDK resource JSDoc it mirrors). Wire objects are OPEN sets (additionalProperties: true).
|
|
@@ -8727,7 +8934,7 @@ components:
|
|
|
8727
8934
|
description: >
|
|
8728
8935
|
The 200 body of POST /v1/approvals/{sessionId}/decide when the pending checkpoint belongs to a
|
|
8729
8936
|
PARKED background agent (server 1.267, ASSISTANT-WIRE-CONTRACT §4a parked variant; server
|
|
8730
|
-
parked-decide.ts
|
|
8937
|
+
parked-decide.ts — exact literal shape). ACCEPTANCE semantics: the revive drives
|
|
8731
8938
|
ASYNCHRONOUSLY — 200 means accepted, not completed; a failed drive honestly re-parks the row and
|
|
8732
8939
|
the pending re-appears on the list. Task-level suspends keep the legacy resumed shape —
|
|
8733
8940
|
discriminate by `status === "resuming"`.
|
|
@@ -8827,19 +9034,19 @@ components:
|
|
|
8827
9034
|
detail: { type: string, description: 'Redacted supplement (e.g. why skipped). Additive / tolerate-absent.' }
|
|
8828
9035
|
|
|
8829
9036
|
BakeStatus:
|
|
8830
|
-
# 新(census 批2 四段)——server `BakeStatus`(plugins/store-contracts.ts
|
|
9037
|
+
# 新(census 批2 四段)——server `BakeStatus`(plugins/store-contracts.ts), the COARSE lifecycle
|
|
8831
9038
|
# bakeView/claimResponse/bakesCreate all key on.
|
|
8832
9039
|
type: string
|
|
8833
9040
|
enum: [queued, running, done, failed]
|
|
8834
9041
|
|
|
8835
9042
|
BakeState:
|
|
8836
|
-
# 新(census 批2 四段)——server `BakeState`(store-contracts.ts
|
|
9043
|
+
# 新(census 批2 四段)——server `BakeState`(store-contracts.ts), build.sh's finer 8-value state;
|
|
8837
9044
|
# null before the runner's first `state` line lands.
|
|
8838
9045
|
type: [string, 'null']
|
|
8839
9046
|
enum: [PENDING, BUILDING, PUSHING, VERIFYING, REGISTERING, COMPLETE, FAILED, CANCELLED, null]
|
|
8840
9047
|
|
|
8841
9048
|
BakeErrorCode:
|
|
8842
|
-
# 新(census 批2 四段)——server `BakeErrorCode`(store-contracts.ts
|
|
9049
|
+
# 新(census 批2 四段)——server `BakeErrorCode`(store-contracts.ts), the closed structured terminal
|
|
8843
9050
|
# code set (§P2.14 #2); null = success or an uncategorized failure.
|
|
8844
9051
|
type: [string, 'null']
|
|
8845
9052
|
enum: [band-conflict, duplicate, disk, timeout, cancelled, null]
|
|
@@ -8875,7 +9082,7 @@ components:
|
|
|
8875
9082
|
|
|
8876
9083
|
BakeRecordView:
|
|
8877
9084
|
# 新(census 批2 四段)——GET /v1/images/bakes/{bakeId}'s `{ bake }` envelope. Exact key set = server
|
|
8878
|
-
# `bakeView()` (images.ts
|
|
9085
|
+
# `bakeView()` (images.ts): the durable BakeRecord MINUS the runner-internal secret/lease fields
|
|
8879
9086
|
# (ingestSecret/runnerId/leaseUntil/cancelRequested/argv — an ops surface, not the claim credential).
|
|
8880
9087
|
type: object
|
|
8881
9088
|
description: The operator poll view of one bake (server bakeView projection over the durable BakeRecord).
|
|
@@ -8908,7 +9115,7 @@ components:
|
|
|
8908
9115
|
|
|
8909
9116
|
BakeSubmitAck:
|
|
8910
9117
|
# 新(census 批2 四段)——POST /v1/images/bakes 202 body. All three code paths (attach-to-in-flight,
|
|
8911
|
-
# atomic-admission-created, dryRun) produce this SAME shape (images.ts
|
|
9118
|
+
# atomic-admission-created, dryRun) produce this SAME shape (images.ts).
|
|
8912
9119
|
type: object
|
|
8913
9120
|
description: Acknowledgement of a submitted/attached-to bake.
|
|
8914
9121
|
required: [bakeId, eventsUrl, status, state]
|
|
@@ -8920,7 +9127,7 @@ components:
|
|
|
8920
9127
|
state: { $ref: '#/components/schemas/BakeState' }
|
|
8921
9128
|
|
|
8922
9129
|
BakeCancelAck:
|
|
8923
|
-
# 新(census 批2 四段)——POST /v1/images/bakes/{bakeId}/cancel 202 body (images.ts
|
|
9130
|
+
# 新(census 批2 四段)——POST /v1/images/bakes/{bakeId}/cancel 202 body (images.ts). `note` is
|
|
8924
9131
|
# ALWAYS present (a ternary VALUE, not a conditional key) — the spec previously implied it was optional.
|
|
8925
9132
|
type: object
|
|
8926
9133
|
description: Cooperative-cancel acknowledgement (a durable flag; the runner kills the build at its next heartbeat).
|
|
@@ -8933,7 +9140,7 @@ components:
|
|
|
8933
9140
|
|
|
8934
9141
|
BakeIngestAck:
|
|
8935
9142
|
# 新(census 批2 四段)——POST /v1/images/bakes/{bakeId}/ingest 200 body. 🔴 FOUR distinct shapes share
|
|
8936
|
-
# this one status code (images.ts
|
|
9143
|
+
# this one status code (images.ts): a heartbeat ack carries no `seq`; a non-terminal frame ack
|
|
8937
9144
|
# carries `seq` but no `terminal`; a terminal `done` carries `terminal`+`indexId` (success) OR
|
|
8938
9145
|
# `terminal`+`needsFlip` (the bounded-retry-exhausted non-throw path, still 200 — the runner re-POSTs the
|
|
8939
9146
|
# idempotent done to re-drive the flip). `cancelRequested`+`leaseValid` ride on every non-heartbeat shape
|
|
@@ -9102,7 +9309,7 @@ components:
|
|
|
9102
9309
|
nextBefore?}`; server src/http/routes/sessions-list.ts — exact projection). A principal caller is PINNED to its
|
|
9103
9310
|
own scope (?scope= ignored); a fleet credential may pass ?scope= (default = the single-user
|
|
9104
9311
|
sentinel "_"). Page with `before` = a previous page's `nextBefore` (uuidv7; malformed → 400).
|
|
9105
|
-
# 🔴 census 批2 五段:CLOSED — exact projection (sessions-list.ts
|
|
9312
|
+
# 🔴 census 批2 五段:CLOSED — exact projection (sessions-list.ts); taskId/sessionId are the
|
|
9106
9313
|
# only OMIT-when-absent keys, no others.
|
|
9107
9314
|
required: [id, filename, size, ttlSec, track, bucket, key, createdAt]
|
|
9108
9315
|
additionalProperties: false
|
|
@@ -9123,7 +9330,7 @@ components:
|
|
|
9123
9330
|
enum: [now, next, later]
|
|
9124
9331
|
description: >-
|
|
9125
9332
|
[2400] TR-4 — per-message queue priority on POST /v1/runs/{taskId}/steer. ACCEPTED + ENUM-VALIDATED
|
|
9126
|
-
FAIL-LOUD (`routes/runs.ts
|
|
9333
|
+
FAIL-LOUD (`routes/runs.ts`; anything else is 400 `request.field_invalid`) and echoed back on the
|
|
9127
9334
|
receipt, but ADVISORY today: core's steer is a single-slot last-writer-wins with no per-message priority
|
|
9128
9335
|
or addressable drop, so a faithful priority queue (and DELETE /v1/runs/{taskId}/queue/{messageId}) waits
|
|
9129
9336
|
on a core seam.
|
|
@@ -9133,16 +9340,16 @@ components:
|
|
|
9133
9340
|
description: >
|
|
9134
9341
|
[2400] TR-4 — the POST /v1/runs/{taskId}/steer receipt, DISCRIMINATED on `delivery` (three server mint
|
|
9135
9342
|
points meaning three different things; branch on this, NOT on the status code):
|
|
9136
|
-
`applied` (200, `routes/runs.ts
|
|
9343
|
+
`applied` (200, `routes/runs.ts`) — injected into the run LIVE on this replica, drains at the next
|
|
9137
9344
|
turn boundary (`status:"running"`);
|
|
9138
|
-
`queued` (202
|
|
9345
|
+
`queued` (202) — the run is durably SUSPENDED, so the steer was PARKED on its pending checkpoint
|
|
9139
9346
|
and is injected on resume (`status:"suspended"`);
|
|
9140
|
-
`parked_for_wake` (202
|
|
9347
|
+
`parked_for_wake` (202) — the run already ENDED; the server minted a `task_done` checkpoint and
|
|
9141
9348
|
parked the message on it, delivered ONLY by POST /v1/sessions/{sessionId}/wake — nothing happens until
|
|
9142
9349
|
the session is woken.
|
|
9143
9350
|
`messageId` is server-minted and stable across all three (dedup / correlation handle).
|
|
9144
9351
|
required: [taskId, status, delivery, messageId]
|
|
9145
|
-
# 封闭:三个铸造点是逐字面量拼出来的对象(routes/runs.ts
|
|
9352
|
+
# 封闭:三个铸造点是逐字面量拼出来的对象(routes/runs.ts),不是引擎透传形。
|
|
9146
9353
|
additionalProperties: false
|
|
9147
9354
|
properties:
|
|
9148
9355
|
taskId: { type: string }
|
|
@@ -9176,8 +9383,7 @@ components:
|
|
|
9176
9383
|
TaskOutput-tool text (the child's final assistant body once terminal) — UNTRUSTED model output,
|
|
9177
9384
|
same posture as a run `result`. `output` = the engine registry's UnifiedTaskOutput projection
|
|
9178
9385
|
passed through VERBATIM.
|
|
9179
|
-
# 封闭(census 批2 第三段,2026-07-30):两个铸造点(`routes/runs.ts
|
|
9180
|
-
# 面 4 键 + 条件 `...g14`)顶层键集就是这 5 个。`output` 子对象**保持开**——它是 registry 投影的
|
|
9386
|
+
# 封闭(census 批2 第三段,2026-07-30):两个铸造点(`routes/runs.ts` 的窄面 4 键 / generic 面 4 键 + 条件 `...g14`)顶层键集就是这 5 个。`output` 子对象**保持开**——它是 registry 投影的
|
|
9181
9387
|
# verbatim 透传(deps 签名 `details: unknown`),不是 server 铸的形。
|
|
9182
9388
|
required: [taskId, target, content, output]
|
|
9183
9389
|
additionalProperties: false
|
|
@@ -9216,7 +9422,7 @@ components:
|
|
|
9216
9422
|
exact literal: `status:"running"`, `delivery:"accepted"`). ACCEPTANCE, not an outcome: compaction
|
|
9217
9423
|
runs at the next turn boundary and a `compacted{trigger:"manual"}` event rides the run stream ONLY
|
|
9218
9424
|
if anything was summarized (mooted/failed → no event).
|
|
9219
|
-
# 封闭 + required 补铸造点(census 批2 第三段,2026-07-30):唯一铸造点 `routes/runs.ts
|
|
9425
|
+
# 封闭 + required 补铸造点(census 批2 第三段,2026-07-30):唯一铸造点 `routes/runs.ts` 是
|
|
9220
9426
|
# 四键字面量,四键**全部无条件**——此前 required 只列 taskId,把恒在键写成了可缺。
|
|
9221
9427
|
required: [taskId, status, delivery, note]
|
|
9222
9428
|
additionalProperties: false
|
|
@@ -9233,7 +9439,7 @@ components:
|
|
|
9233
9439
|
`toolCallId` echoed, `delivery:"requested"`). Fire-and-forget: acceptance only — the
|
|
9234
9440
|
authoritative outcome is the tool call's own `tool_end.structured {detached:true, task_id}`;
|
|
9235
9441
|
a non-detachable env makes the request a fail-safe no-op.
|
|
9236
|
-
# 封闭 + required 补铸造点(census 批2 第三段,2026-07-30):唯一铸造点 `routes/runs.ts
|
|
9442
|
+
# 封闭 + required 补铸造点(census 批2 第三段,2026-07-30):唯一铸造点 `routes/runs.ts` 是
|
|
9237
9443
|
# 四键字面量,四键全部无条件(toolCallId=请求回显,body 校验过必在)。
|
|
9238
9444
|
required: [taskId, toolCallId, delivery, note]
|
|
9239
9445
|
additionalProperties: false
|
|
@@ -9321,10 +9527,10 @@ components:
|
|
|
9321
9527
|
ToolApprovalRespondAck:
|
|
9322
9528
|
type: object
|
|
9323
9529
|
description: >
|
|
9324
|
-
The 200 ack of POST /v1/tool-approvals/{approvalId}/respond (server tool-approval.ts
|
|
9530
|
+
The 200 ack of POST /v1/tool-approvals/{approvalId}/respond (server tool-approval.ts — exact
|
|
9325
9531
|
shape, `decision` echoed). Owner-gated with a 404 and NO existence oracle: non-owner and
|
|
9326
9532
|
unknown/settled/expired/wrong-replica ids are indistinguishable.
|
|
9327
|
-
# 封闭(census 批2 第三段,2026-07-30):铸造点 `tool-approval.ts
|
|
9533
|
+
# 封闭(census 批2 第三段,2026-07-30):铸造点 `tool-approval.ts` 三恒在键 + 两条件键
|
|
9328
9534
|
# (rememberApplied/updatedInputForwarded 的条件展开就在同一行字面量里),键集恰是这 5 个。
|
|
9329
9535
|
required: [approvalId, delivery, decision]
|
|
9330
9536
|
additionalProperties: false
|
|
@@ -9348,25 +9554,25 @@ components:
|
|
|
9348
9554
|
UsageMetric:
|
|
9349
9555
|
type: string
|
|
9350
9556
|
enum: [tasks, tokensIn, tokensOut, costUsd]
|
|
9351
|
-
description: 'The ?metric= axis of GET /v1/usage/series (server usage-analytics.ts
|
|
9557
|
+
description: 'The ?metric= axis of GET /v1/usage/series (server usage-analytics.ts). Default costUsd.'
|
|
9352
9558
|
|
|
9353
9559
|
UsageGranularity:
|
|
9354
9560
|
type: string
|
|
9355
9561
|
enum: [hour, day]
|
|
9356
|
-
description: 'The ?granularity= axis of GET /v1/usage/series (UTC buckets; server usage-analytics.ts
|
|
9562
|
+
description: 'The ?granularity= axis of GET /v1/usage/series (UTC buckets; server usage-analytics.ts). Default day.'
|
|
9357
9563
|
|
|
9358
9564
|
UsageDimension:
|
|
9359
9565
|
type: string
|
|
9360
9566
|
enum: [principal, model]
|
|
9361
9567
|
description: >
|
|
9362
|
-
The ?dimension= axis of GET /v1/usage/breakdown (server usage-analytics.ts
|
|
9568
|
+
The ?dimension= axis of GET /v1/usage/breakdown (server usage-analytics.ts). Default principal.
|
|
9363
9569
|
A JWT principal querying dimension=principal only ever sees its own bucket (owner is enforced
|
|
9364
9570
|
upstream — the semantics hold naturally, no leak surface).
|
|
9365
9571
|
|
|
9366
9572
|
UsageTotals:
|
|
9367
9573
|
type: object
|
|
9368
9574
|
description: >
|
|
9369
|
-
Window totals (server usage-analytics.ts
|
|
9575
|
+
Window totals (server usage-analytics.ts UsageTotals). tokensIn = Σ(inputTokens +
|
|
9370
9576
|
cacheReadTokens + cacheWriteTokens) — the billing view (cache hits count); tokensOut = Σ
|
|
9371
9577
|
outputTokens; costUsd = Σ costMicroUsd / 1e6 (authoritative micro-USD ledger, not an estimate).
|
|
9372
9578
|
required: [tasks, tokensIn, tokensOut, costUsd, estimated]
|
|
@@ -9401,9 +9607,9 @@ components:
|
|
|
9401
9607
|
allOf:
|
|
9402
9608
|
- $ref: '#/components/schemas/UsageWindowBase'
|
|
9403
9609
|
- $ref: '#/components/schemas/UsageTotals'
|
|
9404
|
-
# 🔴 封闭 + 本地镜像(census 批2 第二段,2026-07-30)。铸造点 `routes/trace-usage.ts
|
|
9610
|
+
# 🔴 封闭 + 本地镜像(census 批2 第二段,2026-07-30)。铸造点 `routes/trace-usage.ts` 逐字是
|
|
9405
9611
|
# `{ ...base, ...usageSummary(scan.rows) }`,两半都是本仓自己的字面量:`base` = from/to/truncated?
|
|
9406
|
-
# (
|
|
9612
|
+
# (`usage-analytics.ts`),`usageSummary` = `finish(UsageTotals)` 的五键(`usage-analytics.ts`)。
|
|
9407
9613
|
# 镜像的理由与 Event_reasoning 处那条长注逐字同一条(`additionalProperties` 不结算 allOf 分支);
|
|
9408
9614
|
# 一致性由 spec.test.ts 的通用「封闭 allOf 臂必须镜像被引 schema 全部键」门看守。
|
|
9409
9615
|
additionalProperties: false
|
|
@@ -9433,13 +9639,13 @@ components:
|
|
|
9433
9639
|
type: array
|
|
9434
9640
|
items:
|
|
9435
9641
|
type: object
|
|
9436
|
-
# 封闭:桶行铸造点 `usage-analytics.ts
|
|
9642
|
+
# 封闭:桶行铸造点 `usage-analytics.ts` 是两键字面量 `{ t, v }`。
|
|
9437
9643
|
additionalProperties: false
|
|
9438
9644
|
required: [t, v]
|
|
9439
9645
|
properties:
|
|
9440
9646
|
t: { type: string, description: 'ISO-8601 bucket start (UTC).' }
|
|
9441
9647
|
v: { type: number }
|
|
9442
|
-
# 封闭 + 本地镜像:铸造点 `routes/trace-usage.ts
|
|
9648
|
+
# 封闭 + 本地镜像:铸造点 `routes/trace-usage.ts` = `{ ...base, metric, granularity, series }`。见 UsageSummary 处的注。
|
|
9443
9649
|
additionalProperties: false
|
|
9444
9650
|
properties:
|
|
9445
9651
|
from: { type: string }
|
|
@@ -9471,7 +9677,7 @@ components:
|
|
|
9471
9677
|
properties:
|
|
9472
9678
|
key: { type: string, description: 'The bucket key (a principal or a model id).' }
|
|
9473
9679
|
- $ref: '#/components/schemas/UsageTotals'
|
|
9474
|
-
# 封闭 + 本地镜像:桶行铸造点 `usage-analytics.ts
|
|
9680
|
+
# 封闭 + 本地镜像:桶行铸造点 `usage-analytics.ts` 是 `{ key, ...UsageTotals }`。
|
|
9475
9681
|
additionalProperties: false
|
|
9476
9682
|
properties:
|
|
9477
9683
|
key: { type: string }
|
|
@@ -9480,7 +9686,7 @@ components:
|
|
|
9480
9686
|
tokensOut: { type: number }
|
|
9481
9687
|
costUsd: { type: number }
|
|
9482
9688
|
estimated: { type: boolean }
|
|
9483
|
-
# 封闭 + 本地镜像:铸造点 `routes/trace-usage.ts
|
|
9689
|
+
# 封闭 + 本地镜像:铸造点 `routes/trace-usage.ts` = `{ ...base, dimension, breakdown }`。见 UsageSummary 处的注。
|
|
9484
9690
|
additionalProperties: false
|
|
9485
9691
|
properties:
|
|
9486
9692
|
from: { type: string }
|
|
@@ -9496,7 +9702,7 @@ components:
|
|
|
9496
9702
|
exact literal: `status:"running"`, `delivery:"applied"`, `marker` = the engine-minted delivery
|
|
9497
9703
|
marker; NO `note`, unlike the run-subagent verb).
|
|
9498
9704
|
# 🔴 census 批2 五段:CLOSED — all 5 keys are unconditional in the literal
|
|
9499
|
-
# `{ runId: wfRunId, label, status: "running", delivery: "applied", marker }` (workflows.ts
|
|
9705
|
+
# `{ runId: wfRunId, label, status: "running", delivery: "applied", marker }` (workflows.ts);
|
|
9500
9706
|
# this schema previously existed but no path `$ref`'d it (see the path fix above).
|
|
9501
9707
|
required: [runId, label, status, delivery, marker]
|
|
9502
9708
|
additionalProperties: false
|
|
@@ -9513,7 +9719,7 @@ components:
|
|
|
9513
9719
|
# type)对方法返回位的内联形都是盲的 —— 于是它漏了这里一直标为 required 的 `sessionId`,CI 全绿。
|
|
9514
9720
|
type: object
|
|
9515
9721
|
description: >
|
|
9516
|
-
GET /v1/sessions/{sessionId}/workspace 的 200 信封(server src/http/routes/sessions.ts
|
|
9722
|
+
GET /v1/sessions/{sessionId}/workspace 的 200 信封(server src/http/routes/sessions.ts)。
|
|
9517
9723
|
⚠️ `total` = **本页行数**(`snapshots.length`),不是快照总数,且这条腿没有任何分页游标 —— 与同族
|
|
9518
9724
|
`WorkspaceTreePage.total`(真·全量)**同名反义**。`latest` 与展示行同源(防 ghost key)。
|
|
9519
9725
|
additionalProperties: false
|
|
@@ -9530,7 +9736,7 @@ components:
|
|
|
9530
9736
|
# 4.3.0(CAPS-OPS-8):同上,tree 腿的 200 信封。
|
|
9531
9737
|
type: object
|
|
9532
9738
|
description: >
|
|
9533
|
-
GET /v1/sessions/{sessionId}/workspace/{key}/tree 的 200 信封(server src/http/routes/sessions.ts
|
|
9739
|
+
GET /v1/sessions/{sessionId}/workspace/{key}/tree 的 200 信封(server src/http/routes/sessions.ts)。
|
|
9534
9740
|
`total` 在这条腿上是**全量**(`all.length`)—— 与 `WorkspaceSnapshotPage.total` 语义相反。
|
|
9535
9741
|
`key` 回的是解析后的真实键(请求可传 `latest` 别名)。
|
|
9536
9742
|
additionalProperties: false
|