@sema-agent/sdk 4.1.0 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -1
- package/dist/client.d.ts +10 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +7 -2
- package/dist/client.js.map +1 -1
- package/dist/control-types.d.ts +22 -4
- package/dist/control-types.d.ts.map +1 -1
- package/dist/control-types.js +3 -1
- package/dist/control-types.js.map +1 -1
- package/dist/errors.d.ts +42 -5
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +81 -7
- package/dist/errors.js.map +1 -1
- package/dist/events.d.ts +63 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/health.d.ts +76 -7
- package/dist/health.d.ts.map +1 -1
- package/dist/health.js +40 -2
- package/dist/health.js.map +1 -1
- package/dist/idempotency.d.ts +11 -1
- package/dist/idempotency.d.ts.map +1 -1
- package/dist/idempotency.js +11 -1
- package/dist/idempotency.js.map +1 -1
- package/dist/index.d.ts +18 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -2
- package/dist/index.js.map +1 -1
- package/dist/registry/health.d.ts +6 -1
- package/dist/registry/health.d.ts.map +1 -1
- package/dist/registry/health.js +6 -4
- package/dist/registry/health.js.map +1 -1
- package/dist/registry/index.d.ts +7 -1
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js +7 -1
- package/dist/registry/index.js.map +1 -1
- package/dist/resources/approvals.d.ts +43 -13
- package/dist/resources/approvals.d.ts.map +1 -1
- package/dist/resources/approvals.js +35 -12
- package/dist/resources/approvals.js.map +1 -1
- package/dist/resources/assistant.d.ts +21 -4
- package/dist/resources/assistant.d.ts.map +1 -1
- package/dist/resources/assistant.js +10 -3
- package/dist/resources/assistant.js.map +1 -1
- package/dist/resources/attachments.d.ts +9 -2
- package/dist/resources/attachments.d.ts.map +1 -1
- package/dist/resources/attachments.js.map +1 -1
- package/dist/resources/control/secrets.d.ts +10 -1
- package/dist/resources/control/secrets.d.ts.map +1 -1
- package/dist/resources/control/secrets.js +10 -1
- package/dist/resources/control/secrets.js.map +1 -1
- package/dist/resources/fleet.d.ts +11 -5
- package/dist/resources/fleet.d.ts.map +1 -1
- package/dist/resources/fleet.js +2 -1
- package/dist/resources/fleet.js.map +1 -1
- package/dist/resources/images.d.ts +10 -1
- package/dist/resources/images.d.ts.map +1 -1
- package/dist/resources/images.js +20 -5
- package/dist/resources/images.js.map +1 -1
- package/dist/resources/leader.d.ts +7 -3
- package/dist/resources/leader.d.ts.map +1 -1
- package/dist/resources/leader.js +7 -3
- package/dist/resources/leader.js.map +1 -1
- package/dist/resources/ops.d.ts +29 -2
- package/dist/resources/ops.d.ts.map +1 -1
- package/dist/resources/ops.js +6 -1
- package/dist/resources/ops.js.map +1 -1
- package/dist/resources/runs.d.ts +89 -18
- package/dist/resources/runs.d.ts.map +1 -1
- package/dist/resources/runs.js +53 -17
- package/dist/resources/runs.js.map +1 -1
- package/dist/resources/session-sync.d.ts +77 -17
- package/dist/resources/session-sync.d.ts.map +1 -1
- package/dist/resources/session-sync.js +81 -20
- package/dist/resources/session-sync.js.map +1 -1
- package/dist/resources/sessions.d.ts +82 -13
- package/dist/resources/sessions.d.ts.map +1 -1
- package/dist/resources/sessions.js +39 -7
- package/dist/resources/sessions.js.map +1 -1
- package/dist/resources/tool-approvals.d.ts +8 -5
- package/dist/resources/tool-approvals.d.ts.map +1 -1
- package/dist/resources/tool-approvals.js +2 -1
- package/dist/resources/tool-approvals.js.map +1 -1
- package/dist/resources/trace.d.ts +17 -3
- package/dist/resources/trace.d.ts.map +1 -1
- package/dist/resources/trace.js +25 -5
- package/dist/resources/trace.js.map +1 -1
- package/dist/resources/workflows.d.ts +42 -10
- package/dist/resources/workflows.d.ts.map +1 -1
- package/dist/resources/workflows.js +46 -9
- package/dist/resources/workflows.js.map +1 -1
- package/dist/resources/workspace.d.ts +36 -11
- package/dist/resources/workspace.d.ts.map +1 -1
- package/dist/resources/workspace.js.map +1 -1
- package/dist/sse.d.ts +58 -14
- package/dist/sse.d.ts.map +1 -1
- package/dist/sse.js +88 -15
- package/dist/sse.js.map +1 -1
- package/dist/sync.d.ts +37 -8
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +24 -8
- package/dist/sync.js.map +1 -1
- package/dist/transport.d.ts +31 -4
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +38 -6
- package/dist/transport.js.map +1 -1
- package/dist/types.d.ts +156 -51
- package/dist/types.d.ts.map +1 -1
- package/openapi.yaml +377 -59
- package/package.json +2 -2
- package/registry-openapi.yaml +34 -3
package/openapi.yaml
CHANGED
|
@@ -494,12 +494,20 @@ paths:
|
|
|
494
494
|
turn (FIFO), spread across turns. FORWARD-DRAFT: core's steer is harness-level today, not
|
|
495
495
|
per-call; the per-call mapping is pending D-A core.
|
|
496
496
|
responses:
|
|
497
|
-
'200':
|
|
497
|
+
'200':
|
|
498
|
+
description: Steer accepted and APPLIED to the live run on this replica (`delivery:"applied"`).
|
|
499
|
+
content:
|
|
500
|
+
application/json:
|
|
501
|
+
schema: { $ref: '#/components/schemas/SteerReceipt' }
|
|
498
502
|
'202':
|
|
499
503
|
description: >-
|
|
500
|
-
Steer accepted and
|
|
501
|
-
|
|
502
|
-
(`
|
|
504
|
+
Steer accepted and PARKED. Two shapes share this code — branch on `delivery`, not the status:
|
|
505
|
+
a durable-`suspended` run parks on its pending checkpoint (`delivery:"queued"`) and drains on resume;
|
|
506
|
+
an ALREADY-ENDED run gets a freshly-minted `task_done` checkpoint (`delivery:"parked_for_wake"`) and
|
|
507
|
+
the message is delivered only by POST /v1/sessions/{sessionId}/wake.
|
|
508
|
+
content:
|
|
509
|
+
application/json:
|
|
510
|
+
schema: { $ref: '#/components/schemas/SteerReceipt' }
|
|
503
511
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
504
512
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
505
513
|
'409':
|
|
@@ -1278,9 +1286,10 @@ paths:
|
|
|
1278
1286
|
description: Delivered onto the live stream.
|
|
1279
1287
|
content:
|
|
1280
1288
|
application/json:
|
|
1289
|
+
# 封闭(census 批2 第三段,2026-07-30):live 臂铸造点 `routes/notify-wake.ts:98` 是两键字面量。
|
|
1290
|
+
# 4.3.0:形提成具名 `SessionNotifyResult` 的 live 臂(SDK 同批给了判别联合返回型)。
|
|
1281
1291
|
schema:
|
|
1282
1292
|
type: object
|
|
1283
|
-
# 封闭(census 批2 第三段,2026-07-30):live 臂铸造点 `routes/notify-wake.ts:86` 是两键字面量。
|
|
1284
1293
|
additionalProperties: false
|
|
1285
1294
|
required: [sessionId, delivery]
|
|
1286
1295
|
properties:
|
|
@@ -1290,9 +1299,9 @@ paths:
|
|
|
1290
1299
|
description: No live stream — parked in the session inbox, drained on the next stream open.
|
|
1291
1300
|
content:
|
|
1292
1301
|
application/json:
|
|
1302
|
+
# 封闭 + note 补 required:parked 臂铸造点 `routes/notify-wake.ts:116` 是三键字面量,note 无条件。
|
|
1293
1303
|
schema:
|
|
1294
1304
|
type: object
|
|
1295
|
-
# 封闭 + note 补 required:parked 臂铸造点 `routes/notify-wake.ts:104` 是三键字面量,note 无条件。
|
|
1296
1305
|
additionalProperties: false
|
|
1297
1306
|
required: [sessionId, delivery, note]
|
|
1298
1307
|
properties:
|
|
@@ -1387,26 +1396,11 @@ paths:
|
|
|
1387
1396
|
description: The snapshot listing.
|
|
1388
1397
|
content:
|
|
1389
1398
|
application/json:
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
required: [sessionId, snapshots, total]
|
|
1396
|
-
properties:
|
|
1397
|
-
sessionId: { type: string }
|
|
1398
|
-
snapshots:
|
|
1399
|
-
type: array
|
|
1400
|
-
items:
|
|
1401
|
-
type: object
|
|
1402
|
-
additionalProperties: false
|
|
1403
|
-
required: [key, files]
|
|
1404
|
-
properties:
|
|
1405
|
-
key: { type: string }
|
|
1406
|
-
files: { type: integer }
|
|
1407
|
-
bytes: { type: integer }
|
|
1408
|
-
latest: { type: string }
|
|
1409
|
-
total: { type: integer }
|
|
1399
|
+
# 封闭两层(census 批2 第三段,2026-07-30):铸造点 `routes/sessions.ts:624-629`(信封)与
|
|
1400
|
+
# `:620`(行)。条件键=信封 `latest`(零快照即省略)、行 `bytes`(blobSizes 面缺席=诚实省略)。
|
|
1401
|
+
# 4.3.0:形提成具名 `WorkspaceSnapshotPage`(SDK 同批把返回位的内联字面量也提成了 exported type,
|
|
1402
|
+
# 让 spec-resource-schema-gate 罩得住 —— CAPS-OPS-8)。
|
|
1403
|
+
schema: { $ref: '#/components/schemas/WorkspaceSnapshotPage' }
|
|
1410
1404
|
'400': { $ref: '#/components/responses/BadRequest' }
|
|
1411
1405
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
1412
1406
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
@@ -1447,27 +1441,10 @@ paths:
|
|
|
1447
1441
|
description: One page of the tree.
|
|
1448
1442
|
content:
|
|
1449
1443
|
application/json:
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
additionalProperties: false
|
|
1455
|
-
required: [sessionId, key, entries, total]
|
|
1456
|
-
properties:
|
|
1457
|
-
sessionId: { type: string }
|
|
1458
|
-
key: { type: string }
|
|
1459
|
-
entries:
|
|
1460
|
-
type: array
|
|
1461
|
-
items:
|
|
1462
|
-
type: object
|
|
1463
|
-
additionalProperties: false
|
|
1464
|
-
required: [path, hash]
|
|
1465
|
-
properties:
|
|
1466
|
-
path: { type: string }
|
|
1467
|
-
hash: { type: string }
|
|
1468
|
-
size: { type: integer }
|
|
1469
|
-
total: { type: integer }
|
|
1470
|
-
nextOffset: { type: integer }
|
|
1444
|
+
# 封闭两层(census 批2 第三段,2026-07-30):铸造点 `routes/sessions.ts:651-657`(信封)与
|
|
1445
|
+
# `:654`(行)。条件键=信封 `nextOffset`(尾页省略)、行 `size`(blobSizes 面缺席省略)。
|
|
1446
|
+
# 4.3.0:形提成具名 `WorkspaceTreePage`(理由同 list 腿 —— CAPS-OPS-8)。
|
|
1447
|
+
schema: { $ref: '#/components/schemas/WorkspaceTreePage' }
|
|
1471
1448
|
'400': { $ref: '#/components/responses/BadRequest' }
|
|
1472
1449
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
1473
1450
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
@@ -1688,7 +1665,11 @@ paths:
|
|
|
1688
1665
|
2c session-sync PULL — the THIN snapshot: entry IDS (oldest-first, NOT payloads — those stream via
|
|
1689
1666
|
`/sync/entries`) + per-snapshot relPath→blobHash + policy + anchors + leaf. The local peer feeds `entryIds`
|
|
1690
1667
|
to the §7 classifier to decide fast-forward/fork BEFORE pulling the entry stream + only the blob hashes it
|
|
1691
|
-
lacks. Owner-scoped (non-owner → 404, no oracle); 400 on
|
|
1668
|
+
lacks. Owner-scoped (non-owner → 404, no oracle); 400 on an id that is not uuid-SHAPED — 🔴 the sync family's
|
|
1669
|
+
gate is `isUuidShape` (ANY uuid version), NOT `isUuidV7`: server `routes/session-sync.ts:135-138` deliberately
|
|
1670
|
+
keeps a v4-keyed legacy shell session pushable (it was creatable via the lenient submit face), while
|
|
1671
|
+
crafted-id classes stay shut out. `fork`/`delete`/`policy` DO use `isUuidV7` — only this family is lenient;
|
|
1672
|
+
501 without a durable session store.
|
|
1692
1673
|
responses:
|
|
1693
1674
|
'200':
|
|
1694
1675
|
description: The manifest, wrapped as `{ manifest }`.
|
|
@@ -1731,7 +1712,7 @@ paths:
|
|
|
1731
1712
|
at 200 BEFORE the first line, so a mid-stream failure ends the body WITHOUT the trailer — the trailer's
|
|
1732
1713
|
ABSENCE (or a count mismatch) is the SOLE truncation signal (NO 5xx mid-stream). The SDK reader throws
|
|
1733
1714
|
`SyncTruncatedError` on a missing trailer / count mismatch. Owner-scoped (404); 400 on a bad afterSeq /
|
|
1734
|
-
non-
|
|
1715
|
+
non-uuid-SHAPED id (ANY uuid version passes — see the manifest leg); 501 without a durable entry-streaming store.
|
|
1735
1716
|
responses:
|
|
1736
1717
|
'200':
|
|
1737
1718
|
description: The NDJSON entry stream (begin / entry× N / end-trailer).
|
|
@@ -1836,7 +1817,8 @@ paths:
|
|
|
1836
1817
|
description: >
|
|
1837
1818
|
2c session-sync PLAN — classify the §7 relation between the LOCAL peer's `entryIds` (oldest-first, the SOURCE)
|
|
1838
1819
|
and the cloud's current log (the DST), WITHOUT writing. Returns the `SyncRelation` (`fresh` for a fresh cloud
|
|
1839
|
-
session). own-or-FRESH gate; 400 on a non-string-array body / non-
|
|
1820
|
+
session). own-or-FRESH gate; 400 on a non-string-array body / a non-uuid-SHAPED id (ANY uuid version passes —
|
|
1821
|
+
see the manifest leg). Unlike import, plan NEVER 409s —
|
|
1840
1822
|
a fork/stale is REPORTED in the relation, not raised.
|
|
1841
1823
|
requestBody:
|
|
1842
1824
|
required: true
|
|
@@ -1893,6 +1875,20 @@ paths:
|
|
|
1893
1875
|
policy: { type: array, items: { $ref: '#/components/schemas/SessionRulesRecord' } }
|
|
1894
1876
|
anchors: { type: array, items: { $ref: '#/components/schemas/SyncAnchor' } }
|
|
1895
1877
|
resolution: { type: string, enum: [overwrite-dst], description: Override a fork/stale loss-of-history conflict. }
|
|
1878
|
+
logDigest:
|
|
1879
|
+
type: string
|
|
1880
|
+
description: >
|
|
1881
|
+
🔴 OPTIONAL content digest of the SOURCE's whole entry log (core `sessionLogDigest`, scheme
|
|
1882
|
+
`sema-log-v3`; this leg's core floor is ^1.416.0). Server producer/consumer:
|
|
1883
|
+
`routes/session-sync.ts:295,310,357-366`. This is THE key that makes `ImportStaged.payloadVerified:true`
|
|
1884
|
+
reachable — until 4.3.0 the response schema promised a `payloadVerified`/`entry-ids+digest` pair
|
|
1885
|
+
that the request side had no way to trigger. Rationale: `identical` is classified from entry-id
|
|
1886
|
+
SETS only, and an entry id is a uuidv7 (NOT content-addressed), so "same ids, different payloads"
|
|
1887
|
+
is structurally possible and would be reported as already-synced. Supply this and the server
|
|
1888
|
+
recomputes the digest over its own log: equal ⇒ `basis:"entry-ids+digest"` + `payloadVerified:true`;
|
|
1889
|
+
different or not comparable ⇒ it does NOT short-circuit and stages a full sync (safe direction).
|
|
1890
|
+
A malformed value is NOT rejected — it is treated as absent (a digest mismatch must never become
|
|
1891
|
+
an error, a 409, or a refusal to sync).
|
|
1896
1892
|
responses:
|
|
1897
1893
|
'200':
|
|
1898
1894
|
description: Staged (or `identical` no-op).
|
|
@@ -2070,7 +2066,17 @@ paths:
|
|
|
2070
2066
|
application/json:
|
|
2071
2067
|
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
2072
2068
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
2073
|
-
'404':
|
|
2069
|
+
'404':
|
|
2070
|
+
description: >
|
|
2071
|
+
Owner-gate / unknown session (no existence oracle), OR — [2400] CB-2, declared 2026-08-02 — the core
|
|
2072
|
+
code `checkpoint.not_found`: the pending checkpoint this decide addressed is gone. It is the ONE
|
|
2073
|
+
member of the mirrored `checkpoint.*` family the server sends as a 404 rather than a 409
|
|
2074
|
+
(`src/http/server.ts:2199`: `e.code === "checkpoint.not_found" ? 404 : 409`), so the SDK maps it to
|
|
2075
|
+
NotFoundError while the rest of the family maps to ConflictError. Client action: refetch the inbox —
|
|
2076
|
+
do not retry this decide.
|
|
2077
|
+
content:
|
|
2078
|
+
application/json:
|
|
2079
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
2074
2080
|
'409':
|
|
2075
2081
|
description: >
|
|
2076
2082
|
Either a session-CAS conflict (`ErrorResponse.activeTaskId`), OR a design/80 D-1
|
|
@@ -2078,6 +2084,20 @@ paths:
|
|
|
2078
2084
|
NOT match the current pending action (TOCTOU/swap). The SDK splits these by `errorCode` into
|
|
2079
2085
|
ConflictError vs ApprovalBindingMismatchError. binding_mismatch = SAFETY signal: refetch + re-present
|
|
2080
2086
|
to the human, NEVER auto-retry.
|
|
2087
|
+
FOURTH member ([2400] CB-2, declared 2026-08-02): `gate_not_tool_approval` — the suspension this
|
|
2088
|
+
sessionId is parked on is NOT a tool-approval gate (`src/http/server.ts:1581` rejects pre-CAS when the
|
|
2089
|
+
gate kind is neither `human` nor `irreversible_ask`: nothing is consumed, no model leg burns). It is
|
|
2090
|
+
the THIRD member of the wrong-door guard family alongside `gate_not_resumable` (§4b) and
|
|
2091
|
+
`gate_not_plan_review` (§4c) → SDK `GateNotToolApprovalError`. Client action: route by the row's
|
|
2092
|
+
`gateKind` — `plan_review` → `POST /v1/assistant/tasks/{taskId}/plan_review`, `resource_limit` →
|
|
2093
|
+
`POST /v1/assistant/tasks/{taskId}/resume`. Retrying the same body never succeeds.
|
|
2094
|
+
FIFTH group ([2400] CB-2): the core `checkpoint.*` family the server mirrors verbatim
|
|
2095
|
+
(`src/http/server.ts:2199-2206`) — `checkpoint.gate_mismatch` / `checkpoint.reopen_failed` /
|
|
2096
|
+
`checkpoint.reopen_revote` / `checkpoint.already_exists` / `checkpoint.resume_aborted` /
|
|
2097
|
+
`checkpoint.unsupported_version` all arrive as 409 and fall on the SDK's `checkpoint.` PREFIX family
|
|
2098
|
+
(→ ConflictError, `.errorCode` carried verbatim; an OPEN set, so a future core code degrades with
|
|
2099
|
+
information instead of collapsing anonymously). The one non-409 member is `checkpoint.not_found`,
|
|
2100
|
+
which the same mint point sends as a 404 (see below).
|
|
2081
2101
|
THIRD member (moved here from a documented-but-nonexistent 410, 2026-07-31): `approval_stale`
|
|
2082
2102
|
(`errorCode`; `terminal:"resolved"` when attributable, else the key is absent) — the checkpoint is
|
|
2083
2103
|
already terminal (someone resolved it / abandonment-TTL GC / SLA resolve-deny). Client action:
|
|
@@ -2981,7 +3001,12 @@ paths:
|
|
|
2981
3001
|
per-row delta for every transition. Frame order: `event: meta` `{version, scoped}` → `event: snapshot`
|
|
2982
3002
|
`{tasks, workflows, ts}` → then `event: task`/`event: workflow` UPSERTS (each `data: {row, ts}` is the
|
|
2983
3003
|
POST-MERGE FULL row — replace by `row.id`, NOT a sparse patch) + `event: task_remove`/`event:
|
|
2984
|
-
workflow_remove` `{id, ts}` departures.
|
|
3004
|
+
workflow_remove` `{id, ts}` departures.
|
|
3005
|
+
🔴 Keep-alive is a REAL NAMED FRAME — `event: heartbeat` + `data: {}` every 15 s
|
|
3006
|
+
(`src/http/routes/fleet.ts:223`), NOT an SSE `: hb` comment (the旁注 says why: a per-frame-parsing BFF
|
|
3007
|
+
drops comments, so downstream saw a zero-frame window). Do NOT implement the reader as "skip lines
|
|
3008
|
+
starting with `:`" — swallow the heartbeat BY NAME. (Corrected 2026-08-02; the `: hb` shape belongs to
|
|
3009
|
+
`GET /v1/sessions/{sessionId}/events` alone, and beats at a tunable ~25 s.)
|
|
2985
3010
|
🔴 OWNER-SCOPED by the credential-derived principal (NOT a spoofable header) UNLESS fleet-wide (an operator
|
|
2986
3011
|
/ deployment trace token sees every tenant's rows). The row `scope` is WIRE-STRIPPED after the owner-gate —
|
|
2987
3012
|
it never appears on a row; the `meta.scoped` flag tells the consumer which view this is (true = owner-scoped).
|
|
@@ -3981,6 +4006,17 @@ components:
|
|
|
3981
4006
|
objective:
|
|
3982
4007
|
type: string
|
|
3983
4008
|
description: The task. Put per-request context here (keep `systemPrompt` stable/cacheable).
|
|
4009
|
+
taskId:
|
|
4010
|
+
type: string
|
|
4011
|
+
description: >-
|
|
4012
|
+
[2400] TR-16 (declared 2026-08-02) — CALLER-MINTED uuidv7 task id: the DURABLE second tier of
|
|
4013
|
+
idempotency on POST /v1/runs (`src/http/routes/runs.ts:196-217`). The `Idempotency-Key` header's
|
|
4014
|
+
cache is in-memory and PER-POD, so a dispatch gateway that re-routes a retry to ANOTHER instance
|
|
4015
|
+
after a network error would start a SECOND run; THIS replay reads the durable run store, so it
|
|
4016
|
+
survives the re-route and a restart — it is the prerequisite for gateway failover. A hit replays the
|
|
4017
|
+
original 202 receipt (`{taskId, sessionId, status}`); nothing re-runs, nothing re-bills.
|
|
4018
|
+
Shape-gated: a non-uuidv7 value is 400 `request.id_invalid`. Owner-gated: a taskId owned by another
|
|
4019
|
+
principal answers 409 `conflict.run_exists` (no cross-tenant id oracle). Omit ⇒ the server mints one.
|
|
3984
4020
|
scenario: { $ref: '#/components/schemas/Scenario' }
|
|
3985
4021
|
sessionId:
|
|
3986
4022
|
type: string
|
|
@@ -4201,6 +4237,30 @@ components:
|
|
|
4201
4237
|
description: Per-task sub-agent definitions (roster additions scoped to this task only).
|
|
4202
4238
|
interactiveTools: { type: boolean, description: Mount interactive (prompting) tools. }
|
|
4203
4239
|
retainBackgroundProcesses: { type: boolean, description: Keep background processes alive past the turn. }
|
|
4240
|
+
forwardSubagentEvents:
|
|
4241
|
+
type: boolean
|
|
4242
|
+
description: >
|
|
4243
|
+
🔴 PER-TASK opt-in for forwarding subagent CONTENT onto the parent's event stream (server
|
|
4244
|
+
`src/http/wire-types.ts:157`, consumed at `boot/resolve-spec.ts:557` — read STRICTLY as `=== true`).
|
|
4245
|
+
⚠️ The capability bit of the same name says "this body key is ACCEPTED", NOT "forwarding is on":
|
|
4246
|
+
it is hard-coded true, while forwarding itself is OFF unless this key is sent. Without it the parent
|
|
4247
|
+
stream carries progress-only frames and a subagent-transcript view stays empty forever.
|
|
4248
|
+
(Declared 2026-08-02 — the capability bit had been registered here since 3.x, the request key never was.)
|
|
4249
|
+
retainSubagentSessions:
|
|
4250
|
+
oneOf:
|
|
4251
|
+
- type: boolean
|
|
4252
|
+
- type: object
|
|
4253
|
+
additionalProperties: false
|
|
4254
|
+
properties:
|
|
4255
|
+
ttlMs: { type: integer, description: 'Retention window; server CLAMPS to ≤ 24 h (task-workflow.ts:77-83).' }
|
|
4256
|
+
max: { type: integer, description: 'Retained session count; server CLAMPS to ≤ 64.' }
|
|
4257
|
+
description: >
|
|
4258
|
+
🔴 PER-TASK opt-in to RETAIN finished subagent sessions so they can be resumed (server
|
|
4259
|
+
`src/http/wire-types.ts:169`, normalized at `boot/resolve-spec.ts:564`). This is the OTHER HALF of
|
|
4260
|
+
`POST /v1/runs/{runId}/subagents/{handle}/resume`: the capability bit `subagentResume` can be true and
|
|
4261
|
+
the route mounted, and the call still 409s `resume.retain_off` — retention is per-run and OFF by default.
|
|
4262
|
+
An over-large ask is CLAMPED, not rejected. (Declared 2026-08-02; the error code and the capability bit
|
|
4263
|
+
were both already documented, only the knob that turns retention on was missing.)
|
|
4204
4264
|
excludeTools:
|
|
4205
4265
|
type: array
|
|
4206
4266
|
items: { type: string }
|
|
@@ -4776,6 +4836,20 @@ components:
|
|
|
4776
4836
|
description: >
|
|
4777
4837
|
Approve-with-edit (design/37 last-wins): operator's rewritten tool args, applied AFTER the binding
|
|
4778
4838
|
check. `boundInputHash` STILL binds the ORIGINAL input the human saw — never hash updatedInput.
|
|
4839
|
+
remember:
|
|
4840
|
+
type: string
|
|
4841
|
+
enum: [session]
|
|
4842
|
+
description: >-
|
|
4843
|
+
[2400] HITL-4 (declared 2026-08-02) — the "don't ask again in this session" grant: lands a
|
|
4844
|
+
per-session, per-toolName approval EXEMPTION alongside the decision (server
|
|
4845
|
+
`routes/approvals-assistant.ts` reads it; the SDK has typed it since the facade audit, the spec had
|
|
4846
|
+
not). It is an approval MEMORY, not a policy loosen — a deny / neverAuto always outranks it.
|
|
4847
|
+
Constraints (all server-enforced): only with `decision:"approve"` (else 400
|
|
4848
|
+
`request.field_conflict`); requires the D-1 binding echo in the same body (else 400
|
|
4849
|
+
`remember_requires_binding`); REFUSED on a direct-door worker (400 `remember_not_in_proof` — it is
|
|
4850
|
+
not inside the HMAC payload, so accepting it unsigned would be tamperable); 501 without an exemption
|
|
4851
|
+
store. On the parked-background-agent leg the grant lands on the child's ROOT/HOST session (the whole
|
|
4852
|
+
session tree shares it). The 200 body echoes `rememberApplied` when a store is wired.
|
|
4779
4853
|
|
|
4780
4854
|
ApprovalRow:
|
|
4781
4855
|
type: object
|
|
@@ -5597,6 +5671,42 @@ components:
|
|
|
5597
5671
|
result: { type: string }
|
|
5598
5672
|
seq: { type: integer, minimum: 1 }
|
|
5599
5673
|
source: { type: string, maxLength: 190 }
|
|
5674
|
+
SessionNotifyResult:
|
|
5675
|
+
# 4.3.0(SM-9):把 notify 的两态提成**具名** schema —— 此前只有 path 内联的两个匿名 200/202 形,
|
|
5676
|
+
# SDK 侧的返回型则是裸 `Record<string, unknown>`,`delivery` 这条承重语义(已送达 vs 排队)在类型面
|
|
5677
|
+
# 整个丢失。铸造点 `routes/notify-wake.ts:98`(live)/ `:116`(parked),两臂都是字面量。
|
|
5678
|
+
description: >
|
|
5679
|
+
POST /v1/sessions/{sessionId}/notify 的判别联合。分支 `delivery`:`live` = 会话有活流、通知已送达
|
|
5680
|
+
(HTTP 200);`parked` = 无活流,排队到下次开流才 drain(HTTP 202)。消费方不得把两者都渲染成"已通知"。
|
|
5681
|
+
oneOf:
|
|
5682
|
+
- type: object
|
|
5683
|
+
additionalProperties: false
|
|
5684
|
+
required: [sessionId, delivery]
|
|
5685
|
+
properties:
|
|
5686
|
+
sessionId: { type: string }
|
|
5687
|
+
delivery: { type: string, enum: [live] }
|
|
5688
|
+
- type: object
|
|
5689
|
+
additionalProperties: false
|
|
5690
|
+
required: [sessionId, delivery, note]
|
|
5691
|
+
properties:
|
|
5692
|
+
sessionId: { type: string }
|
|
5693
|
+
delivery: { type: string, enum: [parked] }
|
|
5694
|
+
note: { type: string }
|
|
5695
|
+
SessionWakeResult:
|
|
5696
|
+
# 4.3.0(SM-9):wake 200 形提成具名 schema(形与下面 /wake 路径的 200 逐字同源)。
|
|
5697
|
+
type: object
|
|
5698
|
+
description: >
|
|
5699
|
+
POST /v1/sessions/{sessionId}/wake 的 200 形。⚠️ 200 也可能带 `errorCode`(core 侧 `wake.*` 拒了) ——
|
|
5700
|
+
按机器码分支,别只看 HTTP 状态码。
|
|
5701
|
+
additionalProperties: false
|
|
5702
|
+
required: [sessionId, status]
|
|
5703
|
+
properties:
|
|
5704
|
+
sessionId: { type: string }
|
|
5705
|
+
status: { type: string, description: 'The run''s resulting status (core TaskStatus verbatim).' }
|
|
5706
|
+
taskId: { type: string, description: 'The active run id; OMITTED when no active row.' }
|
|
5707
|
+
errorCode: { type: string, description: 'Failure code when the resumed leg failed / was refused.' }
|
|
5708
|
+
errorMessage: { type: string, description: 'Human-readable failure detail (server-side secret-redacted).' }
|
|
5709
|
+
retriable: { type: boolean, description: 'true = the park is STILL pending (re-parked); refetch and retry.' }
|
|
5600
5710
|
WorkflowJournalRow:
|
|
5601
5711
|
# 🔴 census 批2 四段:CLOSED against server's real projected/truncated row shapes — a row is EITHER the
|
|
5602
5712
|
# projected result OR an honest truncated stub(超 64KiB 的行从不进程内存,投影为 truncated stub)。
|
|
@@ -5646,9 +5756,18 @@ components:
|
|
|
5646
5756
|
WorkflowStreamEvent:
|
|
5647
5757
|
type: object
|
|
5648
5758
|
description: >
|
|
5649
|
-
One frame of GET /v1/workflows/:id/stream (streamWorkflowRun). FIRST frame is `event:meta`
|
|
5650
|
-
`{version, runId}
|
|
5651
|
-
|
|
5759
|
+
One frame of GET /v1/workflows/:id/stream (streamWorkflowRun). FIRST frame is `event:meta` with
|
|
5760
|
+
`data: {type:"meta", version, runId}` (`src/http/routes/workflows.ts:487` — the `type` is double-emitted
|
|
5761
|
+
on purpose: a proxy that forwards only `data:` lines would otherwise leave a `data.type`-dispatching
|
|
5762
|
+
consumer unable to recognise the opener). Subsequent frames carry a core WorkflowEvent verbatim (its
|
|
5763
|
+
`type` is the SSE event name). NOT resumable (replica-local, in-process; no id/Last-Event-ID).
|
|
5764
|
+
`data` is permissive (core-internal, evolves).
|
|
5765
|
+
🔴 There IS exactly one TERMINAL frame and it means FAILURE: `event: error` with
|
|
5766
|
+
`data: {type:"error", errorCode:"workflow.stream_error", message:"workflow stream error"}`
|
|
5767
|
+
(`routes/workflows.ts:517`). Branch on `errorCode` — NEVER anchor on `message`; the errorCode was added
|
|
5768
|
+
precisely because consumers were otherwise forced to anchor prose or to conflate "the stream broke" with
|
|
5769
|
+
"the stream ended normally", i.e. to report a FAILED workflow as finished. (Declared 2026-08-02.)
|
|
5770
|
+
Keep-alive is a REAL NAMED FRAME `event: heartbeat` / `data: {}` @15 s (`:496`), not an SSE comment.
|
|
5652
5771
|
NOTE: on the wire this is SSE framing (event name + JSON data), not a JSON body — schema describes one
|
|
5653
5772
|
decoded frame.
|
|
5654
5773
|
required: [event, data]
|
|
@@ -5752,12 +5871,19 @@ components:
|
|
|
5752
5871
|
required: [id, name, status]
|
|
5753
5872
|
additionalProperties: true
|
|
5754
5873
|
properties:
|
|
5874
|
+
# 🔴 FW-6(2026-08-02):这里此前有一个 `sourceLane` —— **幻影键,已删**。`sourceLane` 只在
|
|
5875
|
+
# `FleetTaskRow`(`src/fleet/fleet-bus.ts:146`)上,`FleetWorkflowRow`(`:150-170`)全文没有它,
|
|
5876
|
+
# `publishWorkflow`(`:338-342`)也从不写它;SDK 侧同样没有(SDK 是对的那一边)。
|
|
5877
|
+
# 按它 codegen 的第三方会得到一个永远 undefined 的 `workflowRow.sourceLane`,并照 FleetTaskRow 那条
|
|
5878
|
+
# 「run-leg composite rows only」的描述写出一个**永不触发**的 workflow 行去重分支。
|
|
5755
5879
|
id: { type: string }
|
|
5756
|
-
sourceLane: { type: string, description: 'run-leg composite rows only (server >=3.6.0, [2070]-1 yield half); BCE-lane rows omit it.' }
|
|
5757
5880
|
name: { type: string }
|
|
5758
5881
|
description: { type: string }
|
|
5759
5882
|
status: { type: string, description: 'Neutral workflow run status (running|completed|failed; open).' }
|
|
5760
5883
|
doneCount: { type: integer }
|
|
5884
|
+
# 🔴 FW-6(2026-08-02):补上一个 server 真发、SDK 真声明、只有 spec 漏了的键。
|
|
5885
|
+
# `src/fleet/fleet-bus.ts:167` 声明,`src/orchestration/workflow-notify-journal.ts:511` 真发。
|
|
5886
|
+
startedCount: { type: integer, description: 'Agents actually STARTED (vs `totalCount` = planned, queued included). CC 2.1.220 的 `⚠ Large workflow` 规模告警用它当分母 —— 漏了它那条告警根本渲染不出来。' }
|
|
5761
5887
|
totalCount: { type: integer }
|
|
5762
5888
|
failedCount: { type: integer }
|
|
5763
5889
|
elapsedMs: { type: integer }
|
|
@@ -5768,7 +5894,9 @@ components:
|
|
|
5768
5894
|
wire this is SSE framing (the `type` here = the SSE `event` name; the object = the decoded `data:` JSON).
|
|
5769
5895
|
Emit order: `meta` (FIRST) → `snapshot` (connect-time full set) → per-row `task`/`workflow` upserts +
|
|
5770
5896
|
`task_remove`/`workflow_remove` departures. The SDK PRODUCES these frames; the consumer maintains the
|
|
5771
|
-
active-set state (update-in-place by `row.id`, remove by `id`).
|
|
5897
|
+
active-set state (update-in-place by `row.id`, remove by `id`).
|
|
5898
|
+
🔴 The keep-alive IS a frame: `event: heartbeat` / `data: {}` @15 s (corrected 2026-08-02 — this line
|
|
5899
|
+
previously said "`: hb` comments are not frames", which described a superseded shape). Swallow it by NAME.
|
|
5772
5900
|
OPEN set — branch on `type`, ignore an unknown future frame.
|
|
5773
5901
|
oneOf:
|
|
5774
5902
|
- $ref: '#/components/schemas/FleetFrame_meta'
|
|
@@ -5792,12 +5920,22 @@ components:
|
|
|
5792
5920
|
hook_notice: '#/components/schemas/FleetFrame_hook_notice'
|
|
5793
5921
|
FleetFrame_meta:
|
|
5794
5922
|
type: object
|
|
5795
|
-
|
|
5796
|
-
|
|
5923
|
+
# 🔴 FW-10(2026-08-02):此前只声明三键,而铸造点 `src/http/routes/fleet.ts:79` **无条件**发五键 ——
|
|
5924
|
+
# `sessionScoped` / `bgNotifyFailClosed` 不在任何条件分支里。这两个键正是「server 契约方复审 F1
|
|
5925
|
+
# (行为错·最高)」的当事键:它们曾被一次白名单重构静默剥掉,导致 cli 的让位臂全程死代码。
|
|
5926
|
+
# SDK 侧已上锁(`test/fleet.test.ts` 有专门的透传回归钉),spec 侧一直空白 —— 按 spec 生成的客户端
|
|
5927
|
+
# 拿不到 `bgNotifyFailClosed`,只能保留帧级 own/foreign 判别(或更糟:以为拿不到就是老 server),
|
|
5928
|
+
# 代际让位机制对这类消费方永远不生效。
|
|
5929
|
+
description: >
|
|
5930
|
+
FIRST frame — `{type, version, scoped, sessionScoped, bgNotifyFailClosed}` (all five UNCONDITIONAL on
|
|
5931
|
+
server >= 1.247). `scoped:true` ⇒ owner-scoped view; `false` ⇒ fleet-wide (operator/trace token).
|
|
5932
|
+
required: [type, version, scoped, sessionScoped, bgNotifyFailClosed]
|
|
5797
5933
|
properties:
|
|
5798
5934
|
type: { const: meta }
|
|
5799
5935
|
version: { type: integer }
|
|
5800
5936
|
scoped: { type: boolean }
|
|
5937
|
+
sessionScoped: { type: boolean, description: 'true ⇒ this connection carried `?session=` (rows and notifications are filtered by the host session).' }
|
|
5938
|
+
bgNotifyFailClosed: { type: boolean, description: 'GENERATION marker — true ⇒ this server''s bg_notification injection path fails CLOSED for scoped subscribers, so a new-generation shell may drop its frame-level own/foreign checks entirely. ABSENT (older server) ⇒ keep them.' }
|
|
5801
5939
|
FleetFrame_snapshot:
|
|
5802
5940
|
type: object
|
|
5803
5941
|
description: 'Connect-time FULL state (the visible, scope-stripped rows). Seed the active-set Map from this.'
|
|
@@ -6779,6 +6917,13 @@ components:
|
|
|
6779
6917
|
- $ref: '#/components/schemas/Event_message_committed'
|
|
6780
6918
|
# [2373]A-2(2026-08-03,server 5.0.0):compaction_outcome 三腿同源批的 spec 半场(SDK 臂 20867e1 同批)。
|
|
6781
6919
|
- $ref: '#/components/schemas/Event_compaction_outcome'
|
|
6920
|
+
# [2400] ch2(SDK 4.2.0):CB-1 流控帽帧 + TR-7 durable 五臂 —— 两侧同缺,见各 schema 处的注。
|
|
6921
|
+
- $ref: '#/components/schemas/Event_error'
|
|
6922
|
+
- $ref: '#/components/schemas/Event_question'
|
|
6923
|
+
- $ref: '#/components/schemas/Event_question_complete'
|
|
6924
|
+
- $ref: '#/components/schemas/Event_elicitation'
|
|
6925
|
+
- $ref: '#/components/schemas/Event_elicitation_complete'
|
|
6926
|
+
- $ref: '#/components/schemas/Event_workflow_complete'
|
|
6782
6927
|
discriminator:
|
|
6783
6928
|
propertyName: type
|
|
6784
6929
|
mapping:
|
|
@@ -6809,6 +6954,12 @@ components:
|
|
|
6809
6954
|
needs_review: '#/components/schemas/Event_needs_review'
|
|
6810
6955
|
message_committed: '#/components/schemas/Event_message_committed'
|
|
6811
6956
|
compaction_outcome: '#/components/schemas/Event_compaction_outcome'
|
|
6957
|
+
error: '#/components/schemas/Event_error'
|
|
6958
|
+
question: '#/components/schemas/Event_question'
|
|
6959
|
+
question_complete: '#/components/schemas/Event_question_complete'
|
|
6960
|
+
elicitation: '#/components/schemas/Event_elicitation'
|
|
6961
|
+
elicitation_complete: '#/components/schemas/Event_elicitation_complete'
|
|
6962
|
+
workflow_complete: '#/components/schemas/Event_workflow_complete'
|
|
6812
6963
|
|
|
6813
6964
|
# design/99 §E2 (SHIPPED, core TaskEventIdentity) — additive per-event identity on every CONTENT event (NOT on
|
|
6814
6965
|
# the lifecycle arms turn_end/compacted/suspended/done/failed). eventId = uuidv7 dedup/resume handle (the durable
|
|
@@ -7728,6 +7879,102 @@ components:
|
|
|
7728
7879
|
sourceTaskId: { type: string }
|
|
7729
7880
|
bgAgentId: { type: string }
|
|
7730
7881
|
|
|
7882
|
+
# ══════════════════════════════════════════════════════════════════════════════════════════════
|
|
7883
|
+
# [2400] 说明书审计 ch2(SDK 4.2.0)补的**六个未登记臂**:一个流控帧(CB-1/TR-6)+ 五个 HITL/workflow
|
|
7884
|
+
# 帧(TR-7)。同一个盲区:`spec-union-arm-gate` 比的是 spec ↔ SDK 两侧的臂集,这六个两侧同缺 ⇒ 那道门
|
|
7885
|
+
# 对它们结构性失明;抓到它们靠的是拿 server 的 `res.write("event: …")` / `append("…")` 铸造点第三方对账。
|
|
7886
|
+
# ══════════════════════════════════════════════════════════════════════════════════════════════
|
|
7887
|
+
Event_error:
|
|
7888
|
+
type: object
|
|
7889
|
+
description: >
|
|
7890
|
+
STREAM-CONTROL frame, NOT a run failure (server src/http/sse-log.ts:86; the trace leg emits the same
|
|
7891
|
+
shape at routes/trace-usage.ts:294). The server writes it as a NAMED frame (`event: error`) whose payload
|
|
7892
|
+
echoes `type`, so both an `event:`-dispatching client and a payload-dispatching one see it.
|
|
7893
|
+
🔴 Its arrival means the RUN IS STILL ALIVE — the 15-minute stream cap fired. The correct handling is to
|
|
7894
|
+
RECONNECT with `Last-Event-ID` and keep reading (the durable leg stamps `id:` on every frame); rendering
|
|
7895
|
+
it as a terminal would declare a live task dead. `done` / `failed` are the terminal arms; this one is not.
|
|
7896
|
+
Known `errorCode`: `STREAM_MAX_DURATION` (open set — branch on the code, degrade unknown codes to the
|
|
7897
|
+
generic "reconnectable stream-control signal").
|
|
7898
|
+
additionalProperties: false
|
|
7899
|
+
required: [type, errorCode]
|
|
7900
|
+
properties:
|
|
7901
|
+
type: { const: error }
|
|
7902
|
+
errorCode: { type: string, description: 'STREAM_MAX_DURATION (open set).' }
|
|
7903
|
+
message: { type: string }
|
|
7904
|
+
Event_question:
|
|
7905
|
+
type: object
|
|
7906
|
+
description: >
|
|
7907
|
+
AskUserQuestion OPEN frame (server src/question.ts:38 `QuestionFrame`). The live leg dispatches it by SSE
|
|
7908
|
+
event name (routes/tasks.ts:677, the same out-of-band channel as `elicitation`/`tool_approval`); the
|
|
7909
|
+
DURABLE leg persists it via `append(type, rest)` (src/runs.ts:498), so the same frame also replays on
|
|
7910
|
+
GET /v1/runs/:id/events — that half is what this schema registers.
|
|
7911
|
+
🔴 UNTRUSTED-for-display: `questions` is secret-redacted, render only, NEVER re-feed to a model.
|
|
7912
|
+
`questions` absent ⇒ the payload exceeded the 16 KiB cap and was dropped (the ask headless-defaults).
|
|
7913
|
+
additionalProperties: false
|
|
7914
|
+
required: [type, questionId]
|
|
7915
|
+
properties:
|
|
7916
|
+
type: { const: question }
|
|
7917
|
+
questionId: { type: string }
|
|
7918
|
+
questions:
|
|
7919
|
+
type: array
|
|
7920
|
+
items: { $ref: '#/components/schemas/AskQuestion' }
|
|
7921
|
+
Event_question_complete:
|
|
7922
|
+
type: object
|
|
7923
|
+
description: >
|
|
7924
|
+
AskUserQuestion CLOSE frame (dialog-dismiss signal). `answered` = a human responded; `unanswered` =
|
|
7925
|
+
ttl / abort / throttle released it and the model got the headless default. Cosmetic — it does not change
|
|
7926
|
+
the run's status.
|
|
7927
|
+
additionalProperties: false
|
|
7928
|
+
required: [type, questionId]
|
|
7929
|
+
properties:
|
|
7930
|
+
type: { const: question_complete }
|
|
7931
|
+
questionId: { type: string }
|
|
7932
|
+
outcome: { type: string, enum: [answered, unanswered] }
|
|
7933
|
+
Event_elicitation:
|
|
7934
|
+
type: object
|
|
7935
|
+
description: >
|
|
7936
|
+
Inbound-MCP elicitation OPEN frame (server src/elicitation.ts:42 `ElicitationFrame`). Same two legs as
|
|
7937
|
+
`question`: live dispatches by event name, the durable leg persists + replays it.
|
|
7938
|
+
🔴 UNTRUSTED: `message` is fenced + secret-redacted; `requestedSchema` is an OPAQUE passthrough (never
|
|
7939
|
+
interpreted/validated) and must still be fenced on display. v1 is always `mode: "form"` (url-mode is
|
|
7940
|
+
rejected upstream as a phishing surface).
|
|
7941
|
+
additionalProperties: false
|
|
7942
|
+
required: [type, elicitationId, mcpServerName]
|
|
7943
|
+
properties:
|
|
7944
|
+
type: { const: elicitation }
|
|
7945
|
+
elicitationId: { type: string }
|
|
7946
|
+
mcpServerName: { type: string }
|
|
7947
|
+
message: { type: string }
|
|
7948
|
+
requestedSchema: {}
|
|
7949
|
+
mode: { type: string, enum: [form] }
|
|
7950
|
+
Event_elicitation_complete:
|
|
7951
|
+
type: object
|
|
7952
|
+
description: 'Inbound-MCP elicitation CLOSE frame; `action` is how it settled (the dialog-dismiss reason).'
|
|
7953
|
+
additionalProperties: false
|
|
7954
|
+
required: [type, elicitationId, mcpServerName]
|
|
7955
|
+
properties:
|
|
7956
|
+
type: { const: elicitation_complete }
|
|
7957
|
+
elicitationId: { type: string }
|
|
7958
|
+
mcpServerName: { type: string }
|
|
7959
|
+
action: { type: string, enum: [accept, decline, cancel] }
|
|
7960
|
+
Event_workflow_complete:
|
|
7961
|
+
type: object
|
|
7962
|
+
description: >
|
|
7963
|
+
Out-of-band delivery of an async workflow's completion (server
|
|
7964
|
+
src/orchestration/workflow-completion-inbox.ts:522). Delivery is STREAM-OPEN driven: the session's inbox
|
|
7965
|
+
is drained on its NEXT leg — the sync leg writes a live frame, the bg/resume legs `append` it as a durable
|
|
7966
|
+
event the tailing client replays.
|
|
7967
|
+
🔴 AT-LEAST-ONCE (two-phase: the entry is acked only after a successful emit, and two legs racing the same
|
|
7968
|
+
session may double-emit) — consumers MUST dedup on `runId`. `summary` is redacted free text
|
|
7969
|
+
(UNTRUSTED-for-display).
|
|
7970
|
+
additionalProperties: false
|
|
7971
|
+
required: [type, runId, status, summary]
|
|
7972
|
+
properties:
|
|
7973
|
+
type: { const: workflow_complete }
|
|
7974
|
+
runId: { type: string }
|
|
7975
|
+
status: { type: string }
|
|
7976
|
+
summary: { type: string }
|
|
7977
|
+
|
|
7731
7978
|
# ── resources/*.ts schema backfill, batch 2 (2026-07-28) — the 28-item WIRE_PENDING ratchet zeroed.
|
|
7732
7979
|
# Each schema below is cross-checked against the server source (file:line cited in its description
|
|
7733
7980
|
# or in the SDK resource JSDoc it mirrors). Wire objects are OPEN sets (additionalProperties: true).
|
|
@@ -8048,6 +8295,40 @@ components:
|
|
|
8048
8295
|
taskId: { type: string, description: 'Issuing task, when recorded. Additive / tolerate-absent.' }
|
|
8049
8296
|
sessionId: { type: string, description: 'Issuing session, when recorded. Additive / tolerate-absent.' }
|
|
8050
8297
|
|
|
8298
|
+
SteerPriority:
|
|
8299
|
+
type: string
|
|
8300
|
+
enum: [now, next, later]
|
|
8301
|
+
description: >-
|
|
8302
|
+
[2400] TR-4 — per-message queue priority on POST /v1/runs/{taskId}/steer. ACCEPTED + ENUM-VALIDATED
|
|
8303
|
+
FAIL-LOUD (`routes/runs.ts:603`; anything else is 400 `request.field_invalid`) and echoed back on the
|
|
8304
|
+
receipt, but ADVISORY today: core's steer is a single-slot last-writer-wins with no per-message priority
|
|
8305
|
+
or addressable drop, so a faithful priority queue (and DELETE /v1/runs/{taskId}/queue/{messageId}) waits
|
|
8306
|
+
on a core seam.
|
|
8307
|
+
|
|
8308
|
+
SteerReceipt:
|
|
8309
|
+
type: object
|
|
8310
|
+
description: >
|
|
8311
|
+
[2400] TR-4 — the POST /v1/runs/{taskId}/steer receipt, DISCRIMINATED on `delivery` (three server mint
|
|
8312
|
+
points meaning three different things; branch on this, NOT on the status code):
|
|
8313
|
+
`applied` (200, `routes/runs.ts:648`) — injected into the run LIVE on this replica, drains at the next
|
|
8314
|
+
turn boundary (`status:"running"`);
|
|
8315
|
+
`queued` (202, `:641`) — the run is durably SUSPENDED, so the steer was PARKED on its pending checkpoint
|
|
8316
|
+
and is injected on resume (`status:"suspended"`);
|
|
8317
|
+
`parked_for_wake` (202, `:734`) — the run already ENDED; the server minted a `task_done` checkpoint and
|
|
8318
|
+
parked the message on it, delivered ONLY by POST /v1/sessions/{sessionId}/wake — nothing happens until
|
|
8319
|
+
the session is woken.
|
|
8320
|
+
`messageId` is server-minted and stable across all three (dedup / correlation handle).
|
|
8321
|
+
required: [taskId, status, delivery, messageId]
|
|
8322
|
+
# 封闭:三个铸造点是逐字面量拼出来的对象(routes/runs.ts:641/648/734),不是引擎透传形。
|
|
8323
|
+
additionalProperties: false
|
|
8324
|
+
properties:
|
|
8325
|
+
taskId: { type: string }
|
|
8326
|
+
status: { type: string, description: 'The run status the server saw at delivery time (running | suspended | a terminal status).' }
|
|
8327
|
+
delivery: { type: string, enum: [applied, queued, parked_for_wake] }
|
|
8328
|
+
messageId: { type: string, description: 'Server-minted, stable across all three legs.' }
|
|
8329
|
+
priority: { $ref: '#/components/schemas/SteerPriority' }
|
|
8330
|
+
note: { type: string, description: 'Human-readable note on the two parked legs; absent on `applied`.' }
|
|
8331
|
+
|
|
8051
8332
|
SubagentSteerReceipt:
|
|
8052
8333
|
type: object
|
|
8053
8334
|
description: >
|
|
@@ -8403,6 +8684,43 @@ components:
|
|
|
8403
8684
|
delivery: { type: string, const: applied, description: 'Literal "applied" on today''s server.' }
|
|
8404
8685
|
marker: { type: string, description: 'Engine-minted delivery marker.' }
|
|
8405
8686
|
|
|
8687
|
+
WorkspaceSnapshotPage:
|
|
8688
|
+
# 4.3.0(CAPS-OPS-8):把 GET …/workspace 的 200 信封提成具名 schema。SDK 侧此前是 `list()` 返回位上的
|
|
8689
|
+
# **内联闭合字面量**,两道 spec 门(field-drift 只扫 types.ts / resource-schema 只扫 resources 的 exported
|
|
8690
|
+
# type)对方法返回位的内联形都是盲的 —— 于是它漏了这里一直标为 required 的 `sessionId`,CI 全绿。
|
|
8691
|
+
type: object
|
|
8692
|
+
description: >
|
|
8693
|
+
GET /v1/sessions/{sessionId}/workspace 的 200 信封(server src/http/routes/sessions.ts:624-629)。
|
|
8694
|
+
⚠️ `total` = **本页行数**(`snapshots.length`),不是快照总数,且这条腿没有任何分页游标 —— 与同族
|
|
8695
|
+
`WorkspaceTreePage.total`(真·全量)**同名反义**。`latest` 与展示行同源(防 ghost key)。
|
|
8696
|
+
additionalProperties: false
|
|
8697
|
+
required: [sessionId, snapshots, total]
|
|
8698
|
+
properties:
|
|
8699
|
+
sessionId: { type: string }
|
|
8700
|
+
snapshots:
|
|
8701
|
+
type: array
|
|
8702
|
+
items: { $ref: '#/components/schemas/WorkspaceSnapshotRow' }
|
|
8703
|
+
latest: { type: string, description: 'Newest snapshot key; absent when the session has none.' }
|
|
8704
|
+
total: { type: integer, description: 'ROWS ON THIS PAGE — not the snapshot count.' }
|
|
8705
|
+
|
|
8706
|
+
WorkspaceTreePage:
|
|
8707
|
+
# 4.3.0(CAPS-OPS-8):同上,tree 腿的 200 信封。
|
|
8708
|
+
type: object
|
|
8709
|
+
description: >
|
|
8710
|
+
GET /v1/sessions/{sessionId}/workspace/{key}/tree 的 200 信封(server src/http/routes/sessions.ts:651-657)。
|
|
8711
|
+
`total` 在这条腿上是**全量**(`all.length`)—— 与 `WorkspaceSnapshotPage.total` 语义相反。
|
|
8712
|
+
`key` 回的是解析后的真实键(请求可传 `latest` 别名)。
|
|
8713
|
+
additionalProperties: false
|
|
8714
|
+
required: [sessionId, key, entries, total]
|
|
8715
|
+
properties:
|
|
8716
|
+
sessionId: { type: string }
|
|
8717
|
+
key: { type: string, description: 'The RESOLVED snapshot key (a `latest` alias in the request comes back resolved).' }
|
|
8718
|
+
entries:
|
|
8719
|
+
type: array
|
|
8720
|
+
items: { $ref: '#/components/schemas/WorkspaceTreeEntry' }
|
|
8721
|
+
total: { type: integer, description: 'FULL entry count (not the page size).' }
|
|
8722
|
+
nextOffset: { type: integer, description: 'Present ⇒ more pages; send it back as ?offset=.' }
|
|
8723
|
+
|
|
8406
8724
|
WorkspaceSnapshotRow:
|
|
8407
8725
|
type: object
|
|
8408
8726
|
description: >
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/sdk",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.3.0",
|
|
4
4
|
"description": "Typed, zero-runtime-dependency SDK for the Sema agent fleet usage plane. The shared substrate for all doors (CC/Codex MCP façade + web). Server-side only — tokens never enter the browser.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BUSL-1.1",
|
|
@@ -48,6 +48,6 @@
|
|
|
48
48
|
"prepublishOnly": "rm -f tsconfig.tsbuildinfo && npm run build && npm run typecheck --workspaces=false --prefix ../.. && npm test --workspaces=false --prefix ../.."
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@sema-agent/registry-core": "^0.
|
|
51
|
+
"@sema-agent/registry-core": "^0.13.0"
|
|
52
52
|
}
|
|
53
53
|
}
|