@sema-agent/sdk 4.2.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 +12 -0
- 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/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/index.d.ts +10 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- 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/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 +3 -2
- package/dist/resources/fleet.d.ts.map +1 -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/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 +72 -12
- package/dist/resources/sessions.d.ts.map +1 -1
- package/dist/resources/sessions.js +29 -6
- package/dist/resources/sessions.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/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 +17 -3
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +18 -1
- package/dist/transport.js.map +1 -1
- package/dist/types.d.ts +86 -9
- package/dist/types.d.ts.map +1 -1
- package/openapi.yaml +172 -54
- package/package.json +2 -2
- package/registry-openapi.yaml +34 -3
package/openapi.yaml
CHANGED
|
@@ -1286,9 +1286,10 @@ paths:
|
|
|
1286
1286
|
description: Delivered onto the live stream.
|
|
1287
1287
|
content:
|
|
1288
1288
|
application/json:
|
|
1289
|
+
# 封闭(census 批2 第三段,2026-07-30):live 臂铸造点 `routes/notify-wake.ts:98` 是两键字面量。
|
|
1290
|
+
# 4.3.0:形提成具名 `SessionNotifyResult` 的 live 臂(SDK 同批给了判别联合返回型)。
|
|
1289
1291
|
schema:
|
|
1290
1292
|
type: object
|
|
1291
|
-
# 封闭(census 批2 第三段,2026-07-30):live 臂铸造点 `routes/notify-wake.ts:86` 是两键字面量。
|
|
1292
1293
|
additionalProperties: false
|
|
1293
1294
|
required: [sessionId, delivery]
|
|
1294
1295
|
properties:
|
|
@@ -1298,9 +1299,9 @@ paths:
|
|
|
1298
1299
|
description: No live stream — parked in the session inbox, drained on the next stream open.
|
|
1299
1300
|
content:
|
|
1300
1301
|
application/json:
|
|
1302
|
+
# 封闭 + note 补 required:parked 臂铸造点 `routes/notify-wake.ts:116` 是三键字面量,note 无条件。
|
|
1301
1303
|
schema:
|
|
1302
1304
|
type: object
|
|
1303
|
-
# 封闭 + note 补 required:parked 臂铸造点 `routes/notify-wake.ts:104` 是三键字面量,note 无条件。
|
|
1304
1305
|
additionalProperties: false
|
|
1305
1306
|
required: [sessionId, delivery, note]
|
|
1306
1307
|
properties:
|
|
@@ -1395,26 +1396,11 @@ paths:
|
|
|
1395
1396
|
description: The snapshot listing.
|
|
1396
1397
|
content:
|
|
1397
1398
|
application/json:
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
required: [sessionId, snapshots, total]
|
|
1404
|
-
properties:
|
|
1405
|
-
sessionId: { type: string }
|
|
1406
|
-
snapshots:
|
|
1407
|
-
type: array
|
|
1408
|
-
items:
|
|
1409
|
-
type: object
|
|
1410
|
-
additionalProperties: false
|
|
1411
|
-
required: [key, files]
|
|
1412
|
-
properties:
|
|
1413
|
-
key: { type: string }
|
|
1414
|
-
files: { type: integer }
|
|
1415
|
-
bytes: { type: integer }
|
|
1416
|
-
latest: { type: string }
|
|
1417
|
-
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' }
|
|
1418
1404
|
'400': { $ref: '#/components/responses/BadRequest' }
|
|
1419
1405
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
1420
1406
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
@@ -1455,27 +1441,10 @@ paths:
|
|
|
1455
1441
|
description: One page of the tree.
|
|
1456
1442
|
content:
|
|
1457
1443
|
application/json:
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
additionalProperties: false
|
|
1463
|
-
required: [sessionId, key, entries, total]
|
|
1464
|
-
properties:
|
|
1465
|
-
sessionId: { type: string }
|
|
1466
|
-
key: { type: string }
|
|
1467
|
-
entries:
|
|
1468
|
-
type: array
|
|
1469
|
-
items:
|
|
1470
|
-
type: object
|
|
1471
|
-
additionalProperties: false
|
|
1472
|
-
required: [path, hash]
|
|
1473
|
-
properties:
|
|
1474
|
-
path: { type: string }
|
|
1475
|
-
hash: { type: string }
|
|
1476
|
-
size: { type: integer }
|
|
1477
|
-
total: { type: integer }
|
|
1478
|
-
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' }
|
|
1479
1448
|
'400': { $ref: '#/components/responses/BadRequest' }
|
|
1480
1449
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
1481
1450
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
@@ -1696,7 +1665,11 @@ paths:
|
|
|
1696
1665
|
2c session-sync PULL — the THIN snapshot: entry IDS (oldest-first, NOT payloads — those stream via
|
|
1697
1666
|
`/sync/entries`) + per-snapshot relPath→blobHash + policy + anchors + leaf. The local peer feeds `entryIds`
|
|
1698
1667
|
to the §7 classifier to decide fast-forward/fork BEFORE pulling the entry stream + only the blob hashes it
|
|
1699
|
-
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.
|
|
1700
1673
|
responses:
|
|
1701
1674
|
'200':
|
|
1702
1675
|
description: The manifest, wrapped as `{ manifest }`.
|
|
@@ -1739,7 +1712,7 @@ paths:
|
|
|
1739
1712
|
at 200 BEFORE the first line, so a mid-stream failure ends the body WITHOUT the trailer — the trailer's
|
|
1740
1713
|
ABSENCE (or a count mismatch) is the SOLE truncation signal (NO 5xx mid-stream). The SDK reader throws
|
|
1741
1714
|
`SyncTruncatedError` on a missing trailer / count mismatch. Owner-scoped (404); 400 on a bad afterSeq /
|
|
1742
|
-
non-
|
|
1715
|
+
non-uuid-SHAPED id (ANY uuid version passes — see the manifest leg); 501 without a durable entry-streaming store.
|
|
1743
1716
|
responses:
|
|
1744
1717
|
'200':
|
|
1745
1718
|
description: The NDJSON entry stream (begin / entry× N / end-trailer).
|
|
@@ -1844,7 +1817,8 @@ paths:
|
|
|
1844
1817
|
description: >
|
|
1845
1818
|
2c session-sync PLAN — classify the §7 relation between the LOCAL peer's `entryIds` (oldest-first, the SOURCE)
|
|
1846
1819
|
and the cloud's current log (the DST), WITHOUT writing. Returns the `SyncRelation` (`fresh` for a fresh cloud
|
|
1847
|
-
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 —
|
|
1848
1822
|
a fork/stale is REPORTED in the relation, not raised.
|
|
1849
1823
|
requestBody:
|
|
1850
1824
|
required: true
|
|
@@ -1901,6 +1875,20 @@ paths:
|
|
|
1901
1875
|
policy: { type: array, items: { $ref: '#/components/schemas/SessionRulesRecord' } }
|
|
1902
1876
|
anchors: { type: array, items: { $ref: '#/components/schemas/SyncAnchor' } }
|
|
1903
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).
|
|
1904
1892
|
responses:
|
|
1905
1893
|
'200':
|
|
1906
1894
|
description: Staged (or `identical` no-op).
|
|
@@ -3013,7 +3001,12 @@ paths:
|
|
|
3013
3001
|
per-row delta for every transition. Frame order: `event: meta` `{version, scoped}` → `event: snapshot`
|
|
3014
3002
|
`{tasks, workflows, ts}` → then `event: task`/`event: workflow` UPSERTS (each `data: {row, ts}` is the
|
|
3015
3003
|
POST-MERGE FULL row — replace by `row.id`, NOT a sparse patch) + `event: task_remove`/`event:
|
|
3016
|
-
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.)
|
|
3017
3010
|
🔴 OWNER-SCOPED by the credential-derived principal (NOT a spoofable header) UNLESS fleet-wide (an operator
|
|
3018
3011
|
/ deployment trace token sees every tenant's rows). The row `scope` is WIRE-STRIPPED after the owner-gate —
|
|
3019
3012
|
it never appears on a row; the `meta.scoped` flag tells the consumer which view this is (true = owner-scoped).
|
|
@@ -4244,6 +4237,30 @@ components:
|
|
|
4244
4237
|
description: Per-task sub-agent definitions (roster additions scoped to this task only).
|
|
4245
4238
|
interactiveTools: { type: boolean, description: Mount interactive (prompting) tools. }
|
|
4246
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.)
|
|
4247
4264
|
excludeTools:
|
|
4248
4265
|
type: array
|
|
4249
4266
|
items: { type: string }
|
|
@@ -5654,6 +5671,42 @@ components:
|
|
|
5654
5671
|
result: { type: string }
|
|
5655
5672
|
seq: { type: integer, minimum: 1 }
|
|
5656
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.' }
|
|
5657
5710
|
WorkflowJournalRow:
|
|
5658
5711
|
# 🔴 census 批2 四段:CLOSED against server's real projected/truncated row shapes — a row is EITHER the
|
|
5659
5712
|
# projected result OR an honest truncated stub(超 64KiB 的行从不进程内存,投影为 truncated stub)。
|
|
@@ -5703,9 +5756,18 @@ components:
|
|
|
5703
5756
|
WorkflowStreamEvent:
|
|
5704
5757
|
type: object
|
|
5705
5758
|
description: >
|
|
5706
|
-
One frame of GET /v1/workflows/:id/stream (streamWorkflowRun). FIRST frame is `event:meta`
|
|
5707
|
-
`{version, runId}
|
|
5708
|
-
|
|
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.
|
|
5709
5771
|
NOTE: on the wire this is SSE framing (event name + JSON data), not a JSON body — schema describes one
|
|
5710
5772
|
decoded frame.
|
|
5711
5773
|
required: [event, data]
|
|
@@ -5809,12 +5871,19 @@ components:
|
|
|
5809
5871
|
required: [id, name, status]
|
|
5810
5872
|
additionalProperties: true
|
|
5811
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 行去重分支。
|
|
5812
5879
|
id: { type: string }
|
|
5813
|
-
sourceLane: { type: string, description: 'run-leg composite rows only (server >=3.6.0, [2070]-1 yield half); BCE-lane rows omit it.' }
|
|
5814
5880
|
name: { type: string }
|
|
5815
5881
|
description: { type: string }
|
|
5816
5882
|
status: { type: string, description: 'Neutral workflow run status (running|completed|failed; open).' }
|
|
5817
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` 规模告警用它当分母 —— 漏了它那条告警根本渲染不出来。' }
|
|
5818
5887
|
totalCount: { type: integer }
|
|
5819
5888
|
failedCount: { type: integer }
|
|
5820
5889
|
elapsedMs: { type: integer }
|
|
@@ -5825,7 +5894,9 @@ components:
|
|
|
5825
5894
|
wire this is SSE framing (the `type` here = the SSE `event` name; the object = the decoded `data:` JSON).
|
|
5826
5895
|
Emit order: `meta` (FIRST) → `snapshot` (connect-time full set) → per-row `task`/`workflow` upserts +
|
|
5827
5896
|
`task_remove`/`workflow_remove` departures. The SDK PRODUCES these frames; the consumer maintains the
|
|
5828
|
-
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.
|
|
5829
5900
|
OPEN set — branch on `type`, ignore an unknown future frame.
|
|
5830
5901
|
oneOf:
|
|
5831
5902
|
- $ref: '#/components/schemas/FleetFrame_meta'
|
|
@@ -5849,12 +5920,22 @@ components:
|
|
|
5849
5920
|
hook_notice: '#/components/schemas/FleetFrame_hook_notice'
|
|
5850
5921
|
FleetFrame_meta:
|
|
5851
5922
|
type: object
|
|
5852
|
-
|
|
5853
|
-
|
|
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]
|
|
5854
5933
|
properties:
|
|
5855
5934
|
type: { const: meta }
|
|
5856
5935
|
version: { type: integer }
|
|
5857
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.' }
|
|
5858
5939
|
FleetFrame_snapshot:
|
|
5859
5940
|
type: object
|
|
5860
5941
|
description: 'Connect-time FULL state (the visible, scope-stripped rows). Seed the active-set Map from this.'
|
|
@@ -8603,6 +8684,43 @@ components:
|
|
|
8603
8684
|
delivery: { type: string, const: applied, description: 'Literal "applied" on today''s server.' }
|
|
8604
8685
|
marker: { type: string, description: 'Engine-minted delivery marker.' }
|
|
8605
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
|
+
|
|
8606
8724
|
WorkspaceSnapshotRow:
|
|
8607
8725
|
type: object
|
|
8608
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
|
}
|
package/registry-openapi.yaml
CHANGED
|
@@ -153,8 +153,21 @@ paths:
|
|
|
153
153
|
- { in: path, name: domain, required: true, schema: { type: string } }
|
|
154
154
|
get:
|
|
155
155
|
operationId: registryScopeConfigDraftGet
|
|
156
|
-
summary: Read a scope's config DRAFT
|
|
157
|
-
|
|
156
|
+
summary: Read a scope's config — DRAFT by default, or the PUBLISHED snapshot with `?source=published`.
|
|
157
|
+
# 🔴 RC-6(2026-08-02):`?source=published` 此前完全未成文,而 SDK 的 `getScopeConfigPublished`
|
|
158
|
+
# (`scope-config-feedback.ts:46`)一直在打它 —— 两个响应形不同(draft 是 `{value, version}`,
|
|
159
|
+
# published 是 `{value, published, publishedAt?}`),按 spec codegen 的人只知道 draft 那一个。
|
|
160
|
+
parameters:
|
|
161
|
+
- in: query
|
|
162
|
+
name: source
|
|
163
|
+
required: false
|
|
164
|
+
schema: { type: string, enum: [published] }
|
|
165
|
+
description: 'Omit ⇒ the DRAFT (workspace) read. `published` ⇒ the PUBLISHED snapshot — what members actually receive.'
|
|
166
|
+
responses:
|
|
167
|
+
'200':
|
|
168
|
+
description: >
|
|
169
|
+
Without `?source=`: the draft, `{value, version, …}` — `version` is the CAS baseline for the PUT.
|
|
170
|
+
With `?source=published`: `{value, published, publishedAt?, …}`.
|
|
158
171
|
put:
|
|
159
172
|
operationId: registryScopeConfigDraftPut
|
|
160
173
|
summary: CAS-write the draft (putScopeConfigDraft; version NUMBER axis — not updatedAt).
|
|
@@ -164,10 +177,28 @@ paths:
|
|
|
164
177
|
/api/v1/scopes/{s}/publish:
|
|
165
178
|
parameters:
|
|
166
179
|
- { in: path, name: s, required: true, schema: { type: string } }
|
|
180
|
+
# 🔴 RC-6(2026-08-02):此前这条路径**只有 post、只有 '200'**。两个后果,都命中同一个设计的核心:
|
|
181
|
+
# ① 缺 `get` ⇒ 按本 spec(随 npm 包发布,package.json exports `./registry-openapi.yaml`)生成客户端的人
|
|
182
|
+
# 拿不到状态查询 verb —— 而 SDK 的 `getPublishState` 一直在打它。
|
|
183
|
+
# ② 缺 `'202'` ⇒ 拿不到 pending 分支,他会把 202 当成一个未处理的异常状态。而 200/202 的判别**就是**
|
|
184
|
+
# 这条设计的核心(`scope-config-feedback.ts:85-86` 明写「消费方绝不许把 202 渲染成已发布」)。
|
|
185
|
+
# 现有的 registry path 门是双向零基线的、很强 —— 但它比对的是**路径集合**,method/responses 全不参与,
|
|
186
|
+
# 所以这两类问题结构上红不了。同批把那道门升到了 path × method(见 test/registry-spec-path-gate.test.ts)。
|
|
187
|
+
get:
|
|
188
|
+
operationId: registryScopePublishState
|
|
189
|
+
summary: Read the publish state (getPublishState) — is a request already pending, and how many approvals does it need?
|
|
190
|
+
responses:
|
|
191
|
+
'200':
|
|
192
|
+
description: >
|
|
193
|
+
`{published?, pending?, approvalsRequired}`. `pending` present ⇒ a request is already outstanding and a
|
|
194
|
+
new one cannot be opened. ⚠️ `approvalsRequired` gates a PROTECTION; if it is ever absent, treat that as
|
|
195
|
+
unknown and fail CLOSED — never render "no approval needed".
|
|
167
196
|
post:
|
|
168
197
|
operationId: registryScopePublishRequest
|
|
169
198
|
summary: Request publish of the draft (requestPublish; goes through the approval gate).
|
|
170
|
-
responses:
|
|
199
|
+
responses:
|
|
200
|
+
'200': { description: 'PUBLISHED — the draft took effect immediately (no approval gate, or already satisfied).' }
|
|
201
|
+
'202': { description: 'PENDING — the approval gate is open and the draft is NOT in effect. Approvers act via …/publish/approve. A consumer MUST NOT render this as published.' }
|
|
171
202
|
|
|
172
203
|
# ── feedback ──────────────────────────────────────────────────────────────────────────────────
|
|
173
204
|
/api/v1/feedback:
|