@sema-agent/sdk 0.0.100 → 0.0.102
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/dist/client.d.ts +4 -2
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +4 -2
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts +57 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +126 -9
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +70 -8
- package/dist/types.d.ts.map +1 -1
- package/openapi.yaml +1194 -68
- package/package.json +1 -1
package/openapi.yaml
CHANGED
|
@@ -13,8 +13,29 @@ openapi: 3.1.0
|
|
|
13
13
|
# 测试锚定,是目前唯一真正贴合 server 当前实现的文档**。本文件保留作 M0 时代的历史参照(早期
|
|
14
14
|
# verb 清单/大致响应形状仍可读),但**任何具体字段名/是否顶层/是否为 optional 的判断,一律以
|
|
15
15
|
# types.ts 为准,本文件不可信**——已实证撞获至少一处两者互斥的真矛盾(`PendingCheckpoint`,
|
|
16
|
-
# 见下方该 schema 旁注)
|
|
17
|
-
#
|
|
16
|
+
# 见下方该 schema 旁注)。
|
|
17
|
+
#
|
|
18
|
+
# ── 状态更新(2026-07-25 回填批完成)────────────────────────────────────────────────────────
|
|
19
|
+
# 上面那句「回填 spec + 建反射式字段 diff 门是后续候办项,未完成前不要相信这里的字段级细节」
|
|
20
|
+
# **已经过时**。现状是:
|
|
21
|
+
# ✅ 反射式字段级 diff 门已建并**零容忍**:`packages/sdk/test/spec-field-drift-gate.test.ts`
|
|
22
|
+
# 用 TS 编译器 API 解析 `types.ts`(跟 extends / 解 Omit / Pick)× 解析本文件(递归展开
|
|
23
|
+
# `allOf`/`$ref`)逐字段比对。存量两族基线**都已清零**:字段级 drift 0、整 schema 缺席 0。
|
|
24
|
+
# ⇒ types.ts 加了字段而这里不加,CI 就红。**字段级细节现在有机器看守了。**
|
|
25
|
+
# ✅ 本批同时补了 3 条此前整条缺失的路径(`/v1/images`、`/v1/images/select`、
|
|
26
|
+
# `/v1/capabilities/scenarios/{name}`)、`AgentEvent` 缺的 6 个臂、`/v1/sessions/{id}` 的
|
|
27
|
+
# 5 个 query 参数,并修掉一处真错(`/v1/tasks/{id}/stream` 原先 $ref 到 `AgentEvent`,实际是
|
|
28
|
+
# `TraceStreamEvent` 词汇表 —— 本文件自己的两处声明互相矛盾)。
|
|
29
|
+
#
|
|
30
|
+
# 🔴 但**权威依然是 types.ts**,理由没变:本文件是手写的第二份声明,门只能保证"字段名集合一致",
|
|
31
|
+
# 保不了语义/可空性/枚举值。已知门**看不见**的三类(判断时请回 types.ts 或 server 源码):
|
|
32
|
+
# ① 枚举值陈旧 —— 本批就抓到 `AssistantTask.status` 少了 `needs_review`(真的一等 triage 态)。
|
|
33
|
+
# ② 联合缺臂 —— `AgentEvent` 曾少 6 臂;门只按"命名 schema ↔ 同名 interface"配对,联合对它不可见。
|
|
34
|
+
# ③ 层差 —— 本文件描述 **wire**(如 gate 的数值字段是显式 `null`),types.ts 描述 **SDK 归一后**
|
|
35
|
+
# (null 已在资源层折成省略键)。两者都对,不要互相"修正"。见 `AssistantGate` 旁注。
|
|
36
|
+
# 另仍有意留在覆盖外(**不是已覆盖**):`/v1/images` 前缀下的 register/:profile/digests 与整个
|
|
37
|
+
# bake 控制面(SDK 侧还用 `Record<string, unknown>`、没有具名类型 ⇒ 应先在 types.ts 具名);
|
|
38
|
+
# `SessionBundle` 目前是本文件里唯一的孤儿 schema(无人 $ref)。
|
|
18
39
|
#
|
|
19
40
|
# Consumed by @sema-agent/sdk (→ both doors: the CC/Codex MCP façade and the
|
|
20
41
|
# portal BFF). Producer = the service.
|
|
@@ -124,6 +145,37 @@ paths:
|
|
|
124
145
|
schema: { $ref: '#/components/schemas/Capabilities' }
|
|
125
146
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
126
147
|
|
|
148
|
+
# 补漏(2026-07-25):本路径此前完全不在本文件里,尽管 SDK 早有 `ScenarioDetail` 类型。形按 server 亲读取证。
|
|
149
|
+
/v1/capabilities/scenarios/{name}:
|
|
150
|
+
get:
|
|
151
|
+
tags: [metrics]
|
|
152
|
+
operationId: scenarioDetail
|
|
153
|
+
x-status: live
|
|
154
|
+
summary: One scenario's detail card.
|
|
155
|
+
description: >
|
|
156
|
+
The detail for a single scenario. The LIST of available names rides `capabilities().scenarios` — this
|
|
157
|
+
route only expands one. Auth = same as `/v1/capabilities` (config surface).
|
|
158
|
+
parameters:
|
|
159
|
+
- name: name
|
|
160
|
+
in: path
|
|
161
|
+
required: true
|
|
162
|
+
schema: { type: string }
|
|
163
|
+
description: 'the scenario name (as listed in `capabilities().scenarios`).'
|
|
164
|
+
responses:
|
|
165
|
+
'200':
|
|
166
|
+
description: The scenario detail card.
|
|
167
|
+
content:
|
|
168
|
+
application/json:
|
|
169
|
+
schema: { $ref: '#/components/schemas/ScenarioDetail' }
|
|
170
|
+
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
171
|
+
'404':
|
|
172
|
+
# 🔴 这条曾是全站唯一的**对象形** error(`{error:{code}}`),SDK 的 toApiError 为它特判过一轮。
|
|
173
|
+
# server 已统一为「字符串 error + 顶层 errorCode」的邻位形(同 cancel/decide),机器判据保留为 errorCode。
|
|
174
|
+
description: 'Unknown scenario — `{ error: "scenario not found", errorCode: "scenario_not_found" }`.'
|
|
175
|
+
content:
|
|
176
|
+
application/json:
|
|
177
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
178
|
+
|
|
127
179
|
/v1/memory:
|
|
128
180
|
parameters:
|
|
129
181
|
- $ref: '#/components/parameters/PrincipalHeader'
|
|
@@ -533,14 +585,71 @@ paths:
|
|
|
533
585
|
CURRENT model context (older history already folded into a summary message) — can be LARGE, the portal
|
|
534
586
|
should lazy-expand. Absent entirely on workers without the TiDB pool (capabilities.asyncRuns is the
|
|
535
587
|
practical same-prereq signal).
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
🔴 The 5 query params below are ADDITIVE: a request with NONE of them returns the byte-identical legacy
|
|
591
|
+
payload. `?message=` SHORT-CIRCUITS to a different response schema (`SessionMessageEnvelope`) — see below.
|
|
592
|
+
# 补漏(2026-07-25):此前本操作**一个 query 参数都没声明**,所以整个分页/截断/单条展开面对生成式消费方
|
|
593
|
+
# 等于不存在。以下 5 个按 server 亲读取证(`http/server.ts:5692-5723`)。
|
|
594
|
+
parameters:
|
|
595
|
+
- name: message
|
|
596
|
+
in: query
|
|
597
|
+
required: false
|
|
598
|
+
schema: { type: integer, minimum: 0 }
|
|
599
|
+
description: >
|
|
600
|
+
The single-message EXPAND leg: returns `SessionMessageEnvelope` (ONE full message body) instead of a
|
|
601
|
+
`SessionRecord`, and IGNORES the other params. Index is stable within one `floorEntryId` generation —
|
|
602
|
+
a compaction changes `floorEntryId` and invalidates held indices. Out-of-range → 404 (body carries
|
|
603
|
+
`total`). This is the companion of a `blobCap`-truncated read: expand = refetch that ONE message.
|
|
604
|
+
- name: tail
|
|
605
|
+
in: query
|
|
606
|
+
required: false
|
|
607
|
+
schema: { type: integer, minimum: 0 }
|
|
608
|
+
description: 'return the LAST N messages (+ a `window` `{offset,total}`).'
|
|
609
|
+
- name: before
|
|
610
|
+
in: query
|
|
611
|
+
required: false
|
|
612
|
+
schema: { type: integer, minimum: 0 }
|
|
613
|
+
description: 'return the page ABOVE a prior window offset (pair with `limit`).'
|
|
614
|
+
- name: limit
|
|
615
|
+
in: query
|
|
616
|
+
required: false
|
|
617
|
+
schema: { type: integer, minimum: 0 }
|
|
618
|
+
description: 'page size for the `tail`/`before` window. Ignored unless one of those is present.'
|
|
619
|
+
- name: blobCap
|
|
620
|
+
in: query
|
|
621
|
+
required: false
|
|
622
|
+
schema: { type: integer, minimum: 1 }
|
|
623
|
+
description: >
|
|
624
|
+
Truncate oversized string bodies to a preview and mark that message `truncated: true`. Only values
|
|
625
|
+
> 0 take effect. Expand a truncated message via `?message=<index>` (full size).
|
|
536
626
|
responses:
|
|
537
627
|
'200':
|
|
538
|
-
description:
|
|
628
|
+
description: >
|
|
629
|
+
A `SessionRecord` — or a `SessionMessageEnvelope` when `?message=` was supplied.
|
|
630
|
+
|
|
631
|
+
⚠️ Parameter parsing is LENIENT by construction: a non-numeric or NEGATIVE value is treated as
|
|
632
|
+
ABSENT, not as an error (so `?tail=-1` quietly returns the full record rather than a 400). A client
|
|
633
|
+
must not rely on a 400 to catch its own bad paging arithmetic.
|
|
539
634
|
content:
|
|
540
635
|
application/json:
|
|
541
|
-
schema:
|
|
636
|
+
schema:
|
|
637
|
+
oneOf:
|
|
638
|
+
- $ref: '#/components/schemas/SessionRecord'
|
|
639
|
+
- $ref: '#/components/schemas/SessionMessageEnvelope'
|
|
542
640
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
543
|
-
'404':
|
|
641
|
+
'404':
|
|
642
|
+
description: >
|
|
643
|
+
Non-owner / unknown session (no existence oracle) — or, with `?message=`, an out-of-range index, whose
|
|
644
|
+
body additionally carries `total`.
|
|
645
|
+
content:
|
|
646
|
+
application/json:
|
|
647
|
+
schema:
|
|
648
|
+
type: object
|
|
649
|
+
additionalProperties: true
|
|
650
|
+
properties:
|
|
651
|
+
error: { type: string }
|
|
652
|
+
total: { type: integer, description: 'present on the out-of-range `?message=` 404 — the message count available.' }
|
|
544
653
|
delete:
|
|
545
654
|
tags: [sessions]
|
|
546
655
|
operationId: sessionsDelete
|
|
@@ -1278,15 +1387,14 @@ paths:
|
|
|
1278
1387
|
Owner-gated (NOT D-G); non-owner → 404. SDK → GateNotResumableError on the 409.
|
|
1279
1388
|
responses:
|
|
1280
1389
|
'200':
|
|
1281
|
-
|
|
1390
|
+
# 2026-07-25:此前只声明 `{status}`。真体(`http/server.ts:7688-7696`,与 plan_review 共用
|
|
1391
|
+
# `driveResumeIntoRunLog`)带 taskId/sessionId + 失败态的 errorCode/errorMessage/retriable。
|
|
1392
|
+
description: >
|
|
1393
|
+
Resumed. 🔴 A 200 does NOT mean success — `status` can be `failed`, in which case `errorCode`/
|
|
1394
|
+
`errorMessage` say why and `retriable:true` means the park is STILL PENDING (decide again).
|
|
1282
1395
|
content:
|
|
1283
1396
|
application/json:
|
|
1284
|
-
schema:
|
|
1285
|
-
type: object
|
|
1286
|
-
required: [status]
|
|
1287
|
-
additionalProperties: true
|
|
1288
|
-
properties:
|
|
1289
|
-
status: { type: string }
|
|
1397
|
+
schema: { $ref: '#/components/schemas/AssistantTaskStatus' }
|
|
1290
1398
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
1291
1399
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
1292
1400
|
'409':
|
|
@@ -1321,15 +1429,13 @@ paths:
|
|
|
1321
1429
|
schema: { $ref: '#/components/schemas/PlanReviewRequest' }
|
|
1322
1430
|
responses:
|
|
1323
1431
|
'200':
|
|
1324
|
-
|
|
1432
|
+
# 2026-07-25:同 resume —— 两条共用 `driveResumeIntoRunLog`,响应体逐字相同。
|
|
1433
|
+
description: >
|
|
1434
|
+
Resolved. 🔴 A 200 does NOT mean success — see `status`/`errorCode`/`retriable` (same body as §4b
|
|
1435
|
+
resume; the two share one handler).
|
|
1325
1436
|
content:
|
|
1326
1437
|
application/json:
|
|
1327
|
-
schema:
|
|
1328
|
-
type: object
|
|
1329
|
-
required: [status]
|
|
1330
|
-
additionalProperties: true
|
|
1331
|
-
properties:
|
|
1332
|
-
status: { type: string }
|
|
1438
|
+
schema: { $ref: '#/components/schemas/AssistantTaskStatus' }
|
|
1333
1439
|
'400':
|
|
1334
1440
|
description: >
|
|
1335
1441
|
Bad/missing `decision`; `edit` without a non-empty `editedPlan`; `editedPlan` present on
|
|
@@ -1364,15 +1470,14 @@ paths:
|
|
|
1364
1470
|
`202` no-op; an already-`suspended` task → 409; `RESOURCE_SUSPEND` off → 501. Owner-gated; non-owner → 404.
|
|
1365
1471
|
responses:
|
|
1366
1472
|
'202':
|
|
1367
|
-
|
|
1473
|
+
# 2026-07-25:此前只声明 `{status}`。真体是 `{taskId, status, note}`(`http/server.ts` 三个 202 出口)。
|
|
1474
|
+
description: >
|
|
1475
|
+
Preempting — or an honest 202 NO-OP. ⚠️ `status` is NOT always `"preempting"`: the two no-op exits
|
|
1476
|
+
echo the run's own status instead (a non-preempt-eligible leg, or a task that already stopped
|
|
1477
|
+
running), and `note` says which case it was. Read `note`, do not assume the preempt took effect.
|
|
1368
1478
|
content:
|
|
1369
1479
|
application/json:
|
|
1370
|
-
schema:
|
|
1371
|
-
type: object
|
|
1372
|
-
required: [status]
|
|
1373
|
-
additionalProperties: true
|
|
1374
|
-
properties:
|
|
1375
|
-
status: { type: string }
|
|
1480
|
+
schema: { $ref: '#/components/schemas/AssistantTaskStatus' }
|
|
1376
1481
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
1377
1482
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
1378
1483
|
'409':
|
|
@@ -1472,10 +1577,20 @@ paths:
|
|
|
1472
1577
|
- $ref: '#/components/parameters/LastEventId'
|
|
1473
1578
|
responses:
|
|
1474
1579
|
'200':
|
|
1475
|
-
|
|
1580
|
+
# 🔴 修正(2026-07-25):此处原先 $ref 到 `AgentEvent`,是真错 —— 而且本文件自己就矛盾:专门为这条路写的
|
|
1581
|
+
# `TraceStreamEvent` schema 的描述里明写「A DISTINCT vocabulary from AgentEvent」,却没有任何地方引用它
|
|
1582
|
+
# (它是本文件里的一个孤儿 schema)。按 server 真码两侧取证后确定 TraceStreamEvent 才是对的:
|
|
1583
|
+
# `streamTaskTrace` 每帧走 `mapTraceEvent`(`trace/project.ts:530`),发的是 SSE **event 名**
|
|
1584
|
+
# `block-thinking-delta` / `block-content-delta` / `tool-call` / `tool-result` / `turn` /
|
|
1585
|
+
# `prompt-assembled` / `done` / `error`,帧里**没有** `type` 字段;SDK 的 `trace.stream()` 注释逐字同款。
|
|
1586
|
+
# 照旧声明生成的客户端会去 switch 一个不存在的 `type` ⇒ 这条流路对它完全不可用。
|
|
1587
|
+
# (AgentEvent 词汇表在 `GET /v1/runs/:id/events`,那条声明是对的 —— 两条是不同的面,别再混。)
|
|
1588
|
+
description: >
|
|
1589
|
+
Resumable SSE of the workspace LIVE timeline — the BLOCK-grained trace vocabulary
|
|
1590
|
+
(`TraceStreamEvent`), NOT the `AgentEvent` vocabulary of `/v1/runs/:id/events`.
|
|
1476
1591
|
content:
|
|
1477
1592
|
text/event-stream:
|
|
1478
|
-
schema: { $ref: '#/components/schemas/
|
|
1593
|
+
schema: { $ref: '#/components/schemas/TraceStreamEvent' }
|
|
1479
1594
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
1480
1595
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
1481
1596
|
|
|
@@ -1793,6 +1908,101 @@ paths:
|
|
|
1793
1908
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
1794
1909
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
1795
1910
|
|
|
1911
|
+
# ── sandbox 镜像目录(补漏 2026-07-25)──────────────────────────────────────────────────────────────
|
|
1912
|
+
# ⚠️ 诚实记下本次的**范围**:只补了带 SDK 具名类型的这两条读面(`ImageIndexEntry`/`ImageSelectResult`)。
|
|
1913
|
+
# server 的 `/v1/images` 前缀下还有 register / :profile / digests/:digest 以及整个 bake 控制面
|
|
1914
|
+
# (`/v1/images/bakes*`,operator 与 runner 两种主体),SDK 侧目前用 `Record<string, unknown>` 表达、
|
|
1915
|
+
# 没有具名类型 ⇒ 本批不进 spec(补它们等于在这里新发明一份契约,应当先在 types.ts 具名)。**不是已覆盖**。
|
|
1916
|
+
/v1/images:
|
|
1917
|
+
parameters:
|
|
1918
|
+
- $ref: '#/components/parameters/PrincipalHeader'
|
|
1919
|
+
get:
|
|
1920
|
+
tags: [sandbox]
|
|
1921
|
+
operationId: imagesList
|
|
1922
|
+
x-status: live
|
|
1923
|
+
summary: Paginated sandbox-image catalog (principal-scoped visibility).
|
|
1924
|
+
description: >
|
|
1925
|
+
The READ-ONLY data source for a "pick a sandbox template" UI. Visibility is scoped to the request
|
|
1926
|
+
principal by the server. Gated on a configured image index — otherwise the route is not mounted.
|
|
1927
|
+
Paginate with `nextCursor` and treat the cursor as OPAQUE (never parse or synthesize one).
|
|
1928
|
+
parameters:
|
|
1929
|
+
- { name: profile, in: query, required: false, schema: { type: string } }
|
|
1930
|
+
- { name: status, in: query, required: false, schema: { type: string, enum: [building, published, deprecated, failed] } }
|
|
1931
|
+
- { name: capability, in: query, required: false, schema: { type: string }, description: 'filter to images having this capability (e.g. `browser`).' }
|
|
1932
|
+
- { name: latest, in: query, required: false, schema: { type: string, enum: ['true'] }, description: 'string `"true"` ⇒ latest-per-profile only.' }
|
|
1933
|
+
- { name: limit, in: query, required: false, schema: { type: integer } }
|
|
1934
|
+
- { name: cursor, in: query, required: false, schema: { type: string }, description: 'echo `nextCursor` from the previous page verbatim.' }
|
|
1935
|
+
responses:
|
|
1936
|
+
'200':
|
|
1937
|
+
description: 'Catalog page — `{ images, nextCursor? }`.'
|
|
1938
|
+
content:
|
|
1939
|
+
application/json:
|
|
1940
|
+
schema:
|
|
1941
|
+
type: object
|
|
1942
|
+
required: [images]
|
|
1943
|
+
additionalProperties: true
|
|
1944
|
+
properties:
|
|
1945
|
+
images:
|
|
1946
|
+
type: array
|
|
1947
|
+
items: { $ref: '#/components/schemas/ImageIndexEntry' }
|
|
1948
|
+
nextCursor: { type: string, description: 'OPAQUE — pass back as `cursor`. Absent on the last page.' }
|
|
1949
|
+
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
1950
|
+
|
|
1951
|
+
/v1/images/select:
|
|
1952
|
+
parameters:
|
|
1953
|
+
- $ref: '#/components/parameters/PrincipalHeader'
|
|
1954
|
+
post:
|
|
1955
|
+
tags: [sandbox]
|
|
1956
|
+
operationId: imagesSelect
|
|
1957
|
+
x-status: live
|
|
1958
|
+
summary: Resolve a profile to its newest published digest (UI PREVIEW only).
|
|
1959
|
+
description: >
|
|
1960
|
+
Pure resolution, no build. 🔴 The result is a PREVIEW, NOT a binding credential: to actually run on this
|
|
1961
|
+
image, send `sandboxImageProfile` (a PROFILE) on the task request and let the server resolve + re-admit
|
|
1962
|
+
under a trusted principal. A caller that sends/caches/recomputes a digest turns a fail-closed admission
|
|
1963
|
+
into a fail-open one.
|
|
1964
|
+
requestBody:
|
|
1965
|
+
required: true
|
|
1966
|
+
content:
|
|
1967
|
+
application/json:
|
|
1968
|
+
schema:
|
|
1969
|
+
type: object
|
|
1970
|
+
required: [profile]
|
|
1971
|
+
additionalProperties: true
|
|
1972
|
+
properties:
|
|
1973
|
+
profile: { type: string, description: 'non-empty; missing/blank → 400.' }
|
|
1974
|
+
capabilitiesNeeded:
|
|
1975
|
+
type: array
|
|
1976
|
+
items: { type: string }
|
|
1977
|
+
description: 'capability names that MUST be satisfied by the resolved image, else 409.'
|
|
1978
|
+
responses:
|
|
1979
|
+
'200':
|
|
1980
|
+
description: The resolution preview.
|
|
1981
|
+
content:
|
|
1982
|
+
application/json:
|
|
1983
|
+
schema: { $ref: '#/components/schemas/ImageSelectResult' }
|
|
1984
|
+
'400':
|
|
1985
|
+
description: '`profile` missing/blank.'
|
|
1986
|
+
content:
|
|
1987
|
+
application/json:
|
|
1988
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
1989
|
+
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
1990
|
+
'404':
|
|
1991
|
+
description: 'No published image for that profile VISIBLE TO THIS PRINCIPAL (invisible and nonexistent are deliberately indistinguishable — no existence oracle).'
|
|
1992
|
+
content:
|
|
1993
|
+
application/json:
|
|
1994
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
1995
|
+
'409':
|
|
1996
|
+
description: 'The resolved image does not satisfy `capabilitiesNeeded` — body carries `missing[]`.'
|
|
1997
|
+
content:
|
|
1998
|
+
application/json:
|
|
1999
|
+
schema:
|
|
2000
|
+
type: object
|
|
2001
|
+
additionalProperties: true
|
|
2002
|
+
properties:
|
|
2003
|
+
error: { type: string }
|
|
2004
|
+
missing: { type: array, items: { type: string } }
|
|
2005
|
+
|
|
1796
2006
|
/metrics/summary:
|
|
1797
2007
|
get:
|
|
1798
2008
|
tags: [metrics]
|
|
@@ -1939,6 +2149,27 @@ components:
|
|
|
1939
2149
|
Primary routing axis (one image serves many; unknown → "default"). Selects model/tools/skills/prompt.
|
|
1940
2150
|
examples: ['default', 'oa', 'code-review', 'team']
|
|
1941
2151
|
|
|
2152
|
+
ScenarioDetail:
|
|
2153
|
+
# 新增(2026-07-25 回填批):`GET /v1/capabilities/scenarios/{name}` 此前**整条路径**都不在本文件里
|
|
2154
|
+
# (只有 `Capabilities.scenarios` 那个名字数组)。形按 server 亲读取证(`http/server.ts:1517-1527`)。
|
|
2155
|
+
type: object
|
|
2156
|
+
description: >
|
|
2157
|
+
One scenario's detail card (`GET /v1/capabilities/scenarios/{name}`). The LIST of names rides
|
|
2158
|
+
`Capabilities.scenarios` instead. `source`/`builtin` = builtin vs center-config overlay; `toolset` names
|
|
2159
|
+
the tool bundle while `tools` are the resolved tool names; `promptSummary` is a human-readable prompt
|
|
2160
|
+
DIGEST (never the full prompt); `enabled` = a center scenario can be declared-but-disabled.
|
|
2161
|
+
required: [name, source, builtin, summary, toolset, tools, promptSummary, enabled]
|
|
2162
|
+
additionalProperties: true
|
|
2163
|
+
properties:
|
|
2164
|
+
name: { type: string }
|
|
2165
|
+
source: { type: string, enum: [builtin, center] }
|
|
2166
|
+
builtin: { type: boolean }
|
|
2167
|
+
summary: { type: string }
|
|
2168
|
+
toolset: { type: string }
|
|
2169
|
+
tools: { type: array, items: { type: string } }
|
|
2170
|
+
promptSummary: { type: string, description: 'a human-readable prompt DIGEST — NOT the full prompt.' }
|
|
2171
|
+
enabled: { type: boolean }
|
|
2172
|
+
|
|
1942
2173
|
RunStatus:
|
|
1943
2174
|
type: string
|
|
1944
2175
|
enum: [running, completed, failed, suspended, needs_review]
|
|
@@ -1958,7 +2189,96 @@ components:
|
|
|
1958
2189
|
outputTokens: { type: integer }
|
|
1959
2190
|
costUsd: { type: number }
|
|
1960
2191
|
cacheHitRate: { type: number }
|
|
2192
|
+
toolCalls: { type: integer }
|
|
2193
|
+
cacheWriteTokens: { type: integer, description: Short-TTL cache-write tokens. }
|
|
2194
|
+
cacheWriteTokensLong: { type: integer, description: Long-TTL (1h) cache-write tokens, priced separately. }
|
|
2195
|
+
totalInputTokens:
|
|
2196
|
+
type: integer
|
|
2197
|
+
description: Normalized total input (prompt + cache reads) — the denominator most cost views want.
|
|
2198
|
+
costMicroUsd:
|
|
2199
|
+
type: integer
|
|
2200
|
+
description: >
|
|
2201
|
+
Integer micro-USD cost. Prefer this over the float `costUsd` for accounting (no FP drift). Both are
|
|
2202
|
+
emitted; they describe the same spend.
|
|
2203
|
+
costBreakdown:
|
|
2204
|
+
description: >
|
|
2205
|
+
Per-axis cost detail (LLM root / nested subagents / compaction / infra). Deliberately untyped — it is an
|
|
2206
|
+
OPEN map whose axes grow with the engine; read defensively rather than modelling it.
|
|
2207
|
+
humanReview:
|
|
2208
|
+
type: object
|
|
2209
|
+
description: MF-24 — human-in-the-loop wait ledger for this task (present once any gate was hit).
|
|
2210
|
+
required: [count, totalWaitMs, gates]
|
|
2211
|
+
properties:
|
|
2212
|
+
count: { type: integer }
|
|
2213
|
+
totalWaitMs: { type: integer }
|
|
2214
|
+
gates:
|
|
2215
|
+
type: array
|
|
2216
|
+
description: One row per gate. OPEN objects — engine may add keys.
|
|
2217
|
+
items:
|
|
2218
|
+
type: object
|
|
2219
|
+
required: [kind, waitMs]
|
|
2220
|
+
additionalProperties: true
|
|
2221
|
+
properties:
|
|
2222
|
+
kind: { type: string }
|
|
2223
|
+
waitMs: { type: integer }
|
|
2224
|
+
decision: { type: string }
|
|
2225
|
+
toolName: { type: string }
|
|
1961
2226
|
required: [turns, tokens]
|
|
2227
|
+
# 🔴 OPEN: the engine may carry fields not named here (live-observed, e.g. extra costBreakdown axes) — the SDK
|
|
2228
|
+
# passes them through rather than dropping, so consumers must not assume this list is exhaustive.
|
|
2229
|
+
additionalProperties: true
|
|
2230
|
+
|
|
2231
|
+
TaskAgentDefinition:
|
|
2232
|
+
# 新增(2026-07-25 回填批)—— 取代 `TaskRequest.agents.items` 的 OPEN 对象(理由见那里的旁注)。
|
|
2233
|
+
type: object
|
|
2234
|
+
description: >
|
|
2235
|
+
One per-task subagent definition (`TaskRequest.agents[]` item) — mirrors core `AgentDefinition` verbatim.
|
|
2236
|
+
🔴 The server WHITELISTS exactly these keys: anything else is a 400 on the strict lane (so an
|
|
2237
|
+
unrecognised key is a client bug, not a passthrough).
|
|
2238
|
+
required: [name]
|
|
2239
|
+
properties:
|
|
2240
|
+
name: { type: string, description: 'the `subagent_type` the model passes to Task. Non-empty, ≤64 chars, UNIQUE per request.' }
|
|
2241
|
+
whenToUse: { type: string, description: 'when the model should delegate to this agent (shown in the Task tool''s agent list). ≤4096 chars.' }
|
|
2242
|
+
whenToUseLean: { type: string, description: 'compact variant of `whenToUse` for lean tool listings. ≤4096 chars.' }
|
|
2243
|
+
allowTools: { type: array, items: { type: string }, description: 'allowlist of tool names. Omit ⇒ inherit ALL tools.' }
|
|
2244
|
+
denyTools: { type: array, items: { type: string }, description: 'denylist (SUBTRACTIVE — applied after `allowTools`).' }
|
|
2245
|
+
skills:
|
|
2246
|
+
type: array
|
|
2247
|
+
description: 'skills preloaded into the agent.'
|
|
2248
|
+
items:
|
|
2249
|
+
type: object
|
|
2250
|
+
required: [name, description, content]
|
|
2251
|
+
additionalProperties: true
|
|
2252
|
+
properties:
|
|
2253
|
+
name: { type: string }
|
|
2254
|
+
description: { type: string }
|
|
2255
|
+
content: { type: string }
|
|
2256
|
+
manifest: { type: object, additionalProperties: true }
|
|
2257
|
+
files:
|
|
2258
|
+
type: array
|
|
2259
|
+
items:
|
|
2260
|
+
type: object
|
|
2261
|
+
required: [path, content]
|
|
2262
|
+
additionalProperties: true
|
|
2263
|
+
properties: { path: { type: string }, content: { type: string } }
|
|
2264
|
+
background: { type: boolean, description: 'run the agent in the background (the parent turn continues).' }
|
|
2265
|
+
isolation: { type: string, enum: [worktree], description: '`worktree` = run the agent in an isolated git worktree.' }
|
|
2266
|
+
model:
|
|
2267
|
+
description: >
|
|
2268
|
+
Shell-resolved REAL model name/id — or a Model object with a string `id`. 🔴 NOT an alias: the server
|
|
2269
|
+
does no translation. Omit ⇒ inherit the parent model.
|
|
2270
|
+
oneOf:
|
|
2271
|
+
- type: string
|
|
2272
|
+
- type: object
|
|
2273
|
+
required: [id]
|
|
2274
|
+
additionalProperties: true
|
|
2275
|
+
properties: { id: { type: string } }
|
|
2276
|
+
thinking: { type: string, enum: [off, minimal, low, medium, high, xhigh, max] }
|
|
2277
|
+
systemPrompt: { type: string, description: 'the agent''s system prompt. ≤65536 chars.' }
|
|
2278
|
+
maxTurns: { type: integer, minimum: 1, description: 'max agent turns before the subagent is stopped.' }
|
|
2279
|
+
memory: { type: object, additionalProperties: true, description: 'memory spec (`{ scope?, scopes?, writeScope?, enabled?, scopeContract? }`).' }
|
|
2280
|
+
observer: { type: string, description: 'observer prompt (agent-observes-agent lane). ≤4096 chars.' }
|
|
2281
|
+
observerMessage: { type: string, description: 'message template the observer sends. ≤4096 chars.' }
|
|
1962
2282
|
|
|
1963
2283
|
TaskRequest:
|
|
1964
2284
|
type: object
|
|
@@ -2086,6 +2406,97 @@ components:
|
|
|
2086
2406
|
properties:
|
|
2087
2407
|
count: { type: integer }
|
|
2088
2408
|
role: { type: string, description: A model role name. }
|
|
2409
|
+
compactionModel:
|
|
2410
|
+
type: string
|
|
2411
|
+
description: >
|
|
2412
|
+
Pin a SEPARATE (usually cheaper) model for compaction. Validated against the catalog on submit — an
|
|
2413
|
+
unknown ref is a 400, not a silent fallback to the main model's price.
|
|
2414
|
+
appendSystemPrompt: { type: string, description: Text appended to the assembled system prompt for this task. }
|
|
2415
|
+
promptProfile:
|
|
2416
|
+
type: string
|
|
2417
|
+
enum: [simple, classic]
|
|
2418
|
+
description: Which prompt-assembly profile to use.
|
|
2419
|
+
clientContext:
|
|
2420
|
+
type: object
|
|
2421
|
+
description: Non-authoritative client hints (never trusted for authz).
|
|
2422
|
+
properties:
|
|
2423
|
+
timeZone: { type: string }
|
|
2424
|
+
userEmail: { type: string }
|
|
2425
|
+
sandboxImageProfile: { type: string, description: Sandbox image profile name for the execution env. }
|
|
2426
|
+
capabilitiesNeeded:
|
|
2427
|
+
type: array
|
|
2428
|
+
items: { type: string }
|
|
2429
|
+
description: Capability names the caller requires; the worker refuses up front rather than 501-ing mid-run.
|
|
2430
|
+
memoryWrite: { type: boolean, description: Allow this task to WRITE user memory (read is governed separately). }
|
|
2431
|
+
settings:
|
|
2432
|
+
type: object
|
|
2433
|
+
description: >
|
|
2434
|
+
TOC `settings.json` contract carried to the worker (CC-parity v1: permissions/hooks/env/model/
|
|
2435
|
+
outputStyle). The SDK owns the schema in `src/settings.ts` (`SemaSettings`) — it is deliberately NOT
|
|
2436
|
+
duplicated here as a component: the service passes it through to core rather than interpreting it, so
|
|
2437
|
+
the TS type is the single authority. OPEN object.
|
|
2438
|
+
additionalProperties: true
|
|
2439
|
+
cwd: { type: string, description: Working directory for the execution env. }
|
|
2440
|
+
selfOrchestration: { type: boolean, description: Permit S8 self-orchestration (run_workflow) inside this task. }
|
|
2441
|
+
enableFork: { type: boolean, description: Permit session forking from inside this task. }
|
|
2442
|
+
# 原注是「形状归 SDK 的 TaskAgentDefinition 所有,这里刻意保持 OPEN 而不重复一遍」。2026-07-25 推翻该选择,
|
|
2443
|
+
# 理由是那条推理只对 TS 消费方成立:TS 消费方本来就 import 得到 `TaskAgentDefinition`,从本文件生成客户端的
|
|
2444
|
+
# 消费方(本文件存在的全部意义)拿到的却是一个「任意键的对象」——而这是**请求体**,写错键会被 server 的严格
|
|
2445
|
+
# 通道 400 掉,恰恰是最需要 schema 的地方。⚠️ 代价诚实记下:这确实成了第二处需要跟着 core `AgentDefinition`
|
|
2446
|
+
# 走的声明。因此反射式 drift 门(`test/spec-field-drift-gate.test.ts`)把 `TaskAgentDefinition` 纳入了逐字段
|
|
2447
|
+
# 比对 —— types.ts 加字段而这里不加,门就会红。这就是"重复"这次可以接受的原因:它被机器看住了。
|
|
2448
|
+
agents:
|
|
2449
|
+
type: array
|
|
2450
|
+
items: { $ref: '#/components/schemas/TaskAgentDefinition' }
|
|
2451
|
+
description: Per-task sub-agent definitions (roster additions scoped to this task only).
|
|
2452
|
+
interactiveTools: { type: boolean, description: Mount interactive (prompting) tools. }
|
|
2453
|
+
retainBackgroundProcesses: { type: boolean, description: Keep background processes alive past the turn. }
|
|
2454
|
+
excludeTools:
|
|
2455
|
+
type: array
|
|
2456
|
+
items: { type: string }
|
|
2457
|
+
description: Tool names to withhold from this task's roster.
|
|
2458
|
+
deferTools:
|
|
2459
|
+
type: array
|
|
2460
|
+
items: { type: string }
|
|
2461
|
+
description: Tool names to DEFER (discoverable via tool search instead of mounted up front).
|
|
2462
|
+
attachments:
|
|
2463
|
+
type: object
|
|
2464
|
+
description: >
|
|
2465
|
+
Turn-boundary reminder attachments (design/133 + G1). Each flag opts INTO an injection; omitted = off.
|
|
2466
|
+
`changedFiles` may also be an object to cap the listing.
|
|
2467
|
+
additionalProperties: true
|
|
2468
|
+
properties:
|
|
2469
|
+
todoReminder: { type: boolean }
|
|
2470
|
+
todoReminderMode: { type: string, enum: [baseline, off] }
|
|
2471
|
+
changedFiles:
|
|
2472
|
+
oneOf:
|
|
2473
|
+
- { type: boolean }
|
|
2474
|
+
- { type: object, properties: { maxFiles: { type: integer } } }
|
|
2475
|
+
planModeReminder: { type: boolean }
|
|
2476
|
+
budgetUsd: { type: boolean }
|
|
2477
|
+
backgroundTasks: { type: boolean }
|
|
2478
|
+
toolsDelta: { type: boolean }
|
|
2479
|
+
agentListing: { type: boolean }
|
|
2480
|
+
skillsListing: { type: boolean }
|
|
2481
|
+
mcpInstructions: { type: boolean }
|
|
2482
|
+
limits:
|
|
2483
|
+
type: object
|
|
2484
|
+
description: >
|
|
2485
|
+
Per-task bounds. The three `false`-only switches are OPT-OUTS of engine defaults (there is no `true`
|
|
2486
|
+
form — passing false disables that default behaviour).
|
|
2487
|
+
properties:
|
|
2488
|
+
timeoutSec: { type: integer }
|
|
2489
|
+
maxOutputTokens: { type: integer }
|
|
2490
|
+
maxTurns: { type: integer }
|
|
2491
|
+
deadlineNudge: { type: boolean, enum: [false] }
|
|
2492
|
+
callCapByDeadline: { type: boolean, enum: [false] }
|
|
2493
|
+
gracefulFinalize: { type: boolean, enum: [false] }
|
|
2494
|
+
outputRetries: { type: integer, description: How many times to retry a malformed structured output. }
|
|
2495
|
+
compaction:
|
|
2496
|
+
type: object
|
|
2497
|
+
description: Compaction tuning for this task.
|
|
2498
|
+
properties:
|
|
2499
|
+
clampTolerance: { type: number }
|
|
2089
2500
|
|
|
2090
2501
|
TaskResult:
|
|
2091
2502
|
type: object
|
|
@@ -2096,6 +2507,46 @@ components:
|
|
|
2096
2507
|
sessionId: { type: string }
|
|
2097
2508
|
status: { $ref: '#/components/schemas/RunStatus' }
|
|
2098
2509
|
result: { type: string }
|
|
2510
|
+
model:
|
|
2511
|
+
type: string
|
|
2512
|
+
description: >
|
|
2513
|
+
MF-25 — the EFFECTIVE model id that served this task: the RESOLVED `Model.id`, NOT the requested
|
|
2514
|
+
`model` ref (which may be a role / catalog name / `@mention`). Lets a UI echo "served by X" instead of
|
|
2515
|
+
the requested ref. A mid-run degradation is reported separately via `degraded`. Verified to reach the
|
|
2516
|
+
wire by a real-HTTP regression pin on the server side (`test/effective-model-echo-wire.test.ts`).
|
|
2517
|
+
salvagedOutput:
|
|
2518
|
+
type: string
|
|
2519
|
+
description: Partial output preserved when the run could not complete normally (best-effort salvage).
|
|
2520
|
+
blockedReason:
|
|
2521
|
+
type: string
|
|
2522
|
+
description: Why a `blocked` status was reached (human-readable).
|
|
2523
|
+
checkpointGate:
|
|
2524
|
+
description: >
|
|
2525
|
+
The gate kind that produced `checkpointToken` when the run suspended. Deliberately UNTYPED here —
|
|
2526
|
+
the shape is core's and still evolving; treat it as opaque and branch on `status`/`errorCode` instead.
|
|
2527
|
+
degraded:
|
|
2528
|
+
type: object
|
|
2529
|
+
description: >
|
|
2530
|
+
Set when the run was served by a FALLBACK model after the requested one became unusable mid-run.
|
|
2531
|
+
`from`/`to` are resolved `Model.id`s; `atTurn` is the turn index where the switch happened.
|
|
2532
|
+
required: [from, to, reason, atTurn]
|
|
2533
|
+
properties:
|
|
2534
|
+
from: { type: string }
|
|
2535
|
+
to: { type: string }
|
|
2536
|
+
reason:
|
|
2537
|
+
type: string
|
|
2538
|
+
description: >
|
|
2539
|
+
Open enum — known values `breaker_open` | `rate_limit` | `budget` | `server_error` |
|
|
2540
|
+
`last_resort`; treat unknown values as opaque rather than failing closed.
|
|
2541
|
+
chain:
|
|
2542
|
+
type: array
|
|
2543
|
+
items: { type: string }
|
|
2544
|
+
description: The full fallback chain walked, when more than one hop occurred.
|
|
2545
|
+
atTurn: { type: integer }
|
|
2546
|
+
structuredOutput:
|
|
2547
|
+
description: >
|
|
2548
|
+
The task's structured (schema-constrained) output when one was requested. Shape is caller-defined,
|
|
2549
|
+
so this is intentionally untyped.
|
|
2099
2550
|
errorCode:
|
|
2100
2551
|
type: string
|
|
2101
2552
|
description: >
|
|
@@ -2144,6 +2595,37 @@ components:
|
|
|
2144
2595
|
description: >
|
|
2145
2596
|
System attribution DERIVED FROM the authenticating credential (unforgeable; body injection ignored).
|
|
2146
2597
|
e.g. oa | cc-mcp | portal. LIVE (service cf1be73).
|
|
2598
|
+
suggestions:
|
|
2599
|
+
type: array
|
|
2600
|
+
items: { type: string }
|
|
2601
|
+
description: Follow-up prompt suggestions produced for this run (absent when none were generated).
|
|
2602
|
+
supervisorCost: { $ref: '#/components/schemas/SupervisorCostBreakdown' }
|
|
2603
|
+
|
|
2604
|
+
SupervisorCostBreakdown:
|
|
2605
|
+
type: object
|
|
2606
|
+
description: >
|
|
2607
|
+
Per-axis cost rollup for a supervised run. `llm` is `null` on a run whose LLM spend was not attributed
|
|
2608
|
+
(e.g. no brain call). All amounts are integer micro-USD (no float drift).
|
|
2609
|
+
required: [llm, infra, totalMicroUsd]
|
|
2610
|
+
properties:
|
|
2611
|
+
llm:
|
|
2612
|
+
type: ['object', 'null']
|
|
2613
|
+
required: [llmRootMicroUsd, nestedSubagentMicroUsd, memoryConsolidationMicroUsd, compactionMicroUsd]
|
|
2614
|
+
properties:
|
|
2615
|
+
llmRootMicroUsd: { type: integer }
|
|
2616
|
+
nestedSubagentMicroUsd: { type: integer }
|
|
2617
|
+
memoryConsolidationMicroUsd: { type: integer }
|
|
2618
|
+
compactionMicroUsd: { type: integer }
|
|
2619
|
+
infra:
|
|
2620
|
+
type: object
|
|
2621
|
+
description: Service-owned infra rates (the engine prices only LLM tokens); all default 0 when unpriced.
|
|
2622
|
+
required: [toolCallMicroUsd, sandboxWalltimeMicroUsd, egressMicroUsd, totalMicroUsd]
|
|
2623
|
+
properties:
|
|
2624
|
+
toolCallMicroUsd: { type: integer }
|
|
2625
|
+
sandboxWalltimeMicroUsd: { type: integer }
|
|
2626
|
+
egressMicroUsd: { type: integer }
|
|
2627
|
+
totalMicroUsd: { type: integer }
|
|
2628
|
+
totalMicroUsd: { type: integer, description: llm + infra. }
|
|
2147
2629
|
|
|
2148
2630
|
CancelAck:
|
|
2149
2631
|
type: object
|
|
@@ -2155,6 +2637,13 @@ components:
|
|
|
2155
2637
|
taskId: { type: string }
|
|
2156
2638
|
status: { type: string }
|
|
2157
2639
|
note: { type: string }
|
|
2640
|
+
errorCode:
|
|
2641
|
+
type: [string, "null"]
|
|
2642
|
+
description: >
|
|
2643
|
+
Present on the two real terminal paths (the common `"cancelled"` outcome, and an explicit `null` when a
|
|
2644
|
+
concurrent reaper/another leg terminalized first — the ack reports the ACTUAL row, it does not fabricate
|
|
2645
|
+
"cancelled"). OMITTED entirely on the plain `cancelling` / no-op branches, so treat absence as "unknown",
|
|
2646
|
+
not as "no error".
|
|
2158
2647
|
|
|
2159
2648
|
ResumeEvicted:
|
|
2160
2649
|
type: object
|
|
@@ -2166,6 +2655,93 @@ components:
|
|
|
2166
2655
|
error: { type: string }
|
|
2167
2656
|
retainedFrom: { type: integer, description: Lowest event seq still retained; resume events from here. }
|
|
2168
2657
|
|
|
2658
|
+
ImageIndexEntry:
|
|
2659
|
+
# 新增(2026-07-25 回填批):sandbox 镜像目录条目。此前 `/v1/images` 整条路径不在本文件里。
|
|
2660
|
+
# 🔴 为什么 21 个字段**全部** required:server 侧 `plugins/tidb-image-index.ts` 的 `mapRow()` 对每一行
|
|
2661
|
+
# 恒全量赋值 —— nullable 的字段也至少给 `null`,**从不省略键**;`GET /v1/images` 的 handler 把 entries
|
|
2662
|
+
# 原样 sendJson、零裁剪。所以「可空」在这里表达为 `type: [..., 'null']`,而不是从 required 里拿掉。
|
|
2663
|
+
type: object
|
|
2664
|
+
description: >
|
|
2665
|
+
One sandbox-image catalog entry (`GET /v1/images` → `images[]`). Visibility is principal-scoped by the
|
|
2666
|
+
server. READ-ONLY data source for a "pick a sandbox template" UI.
|
|
2667
|
+
required:
|
|
2668
|
+
[id, profile, bands, repo, tag, digest, toolchainVersions, capabilities, podContract, sizeBytes, status,
|
|
2669
|
+
visibility, tenantId, manifestSha, recipeGitSha, generatorVersion, buildDate, supersedes, signed,
|
|
2670
|
+
createdAt, updatedAt]
|
|
2671
|
+
additionalProperties: true
|
|
2672
|
+
properties:
|
|
2673
|
+
id: { type: string, description: 'deterministically derived from (repo, digest) — there is no explicit-id upsert path, so an id collision ⟺ a (repo, digest) collision.' }
|
|
2674
|
+
profile: { type: string }
|
|
2675
|
+
bands: { type: array, items: { type: string } }
|
|
2676
|
+
repo: { type: string }
|
|
2677
|
+
tag: { type: string }
|
|
2678
|
+
digest:
|
|
2679
|
+
type: string
|
|
2680
|
+
description: >
|
|
2681
|
+
The immutable digest a running sandbox is built from. 🔴 DISPLAY ONLY — a caller must NEVER send this
|
|
2682
|
+
back to bind an image (bind by `profile`; the server re-resolves + re-admits under a trusted
|
|
2683
|
+
principal, because trusting a caller-supplied digest would fail OPEN).
|
|
2684
|
+
toolchainVersions: { type: object, additionalProperties: { type: string } }
|
|
2685
|
+
capabilities:
|
|
2686
|
+
type: object
|
|
2687
|
+
additionalProperties: true
|
|
2688
|
+
properties:
|
|
2689
|
+
browser: { type: boolean }
|
|
2690
|
+
db: { type: boolean }
|
|
2691
|
+
nestedBuild: { type: boolean, description: 'can it build container images (back-compat boolean).' }
|
|
2692
|
+
nestedBuildMode:
|
|
2693
|
+
type: string
|
|
2694
|
+
enum: [none, docker-cli-only, rootless-buildkit, privileged-dind]
|
|
2695
|
+
description: 'HOW it nests (the posture). Refines `nestedBuild`; absent ⇒ fall back to the boolean.'
|
|
2696
|
+
podContract:
|
|
2697
|
+
type: object
|
|
2698
|
+
additionalProperties: true
|
|
2699
|
+
properties:
|
|
2700
|
+
devShmMB: { type: integer }
|
|
2701
|
+
minMemMB: { type: integer }
|
|
2702
|
+
minCpu: { type: string }
|
|
2703
|
+
readyTimeoutSec: { type: integer }
|
|
2704
|
+
securityContext: { type: object, additionalProperties: true }
|
|
2705
|
+
sizeBytes: { type: ['integer', 'null'] }
|
|
2706
|
+
status: { type: string, enum: [building, published, deprecated, failed] }
|
|
2707
|
+
visibility: { type: string, enum: [public, tenant] }
|
|
2708
|
+
tenantId: { type: ['string', 'null'] }
|
|
2709
|
+
manifestSha: { type: ['string', 'null'] }
|
|
2710
|
+
recipeGitSha: { type: ['string', 'null'] }
|
|
2711
|
+
generatorVersion: { type: ['string', 'null'] }
|
|
2712
|
+
buildDate: { type: ['string', 'null'], description: 'ISO date-time string (the server projects Date/string uniformly to ISO).' }
|
|
2713
|
+
supersedes: { type: ['string', 'null'], description: 'version-lineage anchor (optionally written by the server''s setStatus; semantics not further specified server-side — pass through).' }
|
|
2714
|
+
signed: { type: boolean }
|
|
2715
|
+
createdAt: { type: string, description: ISO date-time. }
|
|
2716
|
+
updatedAt: { type: string, description: ISO date-time. }
|
|
2717
|
+
|
|
2718
|
+
ImageSelectResult:
|
|
2719
|
+
# 新增(2026-07-25 回填批)。
|
|
2720
|
+
type: object
|
|
2721
|
+
description: >
|
|
2722
|
+
`POST /v1/images/select` resolution result — a PREVIEW of "which digest/capabilities does this profile
|
|
2723
|
+
resolve to" for the UI. 🔴 NOT a binding credential: to actually bind, send `sandboxImageProfile` on the
|
|
2724
|
+
task request and let the server resolve under a trusted principal.
|
|
2725
|
+
additionalProperties: true
|
|
2726
|
+
properties:
|
|
2727
|
+
profile: { type: string }
|
|
2728
|
+
digest: { type: string }
|
|
2729
|
+
repo: { type: string }
|
|
2730
|
+
ref:
|
|
2731
|
+
type: string
|
|
2732
|
+
description: >
|
|
2733
|
+
`${repo}@${digest}` — always present on a 200. This is the value a caller threads into the kata
|
|
2734
|
+
adapter's per-sandbox image (the server handler says so itself), i.e. it is load-bearing, not decorative.
|
|
2735
|
+
podContract: { type: object, additionalProperties: true }
|
|
2736
|
+
capabilities:
|
|
2737
|
+
type: object
|
|
2738
|
+
additionalProperties: true
|
|
2739
|
+
properties:
|
|
2740
|
+
browser: { type: boolean }
|
|
2741
|
+
db: { type: boolean }
|
|
2742
|
+
nestedBuild: { type: boolean }
|
|
2743
|
+
manifestSha: { type: string }
|
|
2744
|
+
|
|
2169
2745
|
QuotaError:
|
|
2170
2746
|
type: object
|
|
2171
2747
|
description: 429 per-principal cumulative-quota body (`quotaExceeded`).
|
|
@@ -2362,6 +2938,74 @@ components:
|
|
|
2362
2938
|
memory:
|
|
2363
2939
|
type: boolean
|
|
2364
2940
|
description: Memory transparency endpoints (GET/DELETE /v1/memory) available. the pinned wire contract.
|
|
2941
|
+
workflows: { type: boolean, description: "S8 self-orchestration workflow routes are mounted." }
|
|
2942
|
+
workflowsList: { type: boolean, description: "`GET /v1/workflows` list face (separate from the per-run reads)." }
|
|
2943
|
+
resumeAt: { type: boolean, description: "E18 resume-at-message anchors are resolvable." }
|
|
2944
|
+
rewindFiles: { type: boolean, description: "E19 working-tree snapshot/restore is wired." }
|
|
2945
|
+
rewindFilesTo: { type: boolean, description: "Restore to a SPECIFIC entry id (not just the latest snapshot)." }
|
|
2946
|
+
manualCompact: { type: boolean, description: "`POST /v1/runs/:id/compact` (needs a run store)." }
|
|
2947
|
+
sessions: { type: boolean, description: "Session read face (`GET /v1/sessions/:id`)." }
|
|
2948
|
+
sessionList: { type: boolean, description: "`GET /v1/sessions` list/picker face." }
|
|
2949
|
+
sessionSearch: { type: boolean, description: "Server-side session search." }
|
|
2950
|
+
sessionFork: { type: boolean, description: "Session fork verb." }
|
|
2951
|
+
sessionDelete: { type: boolean, description: "Session delete verb." }
|
|
2952
|
+
sessionInit: { type: boolean, description: "Session pre-initialization verb." }
|
|
2953
|
+
sessionPolicy: { type: boolean, description: "E6 per-session operator-tightened tool rules are durable." }
|
|
2954
|
+
usage: { type: boolean, description: "Usage analytics face." }
|
|
2955
|
+
policy: { type: boolean, description: "`GET /v1/policy` (autonomy/permission READ side)." }
|
|
2956
|
+
permissionModeWrite: { type: boolean, description: "Runtime permission-mode WRITE. Advertised false by design — autonomy is CONFIG, not steer; the READ side is `policy`." }
|
|
2957
|
+
modelSelection: { type: boolean, description: "`model` accepted per request." }
|
|
2958
|
+
effortSelection: { type: boolean, description: "`reasoningEffort` accepted per request." }
|
|
2959
|
+
compactionModel: { type: boolean, description: "A separate model may be pinned for compaction." }
|
|
2960
|
+
appendSystemPrompt: { type: boolean, description: "Per-request system-prompt append is honoured." }
|
|
2961
|
+
toolOutput: { type: boolean, description: "`tool_end` carries the model-facing output." }
|
|
2962
|
+
messageIdentity: { type: boolean, description: "Content events carry `eventId` (+ `parentToolCallId` for sub-agents)." }
|
|
2963
|
+
forwardSubagentEvents: { type: boolean, description: "Sub-agent events are forwarded onto the parent stream." }
|
|
2964
|
+
subagentSteer: { type: boolean, description: "Mid-flight steer of a named sub-agent." }
|
|
2965
|
+
subagentResume: { type: boolean, description: "Operator resume of a settled sub-agent." }
|
|
2966
|
+
subagentOutput: { type: boolean, description: "Sub-agent output read face." }
|
|
2967
|
+
subagentStream: { type: boolean, description: "Per-sub-agent event stream." }
|
|
2968
|
+
taskHandles: { type: boolean, description: "Durable task handles (output/stop verbs by handle)." }
|
|
2969
|
+
taskAgents: { type: boolean, description: "Per-task agent definitions are accepted." }
|
|
2970
|
+
retainBackgroundProcesses: { type: boolean, description: "Background processes may be retained past the turn." }
|
|
2971
|
+
interactiveTools: { type: boolean, description: "Interactive (prompting) tools are available." }
|
|
2972
|
+
projectContext: { type: boolean, description: "Project-context injection is wired." }
|
|
2973
|
+
mcp: { type: boolean, description: "MCP servers can be attached." }
|
|
2974
|
+
mcpInjection: { type: boolean, description: "Per-request MCP injection is accepted." }
|
|
2975
|
+
mcpElicitation: { type: boolean, description: "MCP elicitation round-trips are supported." }
|
|
2976
|
+
askUserQuestion: { type: boolean, description: "AskUserQuestion gate is available (durable when approvals are)." }
|
|
2977
|
+
toolApproval: { type: boolean, description: "Tool-approval gating is active." }
|
|
2978
|
+
promptSuggestions: { type: boolean, description: "Follow-up prompt suggestions are generated." }
|
|
2979
|
+
modelUsage: { type: boolean, description: "`GET /v1/runs/:id/model-usage` (needs a run store + usage plane)." }
|
|
2980
|
+
scheduler: { type: boolean, description: "Assistant-scheduler face is mounted." }
|
|
2981
|
+
sendUserFile: { type: boolean, description: "Outbound user-file delivery is wired." }
|
|
2982
|
+
sendUserFileLedger: { type: boolean, description: "The send-file ledger (audit of deliveries) is available." }
|
|
2983
|
+
excludeTools:
|
|
2984
|
+
type: array
|
|
2985
|
+
items: { type: string }
|
|
2986
|
+
description: Tool names this worker will honour in a request's exclude list.
|
|
2987
|
+
deferTools:
|
|
2988
|
+
type: array
|
|
2989
|
+
items: { type: string }
|
|
2990
|
+
description: Tool names that can be DEFERRED (surfaced via search rather than mounted up front).
|
|
2991
|
+
s3PublicEndpoint:
|
|
2992
|
+
type: ["string", "null"]
|
|
2993
|
+
description: >
|
|
2994
|
+
Public base URL for artifact/snapshot links, when the deployment exposes one. `null` = not configured
|
|
2995
|
+
(links are then worker-relative). One of only two NON-boolean capability values the server emits.
|
|
2996
|
+
taskSettings:
|
|
2997
|
+
type: object
|
|
2998
|
+
description: >
|
|
2999
|
+
Which `settings.json` sub-faces this worker honours (CC-parity v1). OPEN object — unknown keys may
|
|
3000
|
+
appear. The other non-boolean capability value.
|
|
3001
|
+
additionalProperties: true
|
|
3002
|
+
properties:
|
|
3003
|
+
permissions: { type: boolean }
|
|
3004
|
+
permissionMode: { type: boolean }
|
|
3005
|
+
model: { type: boolean }
|
|
3006
|
+
outputStyle: { type: boolean }
|
|
3007
|
+
env: { type: boolean }
|
|
3008
|
+
hooks: { type: boolean }
|
|
2365
3009
|
memoryWrite:
|
|
2366
3010
|
type: boolean
|
|
2367
3011
|
description: MF-30 — memory WRITE (append/edit/forget) available (deps.memory.append; server.ts:828).
|
|
@@ -2583,6 +3227,9 @@ components:
|
|
|
2583
3227
|
properties:
|
|
2584
3228
|
id: { type: string, description: 'Run id (= WorkflowRun.id).' }
|
|
2585
3229
|
scope: { type: string, description: 'Tenant/group scope (= the creating principal).' }
|
|
3230
|
+
name: { type: string, description: "The workflow script's declared `meta.name`." }
|
|
3231
|
+
description: { type: string, description: "The workflow script's declared `meta.description` (one-liner)." }
|
|
3232
|
+
currentPhase: { type: string, description: 'Title of the phase currently executing (absent once terminal).' }
|
|
2586
3233
|
status: { $ref: '#/components/schemas/WorkflowRunStatus' }
|
|
2587
3234
|
phaseCount: { type: integer, description: 'Phases recorded.' }
|
|
2588
3235
|
agentCount: { type: integer, description: 'Agent-runs recorded.' }
|
|
@@ -2591,6 +3238,46 @@ components:
|
|
|
2591
3238
|
endedAt: { type: integer, description: 'End epoch ms (absent while running).' }
|
|
2592
3239
|
createdAt: { type: integer, description: 'Record-creation epoch ms (listByScope sort key).' }
|
|
2593
3240
|
|
|
3241
|
+
WorkflowActivityBeat:
|
|
3242
|
+
# 新增(2026-07-25 回填批)—— workflow 监视面 "Activity · last N of M tool calls" 的一拍。
|
|
3243
|
+
type: object
|
|
3244
|
+
description: >
|
|
3245
|
+
One tool-call beat on a workflow agent's BOUNDED activity tail (source = core `ToolActivity`, projected
|
|
3246
|
+
verbatim by the service detail handler).
|
|
3247
|
+
|
|
3248
|
+
🔴 `arg` is a SHORT primary-arg SUMMARY (command→name, path→basename, url→origin+path), secret-scrubbed
|
|
3249
|
+
and truncated (~80 code points) by core. It exists for the monitor's `Read(path)` / `Bash(grep …)`
|
|
3250
|
+
display — it is NOT the full args. RENDER it; NEVER re-feed it to a model.
|
|
3251
|
+
additionalProperties: true
|
|
3252
|
+
properties:
|
|
3253
|
+
phase: { type: string, enum: [start, end] }
|
|
3254
|
+
toolCallId: { type: string }
|
|
3255
|
+
toolName: { type: string, description: 'the monitor renders `${toolName}(${arg})`.' }
|
|
3256
|
+
arg: { type: string, description: 'SHORT, secret-scrubbed, ~80-code-point summary (set on `phase:"start"`). UNTRUSTED display text.' }
|
|
3257
|
+
isError: { type: boolean, description: 'set on `phase:"end"` — whether the tool call errored.' }
|
|
3258
|
+
|
|
3259
|
+
WorkflowAgentRow:
|
|
3260
|
+
# 新增(2026-07-25 回填批)—— 取代 `WorkflowRun.agents` 的 `items: {}`(零形状)。
|
|
3261
|
+
type: object
|
|
3262
|
+
description: >
|
|
3263
|
+
One agent-run row in a workflow's detail. The shape is PERMISSIVE — read the known render fields below,
|
|
3264
|
+
tolerate the rest as the projection evolves.
|
|
3265
|
+
additionalProperties: true
|
|
3266
|
+
properties:
|
|
3267
|
+
label: { type: string, description: 'display label.' }
|
|
3268
|
+
status: { type: string, description: 'lifecycle status (the input vocabulary the display derivation reads).' }
|
|
3269
|
+
phase: { type: string, description: 'the phase title this agent ran under (groups it into a phase bucket).' }
|
|
3270
|
+
model: { type: string, description: 'per-agent model DISPLAY label (e.g. "Opus 4.8 (1M context)"), not an id.' }
|
|
3271
|
+
tokens: { type: integer }
|
|
3272
|
+
turns: { type: integer }
|
|
3273
|
+
toolCalls: { type: integer, description: 'total tool calls — the "M" in "last N of M tool calls".' }
|
|
3274
|
+
activity:
|
|
3275
|
+
type: array
|
|
3276
|
+
description: 'the "Activity" tail — the LAST-N tool-call beats (bounded).'
|
|
3277
|
+
items: { $ref: '#/components/schemas/WorkflowActivityBeat' }
|
|
3278
|
+
prompt: { type: string, description: 'what the worker was ASKED (core-redacted + bounded). UNTRUSTED display text.' }
|
|
3279
|
+
output: { type: string, description: 'the worker''s final OUTPUT (core-redacted + bounded). UNTRUSTED display text.' }
|
|
3280
|
+
|
|
2594
3281
|
WorkflowRun:
|
|
2595
3282
|
type: object
|
|
2596
3283
|
description: >
|
|
@@ -2601,9 +3288,17 @@ components:
|
|
|
2601
3288
|
properties:
|
|
2602
3289
|
id: { type: string }
|
|
2603
3290
|
scope: { type: string }
|
|
3291
|
+
name: { type: string, description: "The workflow script's declared `meta.name`." }
|
|
3292
|
+
description: { type: string, description: "The workflow script's declared `meta.description` (one-liner)." }
|
|
2604
3293
|
status: { $ref: '#/components/schemas/WorkflowRunStatus' }
|
|
2605
3294
|
phases: { type: array, description: 'Phase records (permissive).', items: {} }
|
|
2606
|
-
|
|
3295
|
+
# `items: {}`(= 任意值,零形状)改为具名 $ref(2026-07-25 回填批):这是 workflow 监视面最吃重的数组,
|
|
3296
|
+
# 空 schema 等于对非 TS 消费方完全没描述过它。`WorkflowAgentRow` 仍是 PERMISSIVE(additionalProperties)——
|
|
3297
|
+
# 只钉住监视面真正 key 的那些字段,其余随投影演进。
|
|
3298
|
+
agents:
|
|
3299
|
+
type: array
|
|
3300
|
+
description: 'Agent-run records (permissive — read the known render fields, tolerate the rest).'
|
|
3301
|
+
items: { $ref: '#/components/schemas/WorkflowAgentRow' }
|
|
2607
3302
|
stats:
|
|
2608
3303
|
type: object
|
|
2609
3304
|
description: 'Token stats — own at stats.tokens, nested at stats.nested.tokens (R-5 own/nested split).'
|
|
@@ -2873,6 +3568,18 @@ components:
|
|
|
2873
3568
|
(they carry a RiskDescriptor); ABSENT for resource_limit/needs_review/plan_review — UI tolerates undefined.
|
|
2874
3569
|
spentMicroUsd: { type: number, description: 'cumulative spend on the suspend chain (when a resource ledger is attached).' }
|
|
2875
3570
|
deadline: { type: integer, description: 'awaiting-human SLA deadline (epoch ms).' }
|
|
3571
|
+
contentKind:
|
|
3572
|
+
type: string
|
|
3573
|
+
description: >
|
|
3574
|
+
Open enum (known value `content_ask`) distinguishing WHAT is being asked about, for gates whose payload
|
|
3575
|
+
is content rather than a tool call. Treat unknown values as opaque.
|
|
3576
|
+
sourceTaskId: { type: string, description: 'The task that produced this checkpoint (when distinct from sessionId).' }
|
|
3577
|
+
principal: { type: string, description: 'The submitting principal, when the deployment records one.' }
|
|
3578
|
+
createdAt: { type: integer, description: 'Creation time, epoch ms (NOTE — SessionRecord.createdAt is an ISO string).' }
|
|
3579
|
+
preview:
|
|
3580
|
+
description: >
|
|
3581
|
+
Optional human-facing preview of what is being approved. Deliberately UNTYPED — the shape follows the
|
|
3582
|
+
gate kind and is meant for display only; never branch on it.
|
|
2876
3583
|
|
|
2877
3584
|
InboxRow:
|
|
2878
3585
|
description: >
|
|
@@ -2883,6 +3590,20 @@ components:
|
|
|
2883
3590
|
- type: object
|
|
2884
3591
|
properties:
|
|
2885
3592
|
objective: { type: ['string', 'null'], description: 'task objective, null if unavailable.' }
|
|
3593
|
+
toolName:
|
|
3594
|
+
type: ['string', 'null']
|
|
3595
|
+
description: 'The gated tool, when the pause came from a tool call (null for non-tool gates).'
|
|
3596
|
+
toolCallId: { type: string, description: 'The gated tool-call id.' }
|
|
3597
|
+
boundCallId: { type: string, description: 'D-1 decision binding — echo it back on /decide.' }
|
|
3598
|
+
boundInputHash:
|
|
3599
|
+
type: string
|
|
3600
|
+
description: >
|
|
3601
|
+
D-1 decision binding — hash of the bound tool input. Echo on /decide so an approval cannot land on
|
|
3602
|
+
a DIFFERENT call that was swapped in after the operator looked.
|
|
3603
|
+
input:
|
|
3604
|
+
description: >
|
|
3605
|
+
REDACTED tool input for display. Untyped by design (per-tool shape) — and note the raw `toolInput`
|
|
3606
|
+
is deliberately NOT on this row: the handler always strips it (along with `token`) before returning.
|
|
2886
3607
|
|
|
2887
3608
|
InboxList:
|
|
2888
3609
|
type: object
|
|
@@ -2894,27 +3615,79 @@ components:
|
|
|
2894
3615
|
type: array
|
|
2895
3616
|
items: { $ref: '#/components/schemas/InboxRow' }
|
|
2896
3617
|
|
|
2897
|
-
|
|
3618
|
+
AssistantGate:
|
|
3619
|
+
# 从 `AssistantTaskRow.gate` 的内联形提取为命名 schema(2026-07-25 回填批):内联的 schema 生成不出可复用
|
|
3620
|
+
# 的具名类型,非 TS 消费方只能拿到匿名对象;且反射式 drift 门只按「命名 schema ↔ 同名 exported interface」
|
|
3621
|
+
# 配对,内联形对它完全不可见 ⇒ 这里的字段漂移过去无人看守。
|
|
3622
|
+
type: object
|
|
3623
|
+
description: >
|
|
3624
|
+
ASSISTANT-WIRE-CONTRACT §3 — the active gate inlined on an `AssistantTask` row.
|
|
3625
|
+
|
|
3626
|
+
🔴 LAYER NOTE (this schema and the SDK's `AssistantGate` type describe DIFFERENT layers, deliberately):
|
|
3627
|
+
this file documents the WIRE, where `severity`/`spentMicroUsd`/`deadline` are sent as EXPLICIT `null`
|
|
3628
|
+
when absent (server `http/server.ts` sends `severity: s.severity ?? null` — a present key holding null,
|
|
3629
|
+
NOT an omitted key). The SDK's TS type declares them `?: number` because the SDK FOLDS null → omitted
|
|
3630
|
+
key at its resource boundary (`resources/assistant.ts` `RawAssistantGate` + `normalizeGate()`), so a
|
|
3631
|
+
TS consumer never observes the null. Both are correct for their layer — do NOT "fix" either to match
|
|
3632
|
+
the other. A non-TS client generated from this file MUST tolerate the nulls itself.
|
|
3633
|
+
required: [kind]
|
|
3634
|
+
additionalProperties: true
|
|
3635
|
+
properties:
|
|
3636
|
+
kind:
|
|
3637
|
+
type: string
|
|
3638
|
+
description: >
|
|
3639
|
+
Same open set as `CheckpointSummary.gateKind` — the FLATTENED projection of core's
|
|
3640
|
+
`CheckpointGate`. (Nested-as-`gate` ⇒ the discriminator is named `kind`; flattened onto a row ⇒
|
|
3641
|
+
`gateKind`. Same value domain, different position — a naming CONVENTION, not an inconsistency.)
|
|
3642
|
+
enum: [human, irreversible_ask, resource_limit, needs_review, plan_review, task_done]
|
|
3643
|
+
x-open-enum: true # a future core kind must render generically, never crash — do not close this union
|
|
3644
|
+
severity:
|
|
3645
|
+
type: ['integer', 'null']
|
|
3646
|
+
enum: [1, 2, 3, 4, 5, null]
|
|
3647
|
+
description: >
|
|
3648
|
+
Risk tier. `null` (or, post-SDK-normalization, absent) = this gate kind carries no RiskDescriptor
|
|
3649
|
+
(resource_limit / needs_review / plan_review) — treat as "unknown", never as 0.
|
|
3650
|
+
spentMicroUsd:
|
|
3651
|
+
type: ['number', 'null']
|
|
3652
|
+
description: >
|
|
3653
|
+
Cumulative spend ALREADY INCURRED on the suspend chain (micro-USD). ⚠️ NOT the same concept as
|
|
3654
|
+
`costMicroUsd` ("what this thing cost") — never treat the two as aliases.
|
|
3655
|
+
deadline:
|
|
3656
|
+
type: ['integer', 'null']
|
|
3657
|
+
description: 'awaiting-human SLA deadline — epoch ms (the checkpoint family''s time convention; run-ledger rows use ISO strings instead).'
|
|
3658
|
+
|
|
3659
|
+
AssistantTask:
|
|
3660
|
+
# 重命名自 `AssistantTaskRow`(2026-07-25):SDK 的 exported interface 叫 `AssistantTask`,而权威已在
|
|
3661
|
+
# types.ts(见本文件顶注),spec 侧沿用另一个名字会让反射式 drift 门永远配不上对 ⇒ 以 TS 名为准对齐。
|
|
2898
3662
|
type: object
|
|
2899
3663
|
description: >
|
|
2900
3664
|
ASSISTANT-WIRE-CONTRACT §3 — a scheduler-overview row = run-store `listRuns(owner)` joined with the core
|
|
2901
3665
|
scheduler seam. ⚠️ `createdAt`/`updatedAt` are ISO date-time strings (unlike inbox/§1 epoch-ms).
|
|
2902
|
-
required: [taskId, sessionId, status, needsAttention, createdAt, updatedAt]
|
|
3666
|
+
required: [taskId, sessionId, status, needsAttention, gate, createdAt, updatedAt]
|
|
2903
3667
|
additionalProperties: true
|
|
2904
3668
|
properties:
|
|
2905
3669
|
taskId: { type: string }
|
|
2906
3670
|
sessionId: { type: string }
|
|
2907
|
-
status:
|
|
2908
|
-
|
|
3671
|
+
status:
|
|
3672
|
+
type: string
|
|
3673
|
+
# 🔴 `needs_review` 是 2026-07-25 补的:server 的行过滤器逐字是
|
|
3674
|
+
# `.filter(r => r.status === "running" || r.status === "suspended" || r.status === "needs_review")`
|
|
3675
|
+
# (`http/server.ts:4677`,已亲读取证)——本枚举此前只有前两个,是真陈旧,照它生成的客户端会把一个
|
|
3676
|
+
# 合法的一等 triage 态判成非法值。字段级 drift 门只比字段名、比不到枚举值,所以它没抓到这条。
|
|
3677
|
+
enum: [running, suspended, needs_review]
|
|
3678
|
+
description: >
|
|
3679
|
+
`running` — live. `suspended` — durably parked on a HITL gate (resolve via §4b resume / §4a decide).
|
|
3680
|
+
`needs_review` — a FIRST-CLASS triage state: a plan_review / dry-run review park (NOT `suspended`);
|
|
3681
|
+
carries `needsAttention:true` + `gate.kind` = `plan_review`/`needs_review` (severity absent) and
|
|
3682
|
+
sorts FIRST. 🔴 Resolve it via §4c `POST /v1/assistant/tasks/:id/plan_review`, NOT §4b resume.
|
|
3683
|
+
⚠️ Distinct axis from `RunStatus.needs_review` (that one is a dry-run TERMINAL run status; this is a
|
|
3684
|
+
park state on the overview row) — same name, different axis.
|
|
3685
|
+
needsAttention: { type: boolean, description: '= parked on a HITL gate (`suspended` OR `needs_review`); server derives it as `!!gate`.' }
|
|
2909
3686
|
gate:
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
kind: { type: string, description: 'same open set as gateKind.' }
|
|
2915
|
-
severity: { type: ['integer', 'null'], enum: [1, 2, 3, 4, 5, null] }
|
|
2916
|
-
spentMicroUsd: { type: ['number', 'null'] }
|
|
2917
|
-
deadline: { type: ['integer', 'null'], description: epoch ms. }
|
|
3687
|
+
description: 'the active gate, or null when the row is not parked.'
|
|
3688
|
+
oneOf:
|
|
3689
|
+
- $ref: '#/components/schemas/AssistantGate'
|
|
3690
|
+
- type: 'null'
|
|
2918
3691
|
createdAt: { type: string, description: ISO date-time. }
|
|
2919
3692
|
updatedAt: { type: string, description: ISO date-time. }
|
|
2920
3693
|
|
|
@@ -2928,7 +3701,39 @@ components:
|
|
|
2928
3701
|
properties:
|
|
2929
3702
|
tasks:
|
|
2930
3703
|
type: array
|
|
2931
|
-
items: { $ref: '#/components/schemas/
|
|
3704
|
+
items: { $ref: '#/components/schemas/AssistantTask' }
|
|
3705
|
+
|
|
3706
|
+
AssistantTaskStatus:
|
|
3707
|
+
# 新增(2026-07-25 回填批):§4b resume / §4c plan_review / §4d preempt 三条决策端点此前在本文件里都只声明
|
|
3708
|
+
# 了 `{status}` 一个字段——与 SDK 三批核查前的旧类型同样陈旧。下面的形按 server 源码逐字取证:
|
|
3709
|
+
# • resume / plan_review 200(共用 `driveResumeIntoRunLog`,`http/server.ts:7688-7696`):
|
|
3710
|
+
# `{ taskId, sessionId, status, errorCode?, errorMessage?, retriable? }`(后三个条件 spread ⇒ 缺则省键)
|
|
3711
|
+
# • preempt 202(`http/server.ts:4726/4734/4737` 三个出口):`{ taskId, status, note }`
|
|
3712
|
+
# ⚠️ `status` 在 202 上**并非恒为 `"preempting"`**:两个 no-op 出口分别回 `run.status` 与
|
|
3713
|
+
# `now?.status ?? "failed"` —— 所以这里不能把它写成 const。
|
|
3714
|
+
type: object
|
|
3715
|
+
description: >
|
|
3716
|
+
The response of the §4b/§4c/§4d decision endpoints (resume / plan_review / preempt). Union of the two
|
|
3717
|
+
real body shapes — `sessionId` appears only on resume/plan_review, `note` only on preempt; everything
|
|
3718
|
+
else is shared (absent keys are OMITTED, never null).
|
|
3719
|
+
required: [taskId, status]
|
|
3720
|
+
additionalProperties: true
|
|
3721
|
+
properties:
|
|
3722
|
+
taskId: { type: string, description: 'always present (all three response bodies carry it).' }
|
|
3723
|
+
status:
|
|
3724
|
+
type: string
|
|
3725
|
+
description: >
|
|
3726
|
+
OPEN string — do NOT narrow. Observed values include `completed` / `failed` / `suspended` /
|
|
3727
|
+
`needs_review` / `preempting`, plus whatever run status a no-op preempt echoes back.
|
|
3728
|
+
sessionId: { type: string, description: 'resume/plan_review ONLY — the session the decided checkpoint belongs to. Absent from the preempt body.' }
|
|
3729
|
+
errorCode: { type: string, description: 'present on a failed resume/plan_review (e.g. `checkpoint.reopen_failed`).' }
|
|
3730
|
+
errorMessage: { type: string, description: 'human-readable failure detail (server-side secret-redacted).' }
|
|
3731
|
+
retriable:
|
|
3732
|
+
type: boolean
|
|
3733
|
+
description: >
|
|
3734
|
+
`true` = the park is STILL PENDING (the server re-parked it), so re-fetching and deciding again is
|
|
3735
|
+
meaningful. Emitted only when the store CONFIRMED the reopen — never inferred.
|
|
3736
|
+
note: { type: string, description: 'preempt ONLY — human-readable explanation (incl. the honest "preempt is a no-op" cases). Absent from the resume/plan_review body.' }
|
|
2932
3737
|
|
|
2933
3738
|
PlanReviewRequest:
|
|
2934
3739
|
type: object
|
|
@@ -2960,6 +3765,10 @@ components:
|
|
|
2960
3765
|
properties:
|
|
2961
3766
|
provider: { type: string }
|
|
2962
3767
|
modelId: { type: string }
|
|
3768
|
+
window:
|
|
3769
|
+
$ref: '#/components/schemas/SessionWindow'
|
|
3770
|
+
promptEpoch:
|
|
3771
|
+
$ref: '#/components/schemas/PromptEpoch'
|
|
2963
3772
|
messages:
|
|
2964
3773
|
type: array
|
|
2965
3774
|
items: {}
|
|
@@ -2980,6 +3789,62 @@ components:
|
|
|
2980
3789
|
runCount: { type: integer }
|
|
2981
3790
|
objectivePreview: { type: ['string', 'null'] }
|
|
2982
3791
|
lastStatus: { type: string }
|
|
3792
|
+
lastRunId:
|
|
3793
|
+
type: ['string', 'null']
|
|
3794
|
+
description: The most recent run's id (null when the session has no run yet) — lets a picker deep-link.
|
|
3795
|
+
title:
|
|
3796
|
+
type: ['string', 'null']
|
|
3797
|
+
description: >
|
|
3798
|
+
Auto-generated session summary title (service-side `session-titler`: one cheap model call kicked off in
|
|
3799
|
+
the background after the first submit, idempotent via an IS-NULL gate). Genuinely `null` until it lands,
|
|
3800
|
+
so render a fallback rather than waiting on it.
|
|
3801
|
+
|
|
3802
|
+
SessionWindow:
|
|
3803
|
+
type: object
|
|
3804
|
+
description: >
|
|
3805
|
+
Pagination window echoed by `GET /v1/sessions/:id` when the caller asked for a message slice.
|
|
3806
|
+
OPEN object — additional keys may appear.
|
|
3807
|
+
required: [offset, total]
|
|
3808
|
+
additionalProperties: true
|
|
3809
|
+
properties:
|
|
3810
|
+
offset: { type: integer, description: Index of the first returned message within the full context. }
|
|
3811
|
+
total: { type: integer, description: Total messages available (so a client can page). }
|
|
3812
|
+
|
|
3813
|
+
SessionMessageEnvelope:
|
|
3814
|
+
# 新增(2026-07-25 回填批):`GET /v1/sessions/{id}?message=<index>` 的单条消息展开支路。本文件此前连
|
|
3815
|
+
# `/v1/sessions/{id}` 的 query 参数都一个没声明,所以这条支路对生成式消费方等于不存在。
|
|
3816
|
+
type: object
|
|
3817
|
+
description: >
|
|
3818
|
+
The single-message expand leg — `GET /v1/sessions/{sessionId}?message=<index>` returns THIS instead of a
|
|
3819
|
+
`SessionRecord`. An out-of-range index → 404 (the error body carries `total`).
|
|
3820
|
+
required: [sessionId, index, message]
|
|
3821
|
+
additionalProperties: true
|
|
3822
|
+
properties:
|
|
3823
|
+
sessionId: { type: string }
|
|
3824
|
+
floorEntryId:
|
|
3825
|
+
type: ['string', 'null']
|
|
3826
|
+
description: 'the compaction floor this index is relative to, when one applies.'
|
|
3827
|
+
index: { type: integer, description: 'the requested message index (echoed).' }
|
|
3828
|
+
message: { description: 'OPEN — the message payload as stored; shape belongs to the transcript format, not to this envelope.' }
|
|
3829
|
+
|
|
3830
|
+
PromptEpoch:
|
|
3831
|
+
type: object
|
|
3832
|
+
description: >
|
|
3833
|
+
A session's prompt-epoch pin (server >=1.220, additive on `GET /v1/sessions/:id`). Identifies WHICH
|
|
3834
|
+
assembled system-prompt artifact this session is pinned to, so a transcript stays reproducible across
|
|
3835
|
+
prompt-pack releases. IDs/digests only — never prompt text. OPEN object.
|
|
3836
|
+
required: [epoch, artifactDigest, packId, assemblyApi, activatedBy]
|
|
3837
|
+
additionalProperties: true
|
|
3838
|
+
properties:
|
|
3839
|
+
epoch: { type: integer, description: Monotonic epoch counter within the session. }
|
|
3840
|
+
artifactDigest: { type: string, description: 'Content digest of the assembled artifact (`sha256:<64 hex>`).' }
|
|
3841
|
+
packId: { type: string, description: 'Prompt-pack identity, e.g. `sema-default@1`.' }
|
|
3842
|
+
assemblyApi: { type: integer, description: Assembly-contract version (currently always 1). }
|
|
3843
|
+
activatedBy:
|
|
3844
|
+
type: string
|
|
3845
|
+
description: >
|
|
3846
|
+
Open enum — known values `session_start` | `compaction` | `legacy_migration`; treat unknown values as
|
|
3847
|
+
opaque rather than failing closed.
|
|
2983
3848
|
|
|
2984
3849
|
SessionListPage:
|
|
2985
3850
|
type: object
|
|
@@ -3231,6 +4096,16 @@ components:
|
|
|
3231
4096
|
- $ref: '#/components/schemas/Event_task_progress'
|
|
3232
4097
|
- $ref: '#/components/schemas/Event_workspace_changed'
|
|
3233
4098
|
- $ref: '#/components/schemas/Event_suspended'
|
|
4099
|
+
# 🔴 以下 6 臂是 2026-07-25 补的:`events.ts` 的 `AgentEvent` 联合有 21 个 `type` 字面量,本文件此前只声明
|
|
4100
|
+
# 15 个 —— 照本文件生成客户端的消费方会把 6 种合法帧当成非法值(事件面是最吃重的 wire 面,这个缺口比
|
|
4101
|
+
# 字段级 drift 更伤)。字段级 drift 门只按「命名 schema ↔ 同名 exported interface」配对,联合缺臂对它
|
|
4102
|
+
# 不可见,故这条只能靠人工核对 —— 补齐时是拿 `events.ts` 的 type 字面量集与本联合做机器 diff 得出的。
|
|
4103
|
+
- $ref: '#/components/schemas/Event_file_link'
|
|
4104
|
+
- $ref: '#/components/schemas/Event_prompt_assembled'
|
|
4105
|
+
- $ref: '#/components/schemas/Event_model_usage'
|
|
4106
|
+
- $ref: '#/components/schemas/Event_task_notification'
|
|
4107
|
+
- $ref: '#/components/schemas/Event_diagnostics'
|
|
4108
|
+
- $ref: '#/components/schemas/Event_steering_injected'
|
|
3234
4109
|
- $ref: '#/components/schemas/Event_done'
|
|
3235
4110
|
- $ref: '#/components/schemas/Event_failed'
|
|
3236
4111
|
discriminator:
|
|
@@ -3249,6 +4124,12 @@ components:
|
|
|
3249
4124
|
task_progress: '#/components/schemas/Event_task_progress'
|
|
3250
4125
|
workspace_changed: '#/components/schemas/Event_workspace_changed'
|
|
3251
4126
|
suspended: '#/components/schemas/Event_suspended'
|
|
4127
|
+
file_link: '#/components/schemas/Event_file_link'
|
|
4128
|
+
prompt_assembled: '#/components/schemas/Event_prompt_assembled'
|
|
4129
|
+
model_usage: '#/components/schemas/Event_model_usage'
|
|
4130
|
+
task_notification: '#/components/schemas/Event_task_notification'
|
|
4131
|
+
diagnostics: '#/components/schemas/Event_diagnostics'
|
|
4132
|
+
steering_injected: '#/components/schemas/Event_steering_injected'
|
|
3252
4133
|
done: '#/components/schemas/Event_done'
|
|
3253
4134
|
failed: '#/components/schemas/Event_failed'
|
|
3254
4135
|
|
|
@@ -3400,6 +4281,60 @@ components:
|
|
|
3400
4281
|
properties:
|
|
3401
4282
|
type: { const: workspace_changed }
|
|
3402
4283
|
cwd: { type: string }
|
|
4284
|
+
CheckpointGate:
|
|
4285
|
+
# 从 `Event_suspended.gate` 的内联 oneOf 提取为命名 schema(2026-07-25 回填批)。两个理由:
|
|
4286
|
+
# ① 内联形生成不出可复用具名类型;② 反射式 drift 门只按「命名 schema ↔ 同名 exported interface」配对,
|
|
4287
|
+
# 内联形对它不可见 —— 这块 wire 契约过去没有任何机器看守。
|
|
4288
|
+
# 🔴 为什么同时写顶层 `properties` 和 `oneOf`:门解析有效属性集时只展开 `$ref`/`allOf`,**不认 `oneOf`**
|
|
4289
|
+
# (`test/spec-field-drift-gate.test.ts` 的 `effectiveSpecProps`)。若只留 oneOf,门会认为本 schema
|
|
4290
|
+
# 「没有属性」从而当作整个 schema 缺席 ⇒ 回填等于没做。两者是合取关系(JSON Schema 语义):顶层
|
|
4291
|
+
# properties 给出字段全集(=门的比对面),oneOf 继续施加逐 kind 的形状校验,互不削弱。
|
|
4292
|
+
# nullability 现在挂在**引用点**(`gate: oneOf[$ref, null]`),不再是本 schema 的一个 union 臂 ——
|
|
4293
|
+
# 命名类型自身是对象形,更贴 TS 的 `gate?: CheckpointGate | null`。
|
|
4294
|
+
type: object
|
|
4295
|
+
description: >
|
|
4296
|
+
CheckpointGate — OPEN DISCRIMINATED SET (design/80 D-0), mirrors core src/core/checkpoint-store.ts.
|
|
4297
|
+
5 known kinds; consumers MUST branch on `kind` and render an UNKNOWN kind generically (core can mint a
|
|
4298
|
+
kind this contract predates — a core→wire contract test fails CI, not prod). Tool args / question text
|
|
4299
|
+
are NOT here — join the task's trace tool-call block via approvals' toolCallId.
|
|
4300
|
+
required: [kind]
|
|
4301
|
+
properties:
|
|
4302
|
+
kind:
|
|
4303
|
+
type: string
|
|
4304
|
+
description: >
|
|
4305
|
+
`human` — plain HITL approval (budget-auto-approvable). `irreversible_ask` — design/37
|
|
4306
|
+
irreversibility / design/70 egress tighten; NOT budgetable (load-bearing safety gate).
|
|
4307
|
+
`resource_limit` — design/74 cost/token/time slice boundary; resolve `{decision:"continue"}`.
|
|
4308
|
+
`needs_review` — design/76 dry-run/shadow → durable `needs_review` TERMINAL (post-prediction
|
|
4309
|
+
review, disjoint from the approval family). `task_done` — design/38 Path A background sub-task
|
|
4310
|
+
handle (door B never sees it).
|
|
4311
|
+
enum: [human, irreversible_ask, resource_limit, needs_review, task_done]
|
|
4312
|
+
x-open-enum: true # do not close this union — an unknown future kind is VALID on the wire
|
|
4313
|
+
reason: { type: string, description: 'present on human / irreversible_ask / resource_limit / needs_review (not task_done).' }
|
|
4314
|
+
toolName: { type: string, description: 'present on human / irreversible_ask.' }
|
|
4315
|
+
oneOf:
|
|
4316
|
+
- type: object # plain human approval (budget-auto-approvable)
|
|
4317
|
+
required: [kind, reason, toolName]
|
|
4318
|
+
properties: { kind: { const: human } }
|
|
4319
|
+
- type: object # design/37 irreversibility / design/70 egress safety-tighten — NOT budgetable (load-bearing safety gate)
|
|
4320
|
+
required: [kind, reason, toolName]
|
|
4321
|
+
properties: { kind: { const: irreversible_ask } }
|
|
4322
|
+
- type: object # design/74 resource (cost/token/time) slice boundary — resolve { decision: "continue" }
|
|
4323
|
+
required: [kind, reason]
|
|
4324
|
+
properties: { kind: { const: resource_limit } }
|
|
4325
|
+
- type: object # design/76 dry-run/shadow → durable needs_review TERMINAL (POST-prediction review, disjoint from approval family)
|
|
4326
|
+
required: [kind, reason]
|
|
4327
|
+
properties: { kind: { const: needs_review } }
|
|
4328
|
+
- type: object # design/38 Path A background sub-task handle (door B never sees it)
|
|
4329
|
+
required: [kind]
|
|
4330
|
+
properties: { kind: { const: task_done } }
|
|
4331
|
+
- type: object # OPEN SET — unknown future kind (e.g. design/80 D-B plan_review); render generically, never crash
|
|
4332
|
+
required: [kind]
|
|
4333
|
+
# 🔴 the pinned wire contract: exclude the 5 KNOWN kinds so a known kind matches ONLY its const member above
|
|
4334
|
+
# (not also this fallback) → keeps `oneOf` unambiguous AND preserves each kind's shape validation.
|
|
4335
|
+
# This fallback matches ONLY a future kind this contract predates. Add new known kinds to the enum.
|
|
4336
|
+
properties: { kind: { type: string, not: { enum: [human, irreversible_ask, resource_limit, needs_review, task_done] } } }
|
|
4337
|
+
|
|
3403
4338
|
Event_suspended:
|
|
3404
4339
|
type: object
|
|
3405
4340
|
description: HITL — the run paused on an F4 gate or AskUserQuestion. Resolve via approvals.decide, then resume.
|
|
@@ -3407,34 +4342,225 @@ components:
|
|
|
3407
4342
|
properties:
|
|
3408
4343
|
type: { const: suspended }
|
|
3409
4344
|
gate:
|
|
3410
|
-
description:
|
|
3411
|
-
CheckpointGate — OPEN DISCRIMINATED SET (design/80 D-0), mirrors core src/core/checkpoint-store.ts.
|
|
3412
|
-
5 known kinds below; consumers MUST branch on `kind` and render an UNKNOWN kind generically (core
|
|
3413
|
-
can mint a kind this contract predates — a core→wire contract test fails CI, not prod). Tool
|
|
3414
|
-
args/question text are NOT here — join the task's trace tool-call block via approvals' toolCallId.
|
|
4345
|
+
description: 'the gate the run paused on, or null.'
|
|
3415
4346
|
oneOf:
|
|
3416
|
-
-
|
|
3417
|
-
required: [kind, reason, toolName]
|
|
3418
|
-
properties: { kind: { const: human }, reason: { type: string }, toolName: { type: string } }
|
|
3419
|
-
- type: object # design/37 irreversibility / design/70 egress safety-tighten — NOT budgetable (load-bearing safety gate)
|
|
3420
|
-
required: [kind, reason, toolName]
|
|
3421
|
-
properties: { kind: { const: irreversible_ask }, reason: { type: string }, toolName: { type: string } }
|
|
3422
|
-
- type: object # design/74 resource (cost/token/time) slice boundary — resolve { decision: "continue" }
|
|
3423
|
-
required: [kind, reason]
|
|
3424
|
-
properties: { kind: { const: resource_limit }, reason: { type: string } }
|
|
3425
|
-
- type: object # design/76 dry-run/shadow → durable needs_review TERMINAL (POST-prediction review, disjoint from approval family)
|
|
3426
|
-
required: [kind, reason]
|
|
3427
|
-
properties: { kind: { const: needs_review }, reason: { type: string } }
|
|
3428
|
-
- type: object # design/38 Path A background sub-task handle (door B never sees it)
|
|
3429
|
-
required: [kind]
|
|
3430
|
-
properties: { kind: { const: task_done } }
|
|
3431
|
-
- type: object # OPEN SET — unknown future kind (e.g. design/80 D-B plan_review); render generically, never crash
|
|
3432
|
-
required: [kind]
|
|
3433
|
-
# 🔴 the pinned wire contract: exclude the 5 KNOWN kinds so a known kind matches ONLY its const member above
|
|
3434
|
-
# (not also this fallback) → keeps `oneOf` unambiguous AND preserves each kind's shape validation.
|
|
3435
|
-
# This fallback matches ONLY a future kind this contract predates. Add new known kinds to the enum.
|
|
3436
|
-
properties: { kind: { type: string, not: { enum: [human, irreversible_ask, resource_limit, needs_review, task_done] } } }
|
|
4347
|
+
- $ref: '#/components/schemas/CheckpointGate'
|
|
3437
4348
|
- type: 'null'
|
|
4349
|
+
ModelUsageDelta:
|
|
4350
|
+
# 新增(2026-07-25 回填批)。SDK 的 facade 审计把这个形状命名了一次(此前是在两个使用点各写一遍的匿名内联形:
|
|
4351
|
+
# `AgentEvent` 的 `model_usage` 臂 与 `done.result.stats.modelUsage` 的值类型,同源同形)。
|
|
4352
|
+
type: object
|
|
4353
|
+
description: >
|
|
4354
|
+
Per-model token/cost delta, keyed by model name in a `Record<string, ModelUsageDelta>`. Fields mirror
|
|
4355
|
+
`turn_end.usage`; ALL optional (open contract — tolerates future core fields).
|
|
4356
|
+
additionalProperties: true
|
|
4357
|
+
properties:
|
|
4358
|
+
inputTokens: { type: integer }
|
|
4359
|
+
outputTokens: { type: integer }
|
|
4360
|
+
cacheReadTokens: { type: integer }
|
|
4361
|
+
cacheWriteTokens: { type: integer }
|
|
4362
|
+
costMicroUsd:
|
|
4363
|
+
type: number
|
|
4364
|
+
description: >
|
|
4365
|
+
What THIS model's slice cost (micro-USD). ⚠️ Distinct concept from `spentMicroUsd`
|
|
4366
|
+
("cumulative already-incurred spend") — never treat the two as aliases.
|
|
4367
|
+
|
|
4368
|
+
PromptManifest:
|
|
4369
|
+
# 新增(2026-07-25 回填批):server ≥1.219 的 prompt-assembly manifest。此前本文件完全没有它(全文 0 次提及),
|
|
4370
|
+
# 尽管它同时是 `AgentEvent.prompt_assembled` 臂和 trace 流 `prompt-assembled` 帧的载荷。
|
|
4371
|
+
type: object
|
|
4372
|
+
description: >
|
|
4373
|
+
The prompt-assembly manifest (core's `prompt.assembled` trace contract verbatim). Carries ONLY
|
|
4374
|
+
ids/digests/counts — NEVER prompt bodies (privacy boundary). 🔴 Hashes are PROCESS-SALTED: they are NOT
|
|
4375
|
+
comparable across worker restarts, so a UI must never diff them cross-process. `constitution`/`blocks`/
|
|
4376
|
+
`totalChars` are the v1 face; `sections`/`tools` are the v2 ADDITIVE face (absent on a v1-only engine).
|
|
4377
|
+
⚠️ One task can carry MULTIPLE manifests — a cascade/verify run re-prepares under one taskId and every
|
|
4378
|
+
rung's manifest is persisted in emission order.
|
|
4379
|
+
required: [constitution, blocks, totalChars]
|
|
4380
|
+
additionalProperties: true
|
|
4381
|
+
properties:
|
|
4382
|
+
constitution:
|
|
4383
|
+
type: string
|
|
4384
|
+
description: 'who owned the constitution layer — `core` is the steady state; anything else is worth eyes.'
|
|
4385
|
+
enum: [core, replaced, provider-assembled, legacy]
|
|
4386
|
+
x-open-enum: true
|
|
4387
|
+
blocks:
|
|
4388
|
+
type: array
|
|
4389
|
+
items:
|
|
4390
|
+
type: object
|
|
4391
|
+
required: [id, chars, hash]
|
|
4392
|
+
additionalProperties: true
|
|
4393
|
+
properties:
|
|
4394
|
+
id: { type: string }
|
|
4395
|
+
chars: { type: integer }
|
|
4396
|
+
hash: { type: string, description: 'process-salted digest — never compare across restarts.' }
|
|
4397
|
+
sections:
|
|
4398
|
+
type: array
|
|
4399
|
+
description: 'v2 additive face — absent on a v1-only engine.'
|
|
4400
|
+
items:
|
|
4401
|
+
type: object
|
|
4402
|
+
required: [id, slot, carrier, cadence, cacheClass, chars, hash]
|
|
4403
|
+
additionalProperties: true
|
|
4404
|
+
properties:
|
|
4405
|
+
id: { type: string }
|
|
4406
|
+
slot: { type: string }
|
|
4407
|
+
carrier: { type: string }
|
|
4408
|
+
cadence: { type: string }
|
|
4409
|
+
cacheClass: { type: string }
|
|
4410
|
+
chars: { type: integer }
|
|
4411
|
+
hash: { type: string }
|
|
4412
|
+
tools:
|
|
4413
|
+
type: array
|
|
4414
|
+
description: 'v2 additive face — the tool contract summary.'
|
|
4415
|
+
items:
|
|
4416
|
+
type: object
|
|
4417
|
+
required: [wireName, aliases, contractId, implementationRevision, cardId, shapeDigest, wireSchemaDigest]
|
|
4418
|
+
additionalProperties: true
|
|
4419
|
+
properties:
|
|
4420
|
+
wireName: { type: string }
|
|
4421
|
+
aliases: { type: array, items: { type: string } }
|
|
4422
|
+
contractId: { type: string }
|
|
4423
|
+
implementationRevision: { type: string }
|
|
4424
|
+
cardId: { type: string }
|
|
4425
|
+
shapeDigest: { type: string }
|
|
4426
|
+
wireSchemaDigest: { type: string }
|
|
4427
|
+
totalChars: { type: integer }
|
|
4428
|
+
|
|
4429
|
+
Event_file_link:
|
|
4430
|
+
type: object
|
|
4431
|
+
description: >
|
|
4432
|
+
The engine SENT THE USER A FILE via a presigned link (probe `capabilities().sendUserFile` before
|
|
4433
|
+
rendering affordances). 🔴 `url` EXPIRES after `ttlSec` seconds — render a fetch-soon affordance, never
|
|
4434
|
+
persist the URL as durable.
|
|
4435
|
+
allOf: [{ $ref: '#/components/schemas/EventIdentity' }]
|
|
4436
|
+
required: [type, url, filename, size, ttlSec, status]
|
|
4437
|
+
properties:
|
|
4438
|
+
type: { const: file_link }
|
|
4439
|
+
url: { type: string, description: 'presigned download URL — EXPIRING, do not persist.' }
|
|
4440
|
+
filename: { type: string }
|
|
4441
|
+
size: { type: integer }
|
|
4442
|
+
ttlSec: { type: integer }
|
|
4443
|
+
status: { type: string, enum: [normal, proactive], description: '`normal` = a turn deliverable; `proactive` = a mid-run push.' }
|
|
4444
|
+
caption: { type: string }
|
|
4445
|
+
display: { type: string, enum: [render, attach], description: 'absent = the consumer''s default.' }
|
|
4446
|
+
|
|
4447
|
+
Event_prompt_assembled:
|
|
4448
|
+
type: object
|
|
4449
|
+
description: >
|
|
4450
|
+
DURABLE only (server ≥1.219) — the prepare's prompt-assembly manifest, FLATTENED onto the frame (the
|
|
4451
|
+
manifest's own keys sit at the top level next to `type`, they are NOT nested under a `manifest` key).
|
|
4452
|
+
Lands AHEAD of the first event of the turn it prepared. ⚠️ MULTIPLE per task on cascade/verify runs.
|
|
4453
|
+
allOf:
|
|
4454
|
+
- $ref: '#/components/schemas/PromptManifest'
|
|
4455
|
+
required: [type]
|
|
4456
|
+
properties:
|
|
4457
|
+
type: { const: prompt_assembled }
|
|
4458
|
+
|
|
4459
|
+
Event_model_usage:
|
|
4460
|
+
type: object
|
|
4461
|
+
description: >
|
|
4462
|
+
Per-model usage delta (live-verified on canary). `usage` is keyed BY MODEL NAME — same source as
|
|
4463
|
+
`done.result.stats.modelUsage` (lets a multi-model / role-routed run attribute spend per model).
|
|
4464
|
+
required: [type, usage]
|
|
4465
|
+
properties:
|
|
4466
|
+
type: { const: model_usage }
|
|
4467
|
+
usage:
|
|
4468
|
+
type: object
|
|
4469
|
+
additionalProperties: { $ref: '#/components/schemas/ModelUsageDelta' }
|
|
4470
|
+
|
|
4471
|
+
Event_task_notification:
|
|
4472
|
+
type: object
|
|
4473
|
+
description: >
|
|
4474
|
+
A BACKGROUND task (bg agent / bash / monitor / workflow / external) settled or emitted a batch while THIS
|
|
4475
|
+
run was live. The engine ALREADY injected the `<task-notification>` into the model in-process — this frame
|
|
4476
|
+
is the UI/display projection only. `partial:true` = a KILLED child's salvaged remnant (render as
|
|
4477
|
+
incomplete). `seq` = stop-cycle/batch counter (dedup key together with task_id + status).
|
|
4478
|
+
🔴 summary/result/lines/diagnostics are UNTRUSTED redacted free text — render, never re-feed to a model.
|
|
4479
|
+
allOf: [{ $ref: '#/components/schemas/EventIdentity' }]
|
|
4480
|
+
required: [type, task_id, task_type, status, summary]
|
|
4481
|
+
additionalProperties: true
|
|
4482
|
+
properties:
|
|
4483
|
+
type: { const: task_notification }
|
|
4484
|
+
task_id: { type: string }
|
|
4485
|
+
task_type: { type: string }
|
|
4486
|
+
status: { type: string }
|
|
4487
|
+
summary: { type: string, description: 'UNTRUSTED display text.' }
|
|
4488
|
+
sessionId: { type: string }
|
|
4489
|
+
toolUseId: { type: string }
|
|
4490
|
+
seq: { type: integer }
|
|
4491
|
+
source: { type: string }
|
|
4492
|
+
lines: { type: array, items: { type: string } }
|
|
4493
|
+
stoppedBy: { type: string }
|
|
4494
|
+
exitCode: { type: integer }
|
|
4495
|
+
partial: { type: boolean, description: '`true` = a KILLED child''s salvaged remnant — render as incomplete.' }
|
|
4496
|
+
diagnostics: { type: string }
|
|
4497
|
+
recentSteps:
|
|
4498
|
+
type: array
|
|
4499
|
+
items:
|
|
4500
|
+
type: object
|
|
4501
|
+
required: [tool, target, outcome]
|
|
4502
|
+
additionalProperties: true
|
|
4503
|
+
properties: { tool: { type: string }, target: { type: string }, outcome: { type: string } }
|
|
4504
|
+
editedFiles:
|
|
4505
|
+
type: array
|
|
4506
|
+
items:
|
|
4507
|
+
type: object
|
|
4508
|
+
required: [path, edits]
|
|
4509
|
+
additionalProperties: true
|
|
4510
|
+
properties: { path: { type: string }, edits: { type: integer } }
|
|
4511
|
+
resumable: { type: boolean }
|
|
4512
|
+
result: { type: string, description: 'UNTRUSTED display text.' }
|
|
4513
|
+
output_file: { type: string }
|
|
4514
|
+
usage: { description: 'open shape — usage rollup of the background task.' }
|
|
4515
|
+
|
|
4516
|
+
Event_diagnostics:
|
|
4517
|
+
type: object
|
|
4518
|
+
description: >
|
|
4519
|
+
NEW LSP diagnostics drained at a turn boundary (server-side redacted). The model already got the context
|
|
4520
|
+
message in-process; this frame is the RENDER source.
|
|
4521
|
+
allOf: [{ $ref: '#/components/schemas/EventIdentity' }]
|
|
4522
|
+
required: [type, files]
|
|
4523
|
+
additionalProperties: true
|
|
4524
|
+
properties:
|
|
4525
|
+
type: { const: diagnostics }
|
|
4526
|
+
files:
|
|
4527
|
+
type: array
|
|
4528
|
+
items:
|
|
4529
|
+
type: object
|
|
4530
|
+
required: [uri, diagnostics]
|
|
4531
|
+
additionalProperties: true
|
|
4532
|
+
properties:
|
|
4533
|
+
uri: { type: string }
|
|
4534
|
+
diagnostics:
|
|
4535
|
+
type: array
|
|
4536
|
+
items:
|
|
4537
|
+
type: object
|
|
4538
|
+
required: [message]
|
|
4539
|
+
additionalProperties: true
|
|
4540
|
+
properties:
|
|
4541
|
+
message: { type: string }
|
|
4542
|
+
severity: { type: integer }
|
|
4543
|
+
range: { description: 'open shape (LSP Range).' }
|
|
4544
|
+
code: { type: ['string', 'integer'] }
|
|
4545
|
+
source: { type: string }
|
|
4546
|
+
isNew: { type: boolean }
|
|
4547
|
+
|
|
4548
|
+
Event_steering_injected:
|
|
4549
|
+
type: object
|
|
4550
|
+
description: >
|
|
4551
|
+
A mid-run system-reminder core injected into the model's context (todo / file-change / date-roll /
|
|
4552
|
+
skills-delta / …). The model already got the injected text in-process; this frame is the RENDER source
|
|
4553
|
+
(`source` picks the icon/label, `preview` is the truncated display text — server-side redacted).
|
|
4554
|
+
allOf: [{ $ref: '#/components/schemas/EventIdentity' }]
|
|
4555
|
+
required: [type, source, preview]
|
|
4556
|
+
additionalProperties: true
|
|
4557
|
+
properties:
|
|
4558
|
+
type: { const: steering_injected }
|
|
4559
|
+
source:
|
|
4560
|
+
type: string
|
|
4561
|
+
description: 'OPEN string — deliberately NOT the closed core enum, so a future core source value cannot runtime-crash a strict switch.'
|
|
4562
|
+
preview: { type: string, description: 'truncated, redacted display text — UNTRUSTED.' }
|
|
4563
|
+
|
|
3438
4564
|
Event_done:
|
|
3439
4565
|
type: object
|
|
3440
4566
|
description: Carries the full TaskResult (output string at .result, stats at .stats) — service Drift 4.
|