@sema-agent/sdk 15.4.0 → 16.0.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 +57 -0
- package/dist/errors.d.ts +25 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +33 -0
- package/dist/errors.js.map +1 -1
- package/dist/events.d.ts +14 -2
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/resources/runs.d.ts +9 -1
- package/dist/resources/runs.d.ts.map +1 -1
- package/dist/resources/runs.js +9 -1
- package/dist/resources/runs.js.map +1 -1
- package/dist/resources/sessions.d.ts +15 -2
- package/dist/resources/sessions.d.ts.map +1 -1
- package/dist/resources/sessions.js +15 -2
- package/dist/resources/sessions.js.map +1 -1
- package/dist/types.d.ts +111 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/openapi.yaml +278 -23
- package/package.json +1 -1
package/openapi.yaml
CHANGED
|
@@ -1708,7 +1708,7 @@ paths:
|
|
|
1708
1708
|
'404':
|
|
1709
1709
|
description: >
|
|
1710
1710
|
Non-owner / unknown session (no existence oracle) — or, with `?message=`, an out-of-range index, whose
|
|
1711
|
-
body additionally carries `total`.
|
|
1711
|
+
body additionally carries `total`. server >= 7.113.0 (S-989; wire VALUE change, no new key): the unknown arm AND the non-owner arm answer `errorCode: "not_found.session"` + `error: "session not found"`, byte-identical (status and body) — one door, one spelling, no existence oracle. server <= 7.112.0 answered the non-owner arm in the RUN spelling (`not_found.run` + the long run-not-found sentence) while the unknown arm already said `not_found.session` — two codes and two sentences on one endpoint WAS the oracle. The SDK lands both arms on `NotFoundError`: branch on the class, never on the code to tell "no such session" from "not yours" (that distinction is exactly what the server refuses to give); the run face `/v1/runs/{taskId}` is unchanged (`not_found.run`).
|
|
1712
1712
|
content:
|
|
1713
1713
|
application/json:
|
|
1714
1714
|
schema:
|
|
@@ -1844,7 +1844,12 @@ paths:
|
|
|
1844
1844
|
leafId: { type: ["string", "null"], description: "null = session exists but has no entries yet." }
|
|
1845
1845
|
'304': { description: 'Leaf unchanged since the presented ETag (no body).' }
|
|
1846
1846
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
1847
|
-
'404':
|
|
1847
|
+
'404':
|
|
1848
|
+
description: >
|
|
1849
|
+
Unknown session or another principal's session. server >= 7.113.0 (S-989; wire VALUE change, no new key): the unknown arm AND the non-owner arm answer `errorCode: "not_found.session"` + `error: "session not found"`, byte-identical (status and body) — one door, one spelling, no existence oracle. server <= 7.112.0 answered the non-owner arm in the RUN spelling (`not_found.run` + the long run-not-found sentence) while the unknown arm already said `not_found.session` — two codes and two sentences on one endpoint WAS the oracle. The SDK lands both arms on `NotFoundError`: branch on the class, never on the code to tell "no such session" from "not yours" (that distinction is exactly what the server refuses to give); the run face `/v1/runs/{taskId}` is unchanged (`not_found.run`).
|
|
1850
|
+
content:
|
|
1851
|
+
application/json:
|
|
1852
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
1848
1853
|
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
1849
1854
|
|
|
1850
1855
|
/v1/sessions/{sessionId}/events:
|
|
@@ -1880,7 +1885,12 @@ paths:
|
|
|
1880
1885
|
text/event-stream:
|
|
1881
1886
|
schema: { type: string }
|
|
1882
1887
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
1883
|
-
'404':
|
|
1888
|
+
'404':
|
|
1889
|
+
description: >
|
|
1890
|
+
Unknown session or another principal's session (answered BEFORE the SSE `200` headers go out). server >= 7.113.0 (S-989; wire VALUE change, no new key): the unknown arm AND the non-owner arm answer `errorCode: "not_found.session"` + `error: "session not found"`, byte-identical (status and body) — one door, one spelling, no existence oracle. server <= 7.112.0 answered the non-owner arm in the RUN spelling (`not_found.run` + the long run-not-found sentence) while the unknown arm already said `not_found.session` — two codes and two sentences on one endpoint WAS the oracle. The SDK lands both arms on `NotFoundError`: branch on the class, never on the code to tell "no such session" from "not yours" (that distinction is exactly what the server refuses to give); the run face `/v1/runs/{taskId}` is unchanged (`not_found.run`).
|
|
1891
|
+
content:
|
|
1892
|
+
application/json:
|
|
1893
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
1884
1894
|
'500':
|
|
1885
1895
|
description: >-
|
|
1886
1896
|
(declared 2026-07-31) errorCode "internal.error" — `routes/sessions.ts`'s catch around the owner
|
|
@@ -2057,7 +2067,17 @@ paths:
|
|
|
2057
2067
|
'400': { $ref: '#/components/responses/BadRequest' }
|
|
2058
2068
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
2059
2069
|
'404': { description: 'No parked checkpoint for this session (nothing to wake), or session not visible to the caller.' }
|
|
2060
|
-
'409':
|
|
2070
|
+
'409':
|
|
2071
|
+
description: >
|
|
2072
|
+
Pending gate (`wake.gate_pending` — decide it through its own entry) or resume context missing; also the resume-leg refusals core
|
|
2073
|
+
raises before the claim (`steering.blocked_by_hook` when the wake carried a `message` and the deployment's `userPromptSubmit`
|
|
2074
|
+
hook crashed / timed out / refused — server >= 7.113.0 adds `retriable: true` there; `checkpoint.config_refused`). Value change on
|
|
2075
|
+
the run row the wake minted for the refused attempt (server >= 7.113.0): it now ends `failed` with a structured terminal carrying
|
|
2076
|
+
`terminal.code: "steering.blocked_by_hook"` and holds no session lock (before 7.113.0 it ended with a code-less terminal and
|
|
2077
|
+
`result: null` — a zero-execution refusal recorded as an ordinary failure); the card itself stays pending.
|
|
2078
|
+
content:
|
|
2079
|
+
application/json:
|
|
2080
|
+
schema: { $ref: '#/components/schemas/ResumeLegConflictError' }
|
|
2061
2081
|
'422': { description: '`steering.invalid_content` — the message failed the steering content gate.' }
|
|
2062
2082
|
'429': { $ref: '#/components/responses/RateLimited' }
|
|
2063
2083
|
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
@@ -3307,7 +3327,7 @@ paths:
|
|
|
3307
3327
|
parked row carries no root-session anchor (refused before the claim, nothing consumed).
|
|
3308
3328
|
content:
|
|
3309
3329
|
application/json:
|
|
3310
|
-
schema: { $ref: '#/components/schemas/
|
|
3330
|
+
schema: { $ref: '#/components/schemas/ResumeLegConflictError' }
|
|
3311
3331
|
# 🔴 REMOVED 2026-07-31 — the 410 that never was. `grep -rn "\b410\b" src/` across the whole server
|
|
3312
3332
|
# is ZERO hits: `approval_stale` ships as a **409** carrying `errorCode: "approval_stale"` (the CAS
|
|
3313
3333
|
# 409 stays bare → ConflictError, so the two 409s never collide). The `terminal` enum values
|
|
@@ -6614,12 +6634,18 @@ components:
|
|
|
6614
6634
|
|
|
6615
6635
|
RunStatus:
|
|
6616
6636
|
type: string
|
|
6617
|
-
enum: [running, completed, failed, suspended, needs_review]
|
|
6637
|
+
enum: [running, completed, failed, suspended, needs_review, blocked]
|
|
6618
6638
|
description: >
|
|
6619
6639
|
`suspended` = HITL (an F4 policy gate or AskUserQuestion is waiting on a human) — NOT an error.
|
|
6620
6640
|
`needs_review` (design/80 D-0) = durable TERMINAL of a dry-run/shadow review (POST-prediction),
|
|
6621
6641
|
distinct from the mid-run `suspended` pause. A user-cancelled run is `failed` with `errorCode`
|
|
6622
6642
|
"cancelled" (cancel is LIVE; `cancelling` is a cancel-ack field, NOT a member of this enum).
|
|
6643
|
+
`blocked` = durable TERMINAL: the run ended without doing the work (`result.terminal.kind: "blocked"` — the agent's
|
|
6644
|
+
`ReportBlocked`, or, server >= 7.113.0, a deployment `userPromptSubmit` hook keeping the prompt from being submitted, see
|
|
6645
|
+
`TerminalBlockedDetail`); a governance verdict, not an error. The server's run-status table has it (`blocked`, an
|
|
6646
|
+
unsuccessful terminal) and the SDK type has listed it since 2.1.4 (whose own note records the server passing core's status words
|
|
6647
|
+
through verbatim from 3.x); this enum was the one place that did not (declared in sdk 16.0.0 when the real-projector pins
|
|
6648
|
+
validated a blocked run row against it).
|
|
6623
6649
|
|
|
6624
6650
|
TaskStats:
|
|
6625
6651
|
type: object
|
|
@@ -7357,6 +7383,15 @@ components:
|
|
|
7357
7383
|
description: >
|
|
7358
7384
|
Turn-boundary reminder attachments (design/133 + G1). Each flag opts INTO an injection; omitted = off.
|
|
7359
7385
|
`changedFiles` may also be an object to cap the listing.
|
|
7386
|
+
🔴 BREAKING (server >= 7.113.0 / core 7.39.0 #1254; K-44): `planModeReminder` was retired and is no longer declared
|
|
7387
|
+
here. A submit body that carries it — any value, `false` included (the server's gate tests `!== undefined`, not
|
|
7388
|
+
truthiness) — is refused 400 `request.field_invalid` with a sentence naming the retirement; before 7.113.0 it was
|
|
7389
|
+
accepted and the engine refused later, at prepare. The engine now states plan posture itself whenever the
|
|
7390
|
+
permission mode is "plan" (first request, periodic reminders, exit frame): remove the key and send
|
|
7391
|
+
`permissionMode: "plan"`. A stored body that still carries the key resumes with the key dropped (resume replays
|
|
7392
|
+
are not refused). THIS schema stays open (`additionalProperties: true`), so a validator built from it will not
|
|
7393
|
+
reject the key — the refusal is the server's, not this schema's. A server <= 7.112.x still accepts the key; this
|
|
7394
|
+
package no longer declares it (sdk 16.0.0, major).
|
|
7360
7395
|
additionalProperties: true
|
|
7361
7396
|
properties:
|
|
7362
7397
|
todoReminder: { type: boolean }
|
|
@@ -7365,7 +7400,6 @@ components:
|
|
|
7365
7400
|
oneOf:
|
|
7366
7401
|
- { type: boolean }
|
|
7367
7402
|
- { type: object, properties: { maxFiles: { type: integer } } }
|
|
7368
|
-
planModeReminder: { type: boolean }
|
|
7369
7403
|
budgetUsd: { type: boolean }
|
|
7370
7404
|
backgroundTasks: { type: boolean }
|
|
7371
7405
|
toolsDelta: { type: boolean }
|
|
@@ -7504,11 +7538,42 @@ components:
|
|
|
7504
7538
|
TerminalCause_blocked:
|
|
7505
7539
|
type: object
|
|
7506
7540
|
additionalProperties: false
|
|
7507
|
-
description:
|
|
7541
|
+
description: >
|
|
7542
|
+
The run ended without doing the work (a governance verdict is NOT a failure). Two sources, told apart by `detail`: with NO
|
|
7543
|
+
`detail` — the agent's own words from its `ReportBlocked` call; with `detail.kind: "prompt_blocked_by_hook"` (server >= 7.113.0 /
|
|
7544
|
+
core #1277; K-43-class closed-object gap) — the engine's sentence about the deployment's `userPromptSubmit` hook, framed as a
|
|
7545
|
+
reminder for the model-facing lane. Terminal: the run is over and nobody is being waited on (contrast `paused`).
|
|
7546
|
+
Same shape on all four faces (the synchronous 200 body, the stream's `done.result`, `GET /v1/runs/{taskId}` -> `result`, the
|
|
7547
|
+
ledger `done` row).
|
|
7508
7548
|
required: [kind, reason]
|
|
7509
7549
|
properties:
|
|
7510
7550
|
kind: { const: blocked }
|
|
7511
|
-
reason: { type: string, description: 'Why the agent
|
|
7551
|
+
reason: { type: string, description: 'Why the run ended without doing the work (the agent''s words, or the engine''s framed hook sentence — branch on `detail?.kind`, never on this prose).' }
|
|
7552
|
+
detail:
|
|
7553
|
+
allOf: [{ $ref: '#/components/schemas/TerminalBlockedDetail' }]
|
|
7554
|
+
description: >
|
|
7555
|
+
server >= 7.113.0 (core #1277) — WHO stopped the run, for the one shape a consumer offers its own way out of: the prompt was
|
|
7556
|
+
NOT submitted (the objective never became a message and the loop never started), so changing it and sending again is
|
|
7557
|
+
meaningful. PRESENT only on that terminal; ABSENT means the agent reported `ReportBlocked` ("I cannot go on"), or a server
|
|
7558
|
+
before 7.113.0.
|
|
7559
|
+
|
|
7560
|
+
TerminalBlockedDetail:
|
|
7561
|
+
type: object
|
|
7562
|
+
additionalProperties: false
|
|
7563
|
+
required: [kind, cause]
|
|
7564
|
+
description: >
|
|
7565
|
+
server >= 7.113.0 (core #1277; K-44) — the machine-readable account of a `blocked` terminal caused by the deployment's
|
|
7566
|
+
`userPromptSubmit` hook. `kind` is closed (`prompt_blocked_by_hook`, one member today). `cause` is the closed four-word set of the hook seat's endings that keep a
|
|
7567
|
+
prompt from being submitted (core `PROMPT_BLOCK_CAUSES`): `block` — the hook answered and refused (its words ride `hookReason`);
|
|
7568
|
+
`crashed` — the hook threw or rejected (the seat is fail-closed: a screen that failed has not cleared the prompt); `timeout` — no
|
|
7569
|
+
answer within the hook's `timeoutMs` bound (fail-closed the same way); `cancelled` — the task was cancelled while the hook was
|
|
7570
|
+
still screening. `hookReason` is the hook's OWN words (present only on cause `block`, and only when the hook gave some): folded to
|
|
7571
|
+
one line, bounded, with the engine's envelope tags defused and passed through the same secret redaction as `reason` — still the
|
|
7572
|
+
hook's text, so render it as untrusted. A word outside the four is read as "the hook seat stopped the prompt, cause not recognised".
|
|
7573
|
+
properties:
|
|
7574
|
+
kind: { const: prompt_blocked_by_hook }
|
|
7575
|
+
cause: { type: string, enum: [block, crashed, timeout, cancelled] }
|
|
7576
|
+
hookReason: { type: string, description: 'The hook''s own refusal words (untrusted free text; present only on `block` and only when stated).' }
|
|
7512
7577
|
|
|
7513
7578
|
PausedCause:
|
|
7514
7579
|
type: object
|
|
@@ -7656,6 +7721,18 @@ components:
|
|
|
7656
7721
|
verdict: { type: string, enum: [PASS, FAIL, PARTIAL, unverified] }
|
|
7657
7722
|
rounds: { type: integer }
|
|
7658
7723
|
findings: { type: array, items: { type: string } }
|
|
7724
|
+
cancelContext:
|
|
7725
|
+
allOf: [{ $ref: '#/components/schemas/CancelContext' }]
|
|
7726
|
+
description: >
|
|
7727
|
+
server >= 7.57.0 (S-94; contract §5.3; K-43 — named here in sdk 16.0.0, it was only readable through this schema's open
|
|
7728
|
+
index before) — the SCENE SNAPSHOT of a USER CANCEL, a side key beside `abortCause` (both are minted by the same mint
|
|
7729
|
+
point, `mintCancelledResult`, under the same "fill the empty seat only" gate; neither lives inside `terminal`).
|
|
7730
|
+
PRESENT only on a cancelled terminal the server minted; ABSENT on a model's own failure / a normal completion, and
|
|
7731
|
+
ABSENT as a whole when not one of its keys can be proven (the server never mints an empty object — absence reads as "no
|
|
7732
|
+
cancel scene to look at", NOT "nothing was wrong at cancel time"). Landings: `GET /v1/runs/{taskId}` -> `result.cancelContext`
|
|
7733
|
+
(and the same object rides the other cancelled-terminal landings listed on `abortCause`). Shape and per-key reading
|
|
7734
|
+
rules: `CancelContext`.
|
|
7735
|
+
|
|
7659
7736
|
abortCause:
|
|
7660
7737
|
allOf: [{ $ref: '#/components/schemas/AbortCause' }]
|
|
7661
7738
|
description: >
|
|
@@ -7703,6 +7780,59 @@ components:
|
|
|
7703
7780
|
CLOSED set, additive-only by the server's rule (a new word is a new server version in `wire-changes` AND a new SDK
|
|
7704
7781
|
minor, in this enum in the same batch): read an unknown word as "the server aborted this run, cause not recognised".
|
|
7705
7782
|
|
|
7783
|
+
CancelContext:
|
|
7784
|
+
type: object
|
|
7785
|
+
# 封闭(K-43,sdk 16.0.0):铸点 `run-cancel-context.js` `buildCancelContext` 是逐键条件 spread 的字面量(lastEventKind / lastEventAgeMs / lastBrainStatus / elapsedMs),
|
|
7786
|
+
# `lastBrainStatus` 经 `turn-activity.js` `pickRunBrainStatus` 投成五键(刻意不含 provider 自由文本 `detail` 与相对量 `retryInMs`)—— 与本 schema 一一对上;
|
|
7787
|
+
# `test/server-7113-wire.test.ts` K3 用真 `recordTurnActivity` + 真 `mintCancelledResult` 的字节逐键核。
|
|
7788
|
+
additionalProperties: false
|
|
7789
|
+
description: >
|
|
7790
|
+
The scene snapshot of a user cancel (server >= 7.57.0 / S-94; contract §5.3; K-43): "how long since this server last heard
|
|
7791
|
+
from this run" — triage material, never a state-machine input. 🔴 It is NOT the model-call phase: the server structurally
|
|
7792
|
+
cannot see first-byte waits or retries (that half lives in the engine's stream layer); `lastEventAgeMs` is NOT "how long the
|
|
7793
|
+
model has been hung" (a long tool call produces no ledger event either). Every key is optional and absence is honest:
|
|
7794
|
+
`lastEventKind` / `lastEventAgeMs` come from a SAME-REPLICA in-process activity registry (a cross-replica cancel or a
|
|
7795
|
+
replica restart cannot read it — absent means "this replica cannot prove it", never fold it to 0: that would render a
|
|
7796
|
+
8-minute hang as "just alive"); `lastEventKind` is MORE likely to be absent than `lastEventAgeMs` (some activity seats advance
|
|
7797
|
+
the clock without a word), so "age without kind" is a legal reading; `lastBrainStatus` is absent when the run never
|
|
7798
|
+
emitted a `status` frame or the replica cannot read it; `elapsedMs` (run start to cancel, wall clock) is normally present
|
|
7799
|
+
and absent only when the row's `createdAt` cannot be parsed (again never folded to 0). The side key `abortCause` says WHO
|
|
7800
|
+
stopped the run; this object says what the server saw at that moment.
|
|
7801
|
+
properties:
|
|
7802
|
+
lastEventKind:
|
|
7803
|
+
type: string
|
|
7804
|
+
description: 'The type of the last event that entered this run''s durable ledger (`text` / `tool_start` / `status` / ...). Open string.'
|
|
7805
|
+
lastEventAgeMs:
|
|
7806
|
+
type: number
|
|
7807
|
+
minimum: 0
|
|
7808
|
+
description: 'Milliseconds since that last durable event (>= 0).'
|
|
7809
|
+
lastBrainStatus:
|
|
7810
|
+
allOf: [{ $ref: '#/components/schemas/CancelContextBrainStatus' }]
|
|
7811
|
+
description: >
|
|
7812
|
+
The last `status` (BrainStatus) frame at the tail of the run's ledger (an S-94 extension), as a five-key subset — "which
|
|
7813
|
+
retry, waiting for what, which error class". STICKY: later text / tool events do not clear it. Absent when the run never
|
|
7814
|
+
emitted a `status` frame or this replica cannot read it (never `null`).
|
|
7815
|
+
elapsedMs:
|
|
7816
|
+
type: number
|
|
7817
|
+
minimum: 0
|
|
7818
|
+
description: 'Wall-clock milliseconds from the run''s start to this cancel (>= 0).'
|
|
7819
|
+
|
|
7820
|
+
CancelContextBrainStatus:
|
|
7821
|
+
type: object
|
|
7822
|
+
additionalProperties: false
|
|
7823
|
+
required: [phase]
|
|
7824
|
+
description: >
|
|
7825
|
+
The five-key subset of the last BrainStatus frame (`CancelContext.lastBrainStatus`; K-43). `phase` is the snapshot's reason to
|
|
7826
|
+
exist (no phase, no snapshot — never half of one). Deliberately NOT carried: `detail` (provider free text) and `retryInMs` /
|
|
7827
|
+
`retryInSec` (relative values go stale; `retryAtMs` is the cross-process one — a wall-clock instant on the SENDING process's
|
|
7828
|
+
clock, an approximation, never compare it with a local monotonic timer).
|
|
7829
|
+
properties:
|
|
7830
|
+
phase: { type: string }
|
|
7831
|
+
attempt: { type: number }
|
|
7832
|
+
maxRetries: { type: number }
|
|
7833
|
+
retryAtMs: { type: number }
|
|
7834
|
+
errClass: { type: string }
|
|
7835
|
+
|
|
7706
7836
|
LegacyPlaneTaskResult:
|
|
7707
7837
|
type: object
|
|
7708
7838
|
additionalProperties: true
|
|
@@ -7912,10 +8042,14 @@ components:
|
|
|
7912
8042
|
changed shape with it (`result.terminal`, no plane keys): the row's `errorCode` column is now projected
|
|
7913
8043
|
from `result.terminal` (`src/http/routes/runs.ts` -> `persistedPlaneOf`, which also reads the flat bytes
|
|
7914
8044
|
7.63.0 and earlier wrote to disk), NOT copied from a `result.errorCode` that no longer exists.
|
|
7915
|
-
# 封闭(census 轴一,2026-07-30;A-075.21 回填后 12
|
|
8045
|
+
# 封闭(census 轴一,2026-07-30;A-075.21 回填后 12 键;**K-43 / sdk 16.0.0 补 `heldBy` / `cancelRequested` 后 14 键**):铸造点 routes/runs.ts 是一个逐键写死的
|
|
7916
8046
|
# 字面量(taskId/sessionId/status/msSinceLastActivity/crossSliceUsage/result/supervisorCost/
|
|
7917
|
-
# suggestions/errorCode/error/jobId/source),与本 properties 一一对上;只有 taskId/sessionId/status
|
|
7918
|
-
# 无条件在场(其余走 `?? undefined` / 条件 spread ⇒ JSON 丢键)⇒ required 维持 3
|
|
8047
|
+
# suggestions/errorCode/error/jobId/source/heldBy/cancelRequested),与本 properties 一一对上;只有 taskId/sessionId/status
|
|
8048
|
+
# 无条件在场(其余走 `?? undefined` / 条件 spread ⇒ JSON 丢键)⇒ required 维持 3 键(`heldBy` / `cancelRequested` 在 server >= 7.73.0 上恒在场,
|
|
8049
|
+
# 但 required 不抬:本包支持底线 3.0.0,老 server 没有这两键)。
|
|
8050
|
+
# 🔴 K-43(既存缺口,与 abortCause 无关,K-41 同病):`heldBy` / `cancelRequested` 自 server 7.73.0(S-230 P-45)就在真 `GET /v1/runs/:id` 上,
|
|
8051
|
+
# 而本封闭对象一直没声明它们 ⇒ 按本 schema 严格校验响应的消费方会得「$ must NOT have additional properties」;门 6 契约套抓不到,
|
|
8052
|
+
# 由 `test/server-7113-wire.test.ts` K3(真 `handleRuns` 字节 × spec)抓。
|
|
7919
8053
|
# (A-075.21:此前的「恰好 10 键」对 msSinceLastActivity(#245 S1)/crossSliceUsage([3833] S-4)
|
|
7920
8054
|
# 两条铸键路径结构性失明 —— server test/producer-contract.test.ts 的 S-4 登记钉逐字记着这笔账。)
|
|
7921
8055
|
additionalProperties: false
|
|
@@ -7983,6 +8117,29 @@ components:
|
|
|
7983
8117
|
items: { type: string }
|
|
7984
8118
|
description: Follow-up prompt suggestions produced for this run (absent when none were generated).
|
|
7985
8119
|
supervisorCost: { $ref: '#/components/schemas/SupervisorCostBreakdown' }
|
|
8120
|
+
heldBy:
|
|
8121
|
+
type: [string, "null"]
|
|
8122
|
+
description: >
|
|
8123
|
+
server >= 7.73.0 (S-230 P-45; contract §5.5 (c); K-43 — the mint has carried it since 7.73.0, this closed schema
|
|
8124
|
+
did not declare it) — the replica HOLDING this run NOW (the row's `instance_id`: written at create, TAKEN OVER by a
|
|
8125
|
+
cross-replica resume claim), so it answers "where is the live leg", not "who created the row". Always present on a
|
|
8126
|
+
server that has it, and an explicit `null` (never a missing key) means no replica holds it. 🔴 `heldBy` becoming
|
|
8127
|
+
`null` OR the run reaching a terminal status = the claim is released (either one); on a terminal row `heldBy` reads
|
|
8128
|
+
as a HISTORICAL fact ("which replica finished it"), not "still occupied". ⚠️ The one exception is the stale fold: a
|
|
8129
|
+
`running` row older than the stale window is shown with `status: "failed"` + `error: "run stalled (instance lost?)"`
|
|
8130
|
+
— that is the READ's judgement; the ledger row is still `running` and its claim is held until the reaper's next beat,
|
|
8131
|
+
and `heldBy` still names the LOST replica (the one useful coordinate when debugging). A deployment-internal replica
|
|
8132
|
+
identity, not a user-readable location. Absent on a server < 7.73.0.
|
|
8133
|
+
cancelRequested:
|
|
8134
|
+
type: boolean
|
|
8135
|
+
description: >
|
|
8136
|
+
server >= 7.73.0 (S-230 P-45; contract §5.5 (c); K-43) — the durable cancel flag (cross-replica; the holding replica
|
|
8137
|
+
polls it on its heartbeat beat). ⚠️ It is a pending cancel: a run that has already been cancelled is spoken by `status` +
|
|
8138
|
+
`errorCode: "cancelled"` (a park-arm cancel never goes through this flag — it finalizes the row directly), and a resume
|
|
8139
|
+
claim CLEARS the flag (a cancel that landed on a suspend must not kill the run again after it resumes). So never read
|
|
8140
|
+
`cancelRequested` flipping back to `false` as "the cancel completed" — wait for a terminal `status` + `errorCode:
|
|
8141
|
+
"cancelled"`. The `cancelling` 202 ack of `POST /v1/runs/{taskId}/cancel` carries the same key
|
|
8142
|
+
(`CancelAck.cancelRequested`). Absent on a server < 7.73.0.
|
|
7986
8143
|
|
|
7987
8144
|
SupervisorCostBreakdown:
|
|
7988
8145
|
type: object
|
|
@@ -8020,14 +8177,23 @@ components:
|
|
|
8020
8177
|
description: >
|
|
8021
8178
|
Synchronous ack for `POST /v1/runs/:id/cancel`. `status` is "cancelling" (accepted) or a terminal status
|
|
8022
8179
|
(idempotent no-op). NOTE: "cancelling" is NOT a RunStatus enum member — it only appears here.
|
|
8023
|
-
# 封闭(census 轴一,2026-07-30):cancel 面的
|
|
8024
|
-
#
|
|
8180
|
+
# 封闭(census 轴一,2026-07-30):cancel 面的 sendJson 铸造点键集的并集 = {taskId, status, note?, errorCode?, cancelRequested};
|
|
8181
|
+
# taskId/status 无条件在场。🔴 K-43 / sdk 16.0.0 补 `cancelRequested`:自 server 7.73.0(S-230 P-45)每一个 2xx 受理体都带它,
|
|
8182
|
+
# 而本封闭对象一直没声明 ⇒ 严格校验回执的消费方会得「$ must NOT have additional properties」;`test/server-7113-wire.test.ts` K3 抓(真 `handleRuns` 三臂字节 × spec)。
|
|
8025
8183
|
additionalProperties: false
|
|
8026
8184
|
required: [taskId, status]
|
|
8027
8185
|
properties:
|
|
8028
8186
|
taskId: { type: string }
|
|
8029
8187
|
status: { type: string }
|
|
8030
8188
|
note: { type: string }
|
|
8189
|
+
cancelRequested:
|
|
8190
|
+
type: boolean
|
|
8191
|
+
description: >
|
|
8192
|
+
server >= 7.73.0 (S-230 P-45; contract §5.5 (c); K-43) — the same predicate as `RunRecord.cancelRequested` (the durable
|
|
8193
|
+
cancel flag), present on every 2xx ack the cancel verb mints: `true` on the `status: "cancelling"` branch (the CAS just
|
|
8194
|
+
won — the flag is on the row and the holding replica's next beat reads it); `false` on the park-arm terminal branch (a
|
|
8195
|
+
parked run is finalized directly, no flag was needed); on the idempotent no-op branches and the concurrent-terminalized
|
|
8196
|
+
branch it reports the row's own flag value (`false` in the contract's account, §5.5 (c)). Absent on a server < 7.73.0.
|
|
8031
8197
|
errorCode:
|
|
8032
8198
|
type: [string, "null"]
|
|
8033
8199
|
description: >
|
|
@@ -12282,7 +12448,9 @@ components:
|
|
|
12282
12448
|
description: >-
|
|
12283
12449
|
server >=7.110.0 (S-928 user-input acceptance ledger): user inputs this session LOST to a crash —
|
|
12284
12450
|
the server had answered 200 `applied` (interrupt{text}: 202) but the process carrying that run died
|
|
12285
|
-
before the
|
|
12451
|
+
before the engine confirmed consuming them (server >= 7.113.0 / core 7.39.0 #1273: an acceptance the engine confirmed
|
|
12452
|
+
consuming is settled `consumed` and is no longer listed here — the <= 7.112.x reading "whether the run consumed
|
|
12453
|
+
them is not known" narrowed to this; it still does NOT say "never consumed"; see `engine_notice`
|
|
12286
12454
|
`task.user_steer_undrained{cause:"crashed"}`). Converged rows only, one row per (taskId, messageId),
|
|
12287
12455
|
newest 500. From server >=7.111.0 (S-966) the rows include SUBAGENT steers (recorded under the run on the
|
|
12288
12456
|
receipt; same row shape, `kind` is still only `steer`; `messageId` = the subagent steer receipt's).
|
|
@@ -13067,7 +13235,9 @@ components:
|
|
|
13067
13235
|
On 400 `request.field_invalid` for a `settings.permissions` bucket (server >= 7.106.0 / S-904): which bucket —
|
|
13068
13236
|
`settings.permissions.allow` | `settings.permissions.deny` | `settings.permissions.ask`. (`rules.*` content refusals
|
|
13069
13237
|
carry their own `field`.) Resume legs carry the same group on 409 `resume_blocked_by_policy`
|
|
13070
|
-
(`blockedBy: "request.field_invalid"`).
|
|
13238
|
+
(`blockedBy: "request.field_invalid"`). Also on 409 `checkpoint.config_refused` (server >= 7.113.0): which part of the
|
|
13239
|
+
row's configuration was refused — `taskConfig` (change the configuration, then decide the SAME card again) or
|
|
13240
|
+
`inheritedGate` (the row's recorded mode seed is bad — the run can only be cancelled). SDK: `err.extra.field`.
|
|
13071
13241
|
count:
|
|
13072
13242
|
type: integer
|
|
13073
13243
|
description: 'S-904 `reason: over_cap` only — how many entries the bucket had (server >= 7.106.0). SDK: `err.extra.count`.'
|
|
@@ -13086,6 +13256,38 @@ components:
|
|
|
13086
13256
|
(S-607); before that it was absent when the original refusal carried no code. SDK:
|
|
13087
13257
|
`ResumeBlockedByPolicyError.blockedBy` (`undefined` when the key is absent or not a string — never defaulted).
|
|
13088
13258
|
|
|
13259
|
+
ResumeLegConflictError:
|
|
13260
|
+
description: >
|
|
13261
|
+
The 409 body of a RESUME LEG that core refused BEFORE the claim (`POST /v1/approvals/{sessionId}/decide`,
|
|
13262
|
+
`POST /v1/sessions/{sessionId}/wake`): `ErrorResponse` plus the one key those 409s may add, `retriable`. The key is declared HERE and
|
|
13263
|
+
not on the shared `ErrorResponse` on purpose (codex r1 [medium], sdk 16.0.0): `ErrorResponse` is the body of every error
|
|
13264
|
+
response in this document, and declaring `retriable` there would offer a retry signal on 401 / 404 / 422 / 5xx bodies where the
|
|
13265
|
+
server never mints it. (`ErrorResponse` stays open, so a validator cannot REJECT the key elsewhere; the confinement is that only
|
|
13266
|
+
these 409 responses reference this schema, and a test pins that count.)
|
|
13267
|
+
allOf:
|
|
13268
|
+
- $ref: '#/components/schemas/ErrorResponse'
|
|
13269
|
+
- type: object
|
|
13270
|
+
properties:
|
|
13271
|
+
retriable:
|
|
13272
|
+
type: boolean
|
|
13273
|
+
enum: [true]
|
|
13274
|
+
description: >-
|
|
13275
|
+
Only ever `true` (the server mints it from one conditional spread, `...(retriable ? { retriable: true } : {})`, in the
|
|
13276
|
+
one place that builds the 409 for a core `CheckpointError`; the only 404 that place can build, `checkpoint.not_found`, is
|
|
13277
|
+
never retriable) — absent otherwise, and absence means "the server did not say", NOT "not retriable". (The 200-status
|
|
13278
|
+
`{ status, errorCode?, retriable? }` bodies of the same legs carry the same key under their own schemas,
|
|
13279
|
+
`SessionWakeResult` and `ApprovalDecisionResult`.)
|
|
13280
|
+
Reading, one reading for the whole family: `retriable: true` = the pending card is STILL pending (core refused BEFORE the
|
|
13281
|
+
claim — the run row stays `suspended` and the card is untouched), NOT "a verbatim retry will succeed". server >= 7.113.0
|
|
13282
|
+
added the key to `checkpoint.walltime_axis_retired` (a pending row whose ledger carries the retired cross-slice walltime
|
|
13283
|
+
quota; a >= 7.39 engine refuses that row EVERY time, so the way out is `POST /v1/runs/{taskId}/cancel` first, then a new
|
|
13284
|
+
task on the same session — or finishing the run on a worker with the previous engine; before 7.113.0 this code ended the
|
|
13285
|
+
run `failed` with the session lock released and an orphaned card), to `steering.blocked_by_hook` on the `/wake` door (a
|
|
13286
|
+
wake carrying a `message` hit the deployment's `userPromptSubmit` hook crashing / timing out / refusing: the card stays
|
|
13287
|
+
pending and the same card can be woken again once the hook recovers; the live `steer` / `interrupt` doors answer the
|
|
13288
|
+
same code with 422 and no key), and to the new mirror code `checkpoint.config_refused` (409; the body also carries `field`:
|
|
13289
|
+
`taskConfig` | `inheritedGate`). Codes / status / `error` text are unchanged. SDK: `APIError.retriable`.
|
|
13290
|
+
|
|
13089
13291
|
# ── Streaming event taxonomy (the UX 命脉). Each SSE `data:` line is one JSON-serialized AgentEvent. ──
|
|
13090
13292
|
# TWO vocabularies (the pinned wire contract Drift 3). ⚠️ The two lines below are the SHAPE-DEFINING
|
|
13091
13293
|
# contrast (per-token deltas vs turn-aggregated), NOT an enumeration of either leg's arm set — the union
|
|
@@ -13409,8 +13611,8 @@ components:
|
|
|
13409
13611
|
|
|
13410
13612
|
Settlement:
|
|
13411
13613
|
description: >
|
|
13412
|
-
HOW the wait an ask was in ENDED — a DISCRIMINATED union on `kind` (core 7.6.0
|
|
13413
|
-
|
|
13614
|
+
HOW the wait an ask was in ENDED — a DISCRIMINATED union on `kind` (core `SETTLEMENT_KINDS`: 12 words at 7.6.0,
|
|
13615
|
+
14 as of core 7.39.0 — `policy_refused` joined at 7.26.2 and `policy_allowed` with the policy party at 7.39.0 / server 7.113.0; CLOSED). It is deliberately NOT a free product of `kind` x `who`: a free product can express
|
|
13414
13616
|
"human_allowed, ended by the engine's window" — a structurally complete record that contradicts itself.
|
|
13415
13617
|
`who` says WHICH PARTY ended it and its shape is fixed BY the word; `when` is epoch ms written at the
|
|
13416
13618
|
settlement site; a person's refusal carries the decider's own `note` when one was attached.
|
|
@@ -13421,6 +13623,7 @@ components:
|
|
|
13421
13623
|
secret-redacted (and `note` length-bounded) before they reach this wire.
|
|
13422
13624
|
oneOf:
|
|
13423
13625
|
- $ref: '#/components/schemas/Settlement_human'
|
|
13626
|
+
- $ref: '#/components/schemas/Settlement_policy'
|
|
13424
13627
|
- $ref: '#/components/schemas/Settlement_approval_window_expired'
|
|
13425
13628
|
- $ref: '#/components/schemas/Settlement_denial_limit_window_expired'
|
|
13426
13629
|
- $ref: '#/components/schemas/Settlement_park_sla_expired'
|
|
@@ -13443,6 +13646,34 @@ components:
|
|
|
13443
13646
|
when: { type: integer, format: int64, description: 'Epoch ms, written at the settlement site.' }
|
|
13444
13647
|
note: { type: string, description: 'The refusing decider''s own words, when one was attached. A refusal WITHOUT a note is a bare "no".' }
|
|
13445
13648
|
|
|
13649
|
+
Settlement_policy:
|
|
13650
|
+
type: object
|
|
13651
|
+
additionalProperties: false
|
|
13652
|
+
description: >
|
|
13653
|
+
The DEPLOYMENT'S OWN POLICY decided (server >= 7.113.0 / core 7.39.0 — the `policy` party; sdk 16.0.0, found by the
|
|
13654
|
+
lockstep's completeness sweep, not in the release's own post): the approval channel reported that a MACHINE, not a
|
|
13655
|
+
person, answered this ask. A person and a policy are the two DECIDERS — each answers either way and differs only in whose
|
|
13656
|
+
decision the record names (`human_allowed` / `human_refused` name a person; `policy_allowed` / `policy_refused` name the
|
|
13657
|
+
policy). Server 7.113.0 value changes (MIGRATION 7.113.0 "audit face"): on the unattended legs (leader worker / repair
|
|
13658
|
+
leg / `sema` CLI and their resumes) the machine's class-answer allow is now settled `policy_allowed` with
|
|
13659
|
+
`who.approver: "unattended_class_answer"` — it was `human_allowed` / `who.party: "person"` — and every policy refusal
|
|
13660
|
+
(`UNATTENDED_APPROVAL_POLICY=deny`, a run-local refusal without a TTY, a decision with `settledBy: "policy"`) is
|
|
13661
|
+
`policy_refused` with `who.party: "policy"` — it was `who.party: "none"` (still the shape on servers 7.93.3 – 7.112.x, where
|
|
13662
|
+
`policy_refused` lives on `Settlement_fail_closed`; both spellings stay valid here). Readers that bucket by party read the new
|
|
13663
|
+
word; a 7.112.x reader of a 7.113.0 ledger withholds the whole `gate` (it does not know the party). The refusal's own words
|
|
13664
|
+
reach the model as the policy's words and are NOT on this record (no `note` seat).
|
|
13665
|
+
required: [kind, who, when]
|
|
13666
|
+
properties:
|
|
13667
|
+
kind: { type: string, enum: [policy_allowed, policy_refused] }
|
|
13668
|
+
who:
|
|
13669
|
+
type: object
|
|
13670
|
+
additionalProperties: false
|
|
13671
|
+
required: [party]
|
|
13672
|
+
properties:
|
|
13673
|
+
party: { const: policy }
|
|
13674
|
+
approver: { type: string, description: 'The seat that answered, secret-redacted (e.g. `unattended_class_answer`). Absent = the channel reported no name.' }
|
|
13675
|
+
when: { type: integer, format: int64, description: 'Epoch ms, written at the settlement site.' }
|
|
13676
|
+
|
|
13446
13677
|
Settlement_approval_window_expired:
|
|
13447
13678
|
type: object
|
|
13448
13679
|
additionalProperties: false
|
|
@@ -13514,7 +13745,9 @@ components:
|
|
|
13514
13745
|
thing — a person''s "no" is the user''s direction, a policy''s is a capability of this run; distinct
|
|
13515
13746
|
from `no_approver` because a channel WAS wired and answered. This family carries NO `note` seat: the
|
|
13516
13747
|
note seat belongs to the two human words, whose ABSENCE is a control-flow fact) · `task_aborted`
|
|
13517
|
-
(the wait''s abort signal ended it).
|
|
13748
|
+
(the wait''s abort signal ended it). 🔴 server >= 7.113.0 (core 7.39.0): a policy refusal is spelled with `who.party: "policy"`
|
|
13749
|
+
and lives on `Settlement_policy`; `policy_refused` + `who.party: "none"` here is the 7.93.3 – 7.112.x shape, kept for the
|
|
13750
|
+
servers inside the support window.
|
|
13518
13751
|
required: [kind, who, when]
|
|
13519
13752
|
properties:
|
|
13520
13753
|
kind:
|
|
@@ -13598,9 +13831,13 @@ components:
|
|
|
13598
13831
|
unattended leg run under `UNATTENDED_PERMISSION_MODE=dontAsk`).
|
|
13599
13832
|
AskClass:
|
|
13600
13833
|
type: string
|
|
13601
|
-
enum: [content_question, hook, ancestor, unverifiable_delete, transcript_write, org_rule, governance_unavailable, rule_unreadable, ask_rule, denial_limit_fallback, operator_forced, write_protection_unresolved, probe, write_protection, tool_marks_mcp, tool_marks_a2a, policy_rra, artifact_shared_read, mode, ordinary]
|
|
13834
|
+
enum: [content_question, hook, ancestor, unverifiable_delete, transcript_write, org_rule, governance_unavailable, rule_unreadable, ask_rule, denial_limit_fallback, operator_forced, shell_floor, write_protection_unresolved, probe, write_protection, tool_marks_mcp, tool_marks_a2a, policy_rra, artifact_shared_read, mode, ordinary]
|
|
13602
13835
|
description: >
|
|
13603
|
-
core
|
|
13836
|
+
core `ASK_CLASSES` (twenty-one words as of core 7.39.0 — 7.34.0 minted twenty; `shell_floor` joined in 7.39.0 #1260 and rides
|
|
13837
|
+
server >= 7.113.0) — which CLASS an ask falls in (the columns of the mode × class arbitration table).
|
|
13838
|
+
`shell_floor` = the operator's `shellGate: "always"` floor on a shell-running seat (the question the `operator_always` mandate
|
|
13839
|
+
word discloses), a class of its own so a set that holds another forced question still holds it; like `operator_forced` it is
|
|
13840
|
+
bypass-IMMUNE (not releasable).
|
|
13604
13841
|
CLOSED on the gate record (screened with core `isAskClass`). `bypassPermissions` releases only the nine RELEASABLE classes
|
|
13605
13842
|
(`transcript_write` / `rule_unreadable` / `probe` / `write_protection` / `tool_marks_mcp` / `tool_marks_a2a` /
|
|
13606
13843
|
`artifact_shared_read` / `mode` / `ordinary`); every other class (deployment-authored `operator_forced`, ask / org rules, hook,
|
|
@@ -14137,7 +14374,14 @@ components:
|
|
|
14137
14374
|
required: [type, inputId]
|
|
14138
14375
|
properties:
|
|
14139
14376
|
type: { const: human_input }
|
|
14140
|
-
inputId:
|
|
14377
|
+
inputId:
|
|
14378
|
+
type: string
|
|
14379
|
+
description: >
|
|
14380
|
+
Stable per-input id (also the durable steering queue idempotency key). server >= 7.113.0 (wire VALUE change): for a LIVE steer
|
|
14381
|
+
it is the receipt's `messageId` verbatim — keyless steers included (<= 7.112.0: an engine-minted uuid whenever no
|
|
14382
|
+
`Idempotency-Key` was sent); with a key it is `idem-<sha256[:32]>` on both the live and the parked leg. 🚧 A keyless PARKED
|
|
14383
|
+
steer is the exception (contract §19): the server passes no `inputId` with the parked entry, so this id does not join the
|
|
14384
|
+
receipt's `messageId`.
|
|
14141
14385
|
sessionSeq: { type: integer, description: 'Leg-scoped monotone sequence of human inputs.' }
|
|
14142
14386
|
carrier: { type: string, description: 'Which carrier delivered it (steer / objective / a source word). Open on read.' }
|
|
14143
14387
|
source: { type: string, description: 'objective | steer | next_turn | wake | external | system. Open on read.' }
|
|
@@ -18074,7 +18318,18 @@ components:
|
|
|
18074
18318
|
taskId: { type: string }
|
|
18075
18319
|
status: { type: string, description: 'The run status the server saw at delivery time (running | suspended | a terminal status).' }
|
|
18076
18320
|
delivery: { type: string, enum: [applied, queued, parked_for_wake] }
|
|
18077
|
-
messageId:
|
|
18321
|
+
messageId:
|
|
18322
|
+
type: string
|
|
18323
|
+
description: >
|
|
18324
|
+
Server-minted, stable across all three legs (`idem-<sha256[:32]>` when an `Idempotency-Key` was sent, else a fresh uuidv7).
|
|
18325
|
+
server >= 7.113.0 (wire VALUE change, no new key): on the LIVE leg (`delivery: "applied"`) the server ALWAYS hands this
|
|
18326
|
+
same value to the engine as the steer's `inputId` — keyless steers included (<= 7.112.0 passed it only when a key was sent,
|
|
18327
|
+
so a keyless live steer's `human_input.inputId` was an engine-minted uuid that never joined this receipt). So the
|
|
18328
|
+
`human_input` frame of that steer (`delivery: "applied"` / `"queued"`) carries `inputId === messageId`, and the user-input
|
|
18329
|
+
acceptance ledger (`userInputUndrained[].messageId`) is keyed by the same value. The PARKED legs: with a key,
|
|
18330
|
+
`inputId === messageId` as before; 🚧 a KEYLESS parked steer (`delivery: "queued"` / `"parked_for_wake"`) is the documented
|
|
18331
|
+
exception (contract §19) — the server passes no `inputId` with the parked queue entry, so this `messageId` is never that entry's
|
|
18332
|
+
`inputId` and the later `human_input` frame does NOT join it.
|
|
18078
18333
|
priority: { $ref: '#/components/schemas/SteerPriority' }
|
|
18079
18334
|
note: { type: string, description: 'Human-readable note on the two parked legs; absent on `applied`.' }
|
|
18080
18335
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "16.0.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",
|