@sema-agent/sdk 0.0.101 → 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 +853 -74
- 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]
|
|
@@ -1997,6 +2228,58 @@ components:
|
|
|
1997
2228
|
# passes them through rather than dropping, so consumers must not assume this list is exhaustive.
|
|
1998
2229
|
additionalProperties: true
|
|
1999
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.' }
|
|
2282
|
+
|
|
2000
2283
|
TaskRequest:
|
|
2001
2284
|
type: object
|
|
2002
2285
|
description: >
|
|
@@ -2156,14 +2439,15 @@ components:
|
|
|
2156
2439
|
cwd: { type: string, description: Working directory for the execution env. }
|
|
2157
2440
|
selfOrchestration: { type: boolean, description: Permit S8 self-orchestration (run_workflow) inside this task. }
|
|
2158
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 加字段而这里不加,门就会红。这就是"重复"这次可以接受的原因:它被机器看住了。
|
|
2159
2448
|
agents:
|
|
2160
2449
|
type: array
|
|
2161
|
-
items:
|
|
2162
|
-
type: object
|
|
2163
|
-
description: >
|
|
2164
|
-
One per-task sub-agent definition. Shape owned by `TaskAgentDefinition` in the SDK types; kept OPEN
|
|
2165
|
-
here rather than duplicated (same reasoning as `settings`).
|
|
2166
|
-
additionalProperties: true
|
|
2450
|
+
items: { $ref: '#/components/schemas/TaskAgentDefinition' }
|
|
2167
2451
|
description: Per-task sub-agent definitions (roster additions scoped to this task only).
|
|
2168
2452
|
interactiveTools: { type: boolean, description: Mount interactive (prompting) tools. }
|
|
2169
2453
|
retainBackgroundProcesses: { type: boolean, description: Keep background processes alive past the turn. }
|
|
@@ -2371,6 +2655,93 @@ components:
|
|
|
2371
2655
|
error: { type: string }
|
|
2372
2656
|
retainedFrom: { type: integer, description: Lowest event seq still retained; resume events from here. }
|
|
2373
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
|
+
|
|
2374
2745
|
QuotaError:
|
|
2375
2746
|
type: object
|
|
2376
2747
|
description: 429 per-principal cumulative-quota body (`quotaExceeded`).
|
|
@@ -2867,6 +3238,46 @@ components:
|
|
|
2867
3238
|
endedAt: { type: integer, description: 'End epoch ms (absent while running).' }
|
|
2868
3239
|
createdAt: { type: integer, description: 'Record-creation epoch ms (listByScope sort key).' }
|
|
2869
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
|
+
|
|
2870
3281
|
WorkflowRun:
|
|
2871
3282
|
type: object
|
|
2872
3283
|
description: >
|
|
@@ -2881,7 +3292,13 @@ components:
|
|
|
2881
3292
|
description: { type: string, description: "The workflow script's declared `meta.description` (one-liner)." }
|
|
2882
3293
|
status: { $ref: '#/components/schemas/WorkflowRunStatus' }
|
|
2883
3294
|
phases: { type: array, description: 'Phase records (permissive).', items: {} }
|
|
2884
|
-
|
|
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' }
|
|
2885
3302
|
stats:
|
|
2886
3303
|
type: object
|
|
2887
3304
|
description: 'Token stats — own at stats.tokens, nested at stats.nested.tokens (R-5 own/nested split).'
|
|
@@ -3198,27 +3615,79 @@ components:
|
|
|
3198
3615
|
type: array
|
|
3199
3616
|
items: { $ref: '#/components/schemas/InboxRow' }
|
|
3200
3617
|
|
|
3201
|
-
|
|
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 名为准对齐。
|
|
3202
3662
|
type: object
|
|
3203
3663
|
description: >
|
|
3204
3664
|
ASSISTANT-WIRE-CONTRACT §3 — a scheduler-overview row = run-store `listRuns(owner)` joined with the core
|
|
3205
3665
|
scheduler seam. ⚠️ `createdAt`/`updatedAt` are ISO date-time strings (unlike inbox/§1 epoch-ms).
|
|
3206
|
-
required: [taskId, sessionId, status, needsAttention, createdAt, updatedAt]
|
|
3666
|
+
required: [taskId, sessionId, status, needsAttention, gate, createdAt, updatedAt]
|
|
3207
3667
|
additionalProperties: true
|
|
3208
3668
|
properties:
|
|
3209
3669
|
taskId: { type: string }
|
|
3210
3670
|
sessionId: { type: string }
|
|
3211
|
-
status:
|
|
3212
|
-
|
|
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`.' }
|
|
3213
3686
|
gate:
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
kind: { type: string, description: 'same open set as gateKind.' }
|
|
3219
|
-
severity: { type: ['integer', 'null'], enum: [1, 2, 3, 4, 5, null] }
|
|
3220
|
-
spentMicroUsd: { type: ['number', 'null'] }
|
|
3221
|
-
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'
|
|
3222
3691
|
createdAt: { type: string, description: ISO date-time. }
|
|
3223
3692
|
updatedAt: { type: string, description: ISO date-time. }
|
|
3224
3693
|
|
|
@@ -3232,7 +3701,39 @@ components:
|
|
|
3232
3701
|
properties:
|
|
3233
3702
|
tasks:
|
|
3234
3703
|
type: array
|
|
3235
|
-
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.' }
|
|
3236
3737
|
|
|
3237
3738
|
PlanReviewRequest:
|
|
3238
3739
|
type: object
|
|
@@ -3309,6 +3810,23 @@ components:
|
|
|
3309
3810
|
offset: { type: integer, description: Index of the first returned message within the full context. }
|
|
3310
3811
|
total: { type: integer, description: Total messages available (so a client can page). }
|
|
3311
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
|
+
|
|
3312
3830
|
PromptEpoch:
|
|
3313
3831
|
type: object
|
|
3314
3832
|
description: >
|
|
@@ -3578,6 +4096,16 @@ components:
|
|
|
3578
4096
|
- $ref: '#/components/schemas/Event_task_progress'
|
|
3579
4097
|
- $ref: '#/components/schemas/Event_workspace_changed'
|
|
3580
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'
|
|
3581
4109
|
- $ref: '#/components/schemas/Event_done'
|
|
3582
4110
|
- $ref: '#/components/schemas/Event_failed'
|
|
3583
4111
|
discriminator:
|
|
@@ -3596,6 +4124,12 @@ components:
|
|
|
3596
4124
|
task_progress: '#/components/schemas/Event_task_progress'
|
|
3597
4125
|
workspace_changed: '#/components/schemas/Event_workspace_changed'
|
|
3598
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'
|
|
3599
4133
|
done: '#/components/schemas/Event_done'
|
|
3600
4134
|
failed: '#/components/schemas/Event_failed'
|
|
3601
4135
|
|
|
@@ -3747,6 +4281,60 @@ components:
|
|
|
3747
4281
|
properties:
|
|
3748
4282
|
type: { const: workspace_changed }
|
|
3749
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
|
+
|
|
3750
4338
|
Event_suspended:
|
|
3751
4339
|
type: object
|
|
3752
4340
|
description: HITL — the run paused on an F4 gate or AskUserQuestion. Resolve via approvals.decide, then resume.
|
|
@@ -3754,34 +4342,225 @@ components:
|
|
|
3754
4342
|
properties:
|
|
3755
4343
|
type: { const: suspended }
|
|
3756
4344
|
gate:
|
|
3757
|
-
description:
|
|
3758
|
-
CheckpointGate — OPEN DISCRIMINATED SET (design/80 D-0), mirrors core src/core/checkpoint-store.ts.
|
|
3759
|
-
5 known kinds below; consumers MUST branch on `kind` and render an UNKNOWN kind generically (core
|
|
3760
|
-
can mint a kind this contract predates — a core→wire contract test fails CI, not prod). Tool
|
|
3761
|
-
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.'
|
|
3762
4346
|
oneOf:
|
|
3763
|
-
-
|
|
3764
|
-
required: [kind, reason, toolName]
|
|
3765
|
-
properties: { kind: { const: human }, reason: { type: string }, toolName: { type: string } }
|
|
3766
|
-
- type: object # design/37 irreversibility / design/70 egress safety-tighten — NOT budgetable (load-bearing safety gate)
|
|
3767
|
-
required: [kind, reason, toolName]
|
|
3768
|
-
properties: { kind: { const: irreversible_ask }, reason: { type: string }, toolName: { type: string } }
|
|
3769
|
-
- type: object # design/74 resource (cost/token/time) slice boundary — resolve { decision: "continue" }
|
|
3770
|
-
required: [kind, reason]
|
|
3771
|
-
properties: { kind: { const: resource_limit }, reason: { type: string } }
|
|
3772
|
-
- type: object # design/76 dry-run/shadow → durable needs_review TERMINAL (POST-prediction review, disjoint from approval family)
|
|
3773
|
-
required: [kind, reason]
|
|
3774
|
-
properties: { kind: { const: needs_review }, reason: { type: string } }
|
|
3775
|
-
- type: object # design/38 Path A background sub-task handle (door B never sees it)
|
|
3776
|
-
required: [kind]
|
|
3777
|
-
properties: { kind: { const: task_done } }
|
|
3778
|
-
- type: object # OPEN SET — unknown future kind (e.g. design/80 D-B plan_review); render generically, never crash
|
|
3779
|
-
required: [kind]
|
|
3780
|
-
# 🔴 the pinned wire contract: exclude the 5 KNOWN kinds so a known kind matches ONLY its const member above
|
|
3781
|
-
# (not also this fallback) → keeps `oneOf` unambiguous AND preserves each kind's shape validation.
|
|
3782
|
-
# This fallback matches ONLY a future kind this contract predates. Add new known kinds to the enum.
|
|
3783
|
-
properties: { kind: { type: string, not: { enum: [human, irreversible_ask, resource_limit, needs_review, task_done] } } }
|
|
4347
|
+
- $ref: '#/components/schemas/CheckpointGate'
|
|
3784
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
|
+
|
|
3785
4564
|
Event_done:
|
|
3786
4565
|
type: object
|
|
3787
4566
|
description: Carries the full TaskResult (output string at .result, stats at .stats) — service Drift 4.
|