@sema-agent/sdk 20.0.3 → 21.1.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 +86 -1
- package/dist/errors.d.ts +7 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +7 -1
- package/dist/errors.js.map +1 -1
- package/dist/events.d.ts +61 -3
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/idempotency.d.ts +4 -0
- package/dist/idempotency.d.ts.map +1 -1
- package/dist/idempotency.js +4 -0
- package/dist/idempotency.js.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/resources/approvals.d.ts +23 -3
- package/dist/resources/approvals.d.ts.map +1 -1
- package/dist/resources/approvals.js +15 -1
- package/dist/resources/approvals.js.map +1 -1
- package/dist/resources/assistant.d.ts +1 -1
- package/dist/resources/assistant.js +1 -1
- package/dist/resources/models.d.ts +3 -1
- package/dist/resources/models.d.ts.map +1 -1
- package/dist/resources/models.js +3 -1
- package/dist/resources/models.js.map +1 -1
- package/dist/resources/session-sync.d.ts +1 -1
- package/dist/resources/tasks.d.ts +7 -1
- package/dist/resources/tasks.d.ts.map +1 -1
- package/dist/resources/tasks.js +7 -1
- package/dist/resources/tasks.js.map +1 -1
- package/dist/resources/tool-approvals.d.ts +15 -1
- package/dist/resources/tool-approvals.d.ts.map +1 -1
- package/dist/resources/tool-approvals.js +8 -0
- package/dist/resources/tool-approvals.js.map +1 -1
- package/dist/types.d.ts +184 -65
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +5 -8
- package/dist/types.js.map +1 -1
- package/openapi.yaml +280 -57
- package/package.json +1 -1
package/openapi.yaml
CHANGED
|
@@ -423,7 +423,7 @@ paths:
|
|
|
423
423
|
prepare-time refusal code that HAS a status in the server's per-code triage table (`resume_at.*` — `resume_at.not_found` is 404, the rest 422 —, governance codes,
|
|
424
424
|
`rewind.store_unconfigured` / `rewind.capture_disabled` / `rewind.child_scope_unsupported` / `rewind_snapshot.unresolvable`, the
|
|
425
425
|
registered `config.*` codes incl. the three roster-bound ones and — server >= 7.116.0 — `config.invalid_checkpoint_store` (400) and
|
|
426
|
-
`config.user_invoked_skill_unknown` (400: top-level `userInvokedSkills` named a skill this run does not carry) and — server >= 7.117.0 — `config.image_invalid` (400: an inline image failed the engine's byte admission; `error` starts with `TaskSpec.images: `), `corrupt_session`; codes outside the table, e.g. `rewind.invalid_spec`, stay
|
|
426
|
+
`config.user_invoked_skill_unknown` (400: top-level `userInvokedSkills` named a skill this run does not carry) and — server >= 7.117.0 — `config.image_invalid` (400: an inline image failed the engine's byte admission; `error` starts with `TaskSpec.images: `) and — server >= 7.126.0 — `config.tool_face_control` (400: a name in `allowTools` / `excludeTools` that no tool of this run answers to, `allowTools: ["mcp__*"]`, `excludeTools: ["*"]`, or an `excludeTools` entry that reaches a protocol tool this leg depends on; the engine rejects before the run starts, never silently ignoring the name; `error` is the engine's sentence naming the entry, its list and why), `corrupt_session`; codes outside the table, e.g. `rewind.invalid_spec`, stay
|
|
427
427
|
200 with a failed body) answers its 4xx / 5xx ERROR BODY only when the whole submission did ZERO WORK (cumulative
|
|
428
428
|
`stats.turns === 0` AND `stats.tokens === 0` — the common case: nothing billed, not idempotency-cached). When a
|
|
429
429
|
`verify` / `cascade` run's earlier tier already ran turns and only the last tier is refused, the SAME code arrives
|
|
@@ -435,6 +435,8 @@ paths:
|
|
|
435
435
|
in `result` (a nested `TaskResult`), and `wiringManifest` / `notice` are absent. A same-key duplicate that is still IN FLIGHT in the same process is merged
|
|
436
436
|
instead and gets the first answer's bytes (no `replay` key). Only a submit that builds a row can be replayed this way (a run store AND a `sessionId`);
|
|
437
437
|
otherwise a settled key re-runs. A key whose row the caller cannot read answers 409 `conflict.run_exists`.
|
|
438
|
+
🔴 SAME KEY = SAME BODY (server >= 7.126.0, contract §0.7): resubmitting the same `Idempotency-Key` with a DIFFERENT request body is 409
|
|
439
|
+
`conflict.idempotency_payload_mismatch` — not replayed, not created, the row untouched. To retry, resend the SAME body; for a different request use a NEW key.
|
|
438
440
|
parameters:
|
|
439
441
|
- $ref: '#/components/parameters/IdempotencyKey'
|
|
440
442
|
requestBody:
|
|
@@ -483,6 +485,12 @@ paths:
|
|
|
483
485
|
or at a row that is not the one this submit's `taskId` names. The sentence is `a run already exists for this submission's taskId or Idempotency-Key`
|
|
484
486
|
(the code is unchanged; only the sentence moved); nothing about the row is echoed (no cross-tenant oracle). Submit under a NEW key. On
|
|
485
487
|
`POST /v1/tasks/stream`, once the stream is open the same refusal arrives as the `done` frame's `{status:"failed", errorCode, errorMessage}`.
|
|
488
|
+
`conflict.idempotency_payload_mismatch` (server >= 7.126.0, contract §0.7 "same request = same body"): the submit's `Idempotency-Key` is already bound to a run row you CAN read,
|
|
489
|
+
and the body of the request that bound it differs from this one (normalization: JSON keys recursively sorted, `taskId` removed, headers never count; a value, a nested value, an
|
|
490
|
+
extra key or a reordered array is a different request). Not replayed, not created, the row untouched; the body is `{ error, errorCode }` and echoes neither the key nor the row.
|
|
491
|
+
Resend the SAME body to retry, or use a NEW key for a different request. Only the key's own binding is compared (a hit by `taskId` alone, or a row created without a key, is not
|
|
492
|
+
body-compared). A2A `message/send` never meets it. On `POST /v1/tasks/stream` it is a clean JSON 409 when found at the door; once the stream is open it arrives as the `done` frame's
|
|
493
|
+
`{status:"failed", errorCode:"conflict.idempotency_payload_mismatch", errorMessage}`.
|
|
486
494
|
content:
|
|
487
495
|
application/json:
|
|
488
496
|
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
@@ -1917,7 +1925,7 @@ paths:
|
|
|
1917
1925
|
# (declared 2026-07-31) errorCode "request.id_invalid" — the path sessionId must decode to a
|
|
1918
1926
|
# canonical uuid of ANY version (`routes/sessions.ts`; server >= 7.125.0 — the ONE shape gate shared with sync / fork / policy;
|
|
1919
1927
|
# <= 7.124.x accepted only uuidv7 here); a malformed id never reaches the store. Branch on the code, never the sentence
|
|
1920
|
-
# (the sentence changed with the gate
|
|
1928
|
+
# (the sentence changed with the gate, and again when the submit door joined it).
|
|
1921
1929
|
$ref: '#/components/responses/BadRequest'
|
|
1922
1930
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
1923
1931
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
@@ -4278,9 +4286,10 @@ paths:
|
|
|
4278
4286
|
description: >
|
|
4279
4287
|
READ-ONLY catalog of `@mention`-pickable models. The user selects a model PER-TASK by typing `@<name>` in
|
|
4280
4288
|
the objective body (the service allowlist-parses it; the client never re-decides). Envelope
|
|
4281
|
-
`{ models, default, defaultModel, droppedEntries? }` — see `ModelsResponse` (`default` = the deployment default model id,
|
|
4289
|
+
`{ models, default, defaultModel, droppedEntries?, candidateRejected? }` — see `ModelsResponse` (`default` = the deployment default model id,
|
|
4282
4290
|
display-only — the internal `default` alias is hidden; `defaultModel` = the same default as `{id, name?}` in one piece;
|
|
4283
|
-
`droppedEntries` = server >= 7.123.0, the catalog entries the read leg dropped, in the same generation as `models
|
|
4291
|
+
`droppedEntries` = server >= 7.123.0, the catalog entries the read leg dropped, in the same generation as `models`;
|
|
4292
|
+
`candidateRejected` = server >= 7.126.0, present-iff the configuration in force is the fallback one because the candidate judge rejected the latest candidate).
|
|
4284
4293
|
🔴 NON-SECRET: only name/id/provider/reasoning/vision + the E4/E7 capability fields — NEVER baseUrl/apiKey/
|
|
4285
4294
|
headers (the service strips them). Fail-safe: on error, render an empty picker (never block).
|
|
4286
4295
|
responses:
|
|
@@ -6933,6 +6942,8 @@ components:
|
|
|
6933
6942
|
server >= 7.125.0 also: `conflict.run_exists` — on a submit (`POST /v1/runs`, `/v1/tasks`, `/v1/tasks/stream`), the `Idempotency-Key` /
|
|
6934
6943
|
`body.taskId` points at a run the caller cannot read, or the two keys of one submit point at different rows. The sentence is
|
|
6935
6944
|
`a run already exists for this submission's taskId or Idempotency-Key` (code unchanged, sentence new; nothing echoed). Submit again under a new key.
|
|
6945
|
+
server >= 7.126.0 also: `conflict.idempotency_payload_mismatch` — the same `Idempotency-Key` carried with a DIFFERENT request body than the one that bound it (contract §0.7:
|
|
6946
|
+
not replayed, not created, the row untouched; resend the SAME body to retry, a NEW key for a different request).
|
|
6936
6947
|
content:
|
|
6937
6948
|
application/json:
|
|
6938
6949
|
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
@@ -6996,13 +7007,12 @@ components:
|
|
|
6996
7007
|
description: >
|
|
6997
7008
|
Primary routing axis (one image serves many). Selects model/tools/skills/prompt. OPEN: a stock server's builtin
|
|
6998
7009
|
table is `code` (factory default) / `default` / `code-review` / `scan` (SDK `KNOWN_SCENARIOS`, checked against the
|
|
6999
|
-
published server's `buildScenarios()` table
|
|
7000
|
-
|
|
7001
|
-
register more through the registry. A name
|
|
7010
|
+
published server's `buildScenarios()` table; servers <= 7.125.x also listed `discuss`, retired with the whole team-orchestration surface at
|
|
7011
|
+
7.126.0, no alias) — and a deployment may register more through the registry. A name
|
|
7002
7012
|
the caller SENDS that the deployment does not serve is a loud 400 `scenario_unknown` (server >= 5.1.0, the body
|
|
7003
7013
|
carries the live vocabulary) — the silent fold to `default` exists only on the server-side ASSIGNMENT chain.
|
|
7004
7014
|
Retired, no alias: `oa` (5.0.0), `autonomous` ([2400] CAPS-OPS-11), `team` (renamed `discuss`, server #273 / C-R14;
|
|
7005
|
-
alias withdrawn at #342
|
|
7015
|
+
alias withdrawn at #342).
|
|
7006
7016
|
examples: ['code', 'default', 'code-review', 'scan']
|
|
7007
7017
|
|
|
7008
7018
|
ScenarioDetail:
|
|
@@ -7130,8 +7140,8 @@ components:
|
|
|
7130
7140
|
name: { type: string, description: 'the `subagent_type` the model passes to Task. Non-empty, ≤64 chars, UNIQUE per request.' }
|
|
7131
7141
|
whenToUse: { type: string, description: 'when the model should delegate to this agent (shown in the Task tool''s agent list). ≤4096 chars.' }
|
|
7132
7142
|
whenToUseLean: { type: string, description: 'compact variant of `whenToUse` for lean tool listings. ≤4096 chars.' }
|
|
7133
|
-
allowTools: { type: array, items: { type: string }, description: 'allowlist of tool names. Omit ⇒ inherit ALL tools.' }
|
|
7134
|
-
denyTools: { type: array, items: { type: string }, description: 'denylist (SUBTRACTIVE — applied after `allowTools`).' }
|
|
7143
|
+
allowTools: { type: array, items: { type: string }, description: 'allowlist of tool names. Omit ⇒ inherit ALL tools. server >= 7.126.0: the names are judged by the ENGINE, one selector shared with the root run''s `allowTools` / `excludeTools`; a name no tool answers to => the run is rejected with the terminal code `config.agent.unknown_tool` (not an HTTP code).' }
|
|
7144
|
+
denyTools: { type: array, items: { type: string }, description: 'denylist (SUBTRACTIVE — applied after `allowTools`). server >= 7.126.0: same engine-judged selector as `allowTools`; `Tool(content)` => the whole tool.' }
|
|
7135
7145
|
skills:
|
|
7136
7146
|
type: array
|
|
7137
7147
|
description: 'skills preloaded into the agent.'
|
|
@@ -7174,10 +7184,9 @@ components:
|
|
|
7174
7184
|
TaskRequest:
|
|
7175
7185
|
type: object
|
|
7176
7186
|
description: >
|
|
7177
|
-
Common request body. `[additionalProperties]` mirrors the service passthrough — scenario-specific fields
|
|
7178
|
-
(
|
|
7179
|
-
|
|
7180
|
-
on two seams outside the scenario builder, so they are declared properties below.
|
|
7187
|
+
Common request body. `[additionalProperties]` mirrors the service passthrough — scenario-specific fields (today only `repo`) ride here.
|
|
7188
|
+
server 7.126.0 (hard BREAKING, no alias) took the declared keys `council` / `debate` and the scenario passthrough keys `businessContext` / `lenses` / `rounds` / `team` out of the accepted set with the team-orchestration
|
|
7189
|
+
surface: sending one is 400 `request.body_shape` listing it in `unknownKeys`. The open `additionalProperties` here does NOT catch them — the server's 400 is the notice.
|
|
7181
7190
|
required: [objective]
|
|
7182
7191
|
additionalProperties: true
|
|
7183
7192
|
properties:
|
|
@@ -7200,7 +7209,12 @@ components:
|
|
|
7200
7209
|
scenario: { $ref: '#/components/schemas/Scenario' }
|
|
7201
7210
|
sessionId:
|
|
7202
7211
|
type: string
|
|
7203
|
-
description:
|
|
7212
|
+
description: >
|
|
7213
|
+
Continue a conversation (same sessionId across turns). Omit on first turn → service mints one.
|
|
7214
|
+
server >= 7.126.0 (contract section 0.8): a caller-supplied session id has ONE shape law on every door — a canonical uuid of ANY version (lowercase 8-4-4-4-12 hex, version nibble 1-8; a client-preset v4 and the
|
|
7215
|
+
server-minted v7 both pass), the same judge `fork` / `delete` / `policy` / 2c sync use. Anything else is 400 `request.id_invalid` (branch on the CODE, never the sentence). A self-chosen name is not a
|
|
7216
|
+
session id any more (keep your own name-to-uuid mapping); the old "at most 64 characters" cap and its `request.field_invalid` refusal are gone; the empty string is NO LONGER "absent" (it is a non-uuid => 400;
|
|
7217
|
+
omit the key for a new session). Shape-only: it does not check that the session exists. A2A `contextId` rides this key and is judged by the same rule.
|
|
7204
7218
|
requireExistingSession:
|
|
7205
7219
|
type: boolean
|
|
7206
7220
|
description: >
|
|
@@ -7306,23 +7320,6 @@ components:
|
|
|
7306
7320
|
the 32-entry cap the surplus entries are DROPPED and named too — same disposition as a malformed
|
|
7307
7321
|
entry, not a 400.
|
|
7308
7322
|
items: { $ref: '#/components/schemas/A2aServerSpec' }
|
|
7309
|
-
council:
|
|
7310
|
-
type: boolean
|
|
7311
|
-
description: >
|
|
7312
|
-
The `code-review` scenario's EXPENSIVE tier — fan the review out to N parallel lenses plus an
|
|
7313
|
-
arbiter (`run_council`) instead of the lead reviewing in-line. Read on TWO seams and both matter:
|
|
7314
|
-
the scenario builder mounts the council tool, and spec resolution treats it as an EXPLICIT team
|
|
7315
|
-
declaration (widening the task's wall-clock tenancy budget and suppressing the value router's
|
|
7316
|
-
auto-escalation). Only a literal `true` counts on both seams. On other scenarios the first seam is
|
|
7317
|
-
inert while the second still applies.
|
|
7318
|
-
debate:
|
|
7319
|
-
type: boolean
|
|
7320
|
-
description: >
|
|
7321
|
-
Run the L2 peer-debate rounds on top of `council`. 🔴 The two seams are ASYMMETRIC — this is not a
|
|
7322
|
-
standalone switch: the scenario builder reads it only INSIDE the `council === true` branch (sending
|
|
7323
|
-
`debate:true` alone produces no debate rounds), while the explicit-team predicate is
|
|
7324
|
-
`council || debate` (sending it alone still widens the budget and suppresses auto-escalation).
|
|
7325
|
-
Literal `true` only, same as `council`.
|
|
7326
7323
|
resumeAt:
|
|
7327
7324
|
type: string
|
|
7328
7325
|
description: >
|
|
@@ -7801,7 +7798,23 @@ components:
|
|
|
7801
7798
|
excludeTools:
|
|
7802
7799
|
type: array
|
|
7803
7800
|
items: { type: string }
|
|
7804
|
-
description:
|
|
7801
|
+
description: >
|
|
7802
|
+
Tool names to withhold from this task's roster. server >= 7.126.0 (engine 7.49.0, contract G.9e): read with the SAME grammar as `allowTools`; a name that
|
|
7803
|
+
NO tool answers to rejects the run before it starts with `config.tool_face_control` (sync leg 400, no token burned; streamed / background legs: a `failed` terminal with
|
|
7804
|
+
the same code) instead of being silently ignored, and `"*"` is rejected on this list too (unmount-everything is only `excludeAllTools`).
|
|
7805
|
+
allowTools:
|
|
7806
|
+
type: array
|
|
7807
|
+
items: { type: string }
|
|
7808
|
+
description: >
|
|
7809
|
+
(server >= 7.126.0, engine 7.49.0 #1623, contract G.9e) The run's AVAILABILITY SELECTOR, passed to the engine's `TaskSpec.allowTools` verbatim (the server reads nothing:
|
|
7810
|
+
no complement, no entry filtering, `[]` is not folded to absent, not mixed with `settings.permissions.allow`). Available tools = everything this run mounts (caller tools,
|
|
7811
|
+
hands, the engine's own tools, MCP / A2A, scenario and leg tools) ∩ `allowTools` − `excludeTools` (deny wins), computed by the engine once before the run starts.
|
|
7812
|
+
`["*"]` = no list at this layer (same as absent); `[]` = give nothing; an entry is a wire name or alias, `Tool(content)` (the whole tool), `mcp__srv` / `mcp__srv__*` /
|
|
7813
|
+
a tool-segment wildcard (`mcp__*` is rejected on this list). A leg's protocol tools (a delegated child's `ReportBlocked`, …) need no mention. A name that NO tool answers to
|
|
7814
|
+
=> `config.tool_face_control` (sync leg 400, no token burned; streamed / background legs: a `failed` terminal with the same code). Wrong shape (not a string array) =>
|
|
7815
|
+
400 `request.field_invalid`, the same gate as `excludeTools` / `deferTools`. An engine older than 7.49.0 rejects loudly (400 `request.field_invalid` naming `allowTools`) —
|
|
7816
|
+
never silently dropped (dropping a narrowing key widens). No capability bit: probe by key closure (<= 7.125.x answers `400 request.body_shape` with the name in
|
|
7817
|
+
`unknownKeys`). The A2A inbound face (`message/send`) does not carry this key.
|
|
7805
7818
|
excludeAllTools:
|
|
7806
7819
|
type: boolean
|
|
7807
7820
|
enum: [true]
|
|
@@ -8040,6 +8053,85 @@ components:
|
|
|
8040
8053
|
🔴 On the wire it carries NO `token` — the same withholding rule as the top-level `paused` arm
|
|
8041
8054
|
(see `PausedCause`); `gate` / `checkpointId` are present as usual.
|
|
8042
8055
|
Absent on every failure the engine itself assembles.
|
|
8056
|
+
detail:
|
|
8057
|
+
allOf: [{ $ref: '#/components/schemas/TerminalFailureDetail' }]
|
|
8058
|
+
description: >
|
|
8059
|
+
The machine-readable account of the failure beside `code` (server >= 7.110.0 carried the `provider_rejected` arm; server >= 7.126.0 / core 7.49.0 it is a CLOSED union branching on `kind`,
|
|
8060
|
+
three arms — see `TerminalFailureDetail`). Branch on `detail.kind`, never on `message`; new members join with a core minor, so a branch MUST keep a default arm. Present only when the arm that
|
|
8061
|
+
named this result has such a fact to project; absent otherwise (absence is not an "older version" signal). The same object crosses three faces: the synchronous 200 body, the stream's `done.result`,
|
|
8062
|
+
`GET /v1/runs/{taskId}` -> `result`.
|
|
8063
|
+
|
|
8064
|
+
TerminalFailureDetail:
|
|
8065
|
+
description: >
|
|
8066
|
+
`TerminalCause_failed.detail` (contract section 5.0a; core `TerminalFailureDetail`) — a CLOSED union branching on `kind`, three arms as of server 7.126.0. An UNKNOWN `kind` (a newer engine) is passed through
|
|
8067
|
+
by the server with every string leaf redacted, never dropped or reshaped: a consumer treats it as the default arm.
|
|
8068
|
+
oneOf:
|
|
8069
|
+
- { $ref: '#/components/schemas/TerminalProviderRejectedDetail' }
|
|
8070
|
+
- { $ref: '#/components/schemas/TerminalCodedDetail' }
|
|
8071
|
+
- { $ref: '#/components/schemas/TerminalModelOutputInvalidDetail' }
|
|
8072
|
+
|
|
8073
|
+
TerminalProviderRejectedDetail:
|
|
8074
|
+
type: object
|
|
8075
|
+
additionalProperties: false
|
|
8076
|
+
required: [kind, status]
|
|
8077
|
+
description: >
|
|
8078
|
+
The model provider REFUSED the request with a 4xx and that refusal is what named this result. 5xx, connect / stream failures, an in-band error inside a 200, a lock conflict, a request-build guard and every non-provider
|
|
8079
|
+
failure carry no detail. 401 / 403 / 429 carry it too: to tell "the user can edit and resend", read `status` (or `code`), not whether `detail` is present.
|
|
8080
|
+
properties:
|
|
8081
|
+
kind: { const: provider_rejected }
|
|
8082
|
+
status: { type: integer, minimum: 400, maximum: 499, description: 'The refusal''s HTTP status (same value as `apiFailure.status`).' }
|
|
8083
|
+
code: { type: string, description: 'The provider''s own error word (`error.code`, else `error.type`); absent when the provider gave none or it is out of shape (1–128 visible ASCII).' }
|
|
8084
|
+
providerCondition:
|
|
8085
|
+
type: string
|
|
8086
|
+
description: 'server >= 7.126.0 (core 7.49.0 #1454): what the refusal says about the account — the engine''s closed word (`quota_exhausted | throttled | overloaded | unknown | stop_other`), passed through verbatim; read as an OPEN set. The terminal reading of the verdict the call''s retry frames carried (`status.providerCondition`).'
|
|
8087
|
+
providerConditionSource: { type: string, description: 'server >= 7.126.0: the evidence `providerCondition` rests on (`unified_header | provider_code | status`); present exactly when it is; read as an OPEN set.' }
|
|
8088
|
+
providerResetAtMs: { type: number, description: 'server >= 7.126.0: epoch milliseconds when the window resets, carried beside a `quota_exhausted` condition.' }
|
|
8089
|
+
route:
|
|
8090
|
+
allOf: [{ $ref: '#/components/schemas/TerminalRequestRoute' }]
|
|
8091
|
+
description: 'server >= 7.126.0: the route the refused request took, in KNOB words only (never a key value or a URL).'
|
|
8092
|
+
|
|
8093
|
+
TerminalRequestRoute:
|
|
8094
|
+
type: object
|
|
8095
|
+
additionalProperties: false
|
|
8096
|
+
required: [credentialSource, root]
|
|
8097
|
+
description: 'server >= 7.126.0 — `TerminalProviderRejectedDetail.route` (core `RequestRoute`): the route a refused request took, in KNOB words only (never a key value or a URL). All four words are read as OPEN sets.'
|
|
8098
|
+
properties:
|
|
8099
|
+
credentialSource: { type: string, description: 'Where the credential came from: `per-model | deployment-config | absent`.' }
|
|
8100
|
+
carrier: { type: string, description: 'How it rode: `apiKey | header`; absent exactly when `credentialSource` is `absent`.' }
|
|
8101
|
+
carrierBag: { type: string, description: 'Which header bag the auth header came from: `options | model | config`.' }
|
|
8102
|
+
root: { type: string, description: 'Which knob named the request''s root: `model | deployment | lane-default`.' }
|
|
8103
|
+
|
|
8104
|
+
TerminalCodedDetail:
|
|
8105
|
+
type: object
|
|
8106
|
+
additionalProperties: false
|
|
8107
|
+
required: [kind, detail]
|
|
8108
|
+
description: >
|
|
8109
|
+
server >= 7.126.0 — the run threw a coded error (this result''s `terminal.code`) whose throw site also stated a structured `detail` (for example a checkpoint error''s `{ reason }`). Present only when that error carried a
|
|
8110
|
+
plain-object `detail` with at least one projectable member.
|
|
8111
|
+
properties:
|
|
8112
|
+
kind: { const: coded }
|
|
8113
|
+
detail:
|
|
8114
|
+
type: object
|
|
8115
|
+
description: 'The thrown error''s `detail`: a JSON-plain snapshot (strings, finite numbers, booleans, null, arrays / plain objects of those; bounded). A member under a credential name stands as `"[redacted]"`; every string leaf passes the error-sentence redaction (credential shapes masked, paths kept).'
|
|
8116
|
+
additionalProperties: true
|
|
8117
|
+
|
|
8118
|
+
TerminalModelOutputInvalidDetail:
|
|
8119
|
+
type: object
|
|
8120
|
+
additionalProperties: false
|
|
8121
|
+
required: [kind, cause]
|
|
8122
|
+
description: 'server >= 7.126.0 — the model''s final turn failed because its tool calls could not be executed. Same words as the `task.tool_turn_incomplete` notice.'
|
|
8123
|
+
properties:
|
|
8124
|
+
kind: { const: model_output_invalid }
|
|
8125
|
+
cause: { type: string, enum: [truncated, unnamed], description: 'Why the calls were dropped: `truncated` = the arguments were cut before they parsed; `unnamed` = a call with no tool name.' }
|
|
8126
|
+
outputLimit:
|
|
8127
|
+
type: object
|
|
8128
|
+
additionalProperties: false
|
|
8129
|
+
required: [capStop]
|
|
8130
|
+
description: 'Only beside `truncated`: the output-cap facts the stream reported.'
|
|
8131
|
+
properties:
|
|
8132
|
+
capStop: { type: boolean }
|
|
8133
|
+
outputTokens: { type: number }
|
|
8134
|
+
capTokens: { type: number }
|
|
8043
8135
|
|
|
8044
8136
|
TerminalCause_blocked:
|
|
8045
8137
|
type: object
|
|
@@ -8405,14 +8497,15 @@ components:
|
|
|
8405
8497
|
The `done.result` of a submit REFUSED after the SSE stream was already open (`POST /v1/tasks/stream`): the status line is gone, so the refusal travels as the
|
|
8406
8498
|
stream's terminal frame in the triple `{status:"failed", errorCode, errorMessage}` — the same code and sentence the JSON refusal body would have carried
|
|
8407
8499
|
(server `src/http/routes/tasks.ts`). Two producers: (1) server >= 7.125.0 — the submit's key (or `body.taskId`) turned out, only at row-creation time, to point at a run row
|
|
8408
|
-
the caller cannot read or that is not the one this submit names: `errorCode: "conflict.run_exists"` (contract §0.7; the frame carries `replay: true`);
|
|
8500
|
+
the caller cannot read or that is not the one this submit names: `errorCode: "conflict.run_exists"` (contract §0.7; the frame carries `replay: true`); server >= 7.126.0 adds
|
|
8501
|
+
`errorCode: "conflict.idempotency_payload_mismatch"` (the same key, found at row-creation time bound by a request with a different body; same projection); (2) a device-placement
|
|
8409
8502
|
refusal (the placement error body's code and sentence). It is NOT an engine result and NOT `ActiveRunConflictDoneResult` (that one is `conflict.session_active_run` and requires
|
|
8410
8503
|
`activeTaskId`). Branch on `errorCode`; the sentence is for people.
|
|
8411
8504
|
additionalProperties: false
|
|
8412
8505
|
required: [status, errorCode, errorMessage]
|
|
8413
8506
|
properties:
|
|
8414
8507
|
status: { const: failed }
|
|
8415
|
-
errorCode: { type: string, description: 'Open string: `conflict.run_exists` (server >= 7.125.0) or the device-placement refusal code.' }
|
|
8508
|
+
errorCode: { type: string, description: 'Open string: `conflict.run_exists` (server >= 7.125.0), `conflict.idempotency_payload_mismatch` (server >= 7.126.0) or the device-placement refusal code.' }
|
|
8416
8509
|
errorMessage: { type: string, description: 'The refusal sentence (display only — never match on it).' }
|
|
8417
8510
|
|
|
8418
8511
|
RunReceipt:
|
|
@@ -8446,22 +8539,48 @@ components:
|
|
|
8446
8539
|
WorkspaceSyncCapability:
|
|
8447
8540
|
type: object
|
|
8448
8541
|
description: >
|
|
8449
|
-
server >= 7.125.0 (contract appendix B.1 / B.1a) — the `GET /v1/capabilities` `workspaceSync` segment
|
|
8450
|
-
`
|
|
8542
|
+
server >= 7.125.0 (contract appendix B.1 / B.1a) — the `GET /v1/capabilities` `workspaceSync` segment, key-for-key the server's composite member table
|
|
8543
|
+
`workspaceSync: [persist, keep, timeoutMs, cache]`. server >= 7.126.0: the members are PRESENT INDEPENDENTLY, each by its own facility — `persist` / `keep` / `timeoutMs` are
|
|
8544
|
+
present-iff the SNAPSHOT STORE (the k8s lane AND the three `MINIO_*` keys; in 7.125.0 `persist` / `keep` were always-present members of the object and `timeoutMs` did not exist, so a 7.125.x body is `{ persist, keep }` — which this schema still accepts: only `persist` <-> `keep` are bound to each other, and `timeoutMs`, when present, needs both); `cache` is present-iff the BUILD-CACHE VOLUME is on
|
|
8545
|
+
(the k8s lane AND `WORKSPACE_CACHE=volume`; independent of the snapshot store). The object itself is present-iff ANY member is present (see `Capabilities.workspaceSync`), so a deployment with the cache
|
|
8546
|
+
volume on but no snapshot store answers an object with only `cache`: "the object is present" no longer implies `persist` is present. Read cross-run retention as `persist === "space"`.
|
|
8451
8547
|
additionalProperties: false
|
|
8452
|
-
|
|
8548
|
+
minProperties: 1
|
|
8549
|
+
dependentRequired:
|
|
8550
|
+
persist: [keep]
|
|
8551
|
+
keep: [persist]
|
|
8552
|
+
timeoutMs: [persist, keep]
|
|
8453
8553
|
properties:
|
|
8454
8554
|
persist:
|
|
8455
8555
|
type: string
|
|
8456
8556
|
enum: [space, off]
|
|
8457
8557
|
description: >
|
|
8458
|
-
The operator knob `WORKSPACE_PERSIST
|
|
8459
|
-
store IS wired but
|
|
8558
|
+
The operator knob `WORKSPACE_PERSIST`, a TWO-WORD closed set, DEFAULT `space` (server >= 7.126.0; the 7.125.0 default was `off`). `space` = the k8s `/workspace` persists across runs per session occupant. `off` = the snapshot
|
|
8559
|
+
store IS wired but the operator switched persistence off: a fresh workspace every run — NOT the same as the member being absent (absent = no snapshot store on this deployment). Present-iff the snapshot store; moves with `keep`.
|
|
8460
8560
|
keep:
|
|
8461
8561
|
type: integer
|
|
8462
8562
|
minimum: 1
|
|
8463
8563
|
maximum: 50
|
|
8464
|
-
description: 'Snapshots kept per space (the session occupant) (`WORKSPACE_SNAPSHOT_KEEP`, an integer in [1, 50], default 3); older ones are deleted after each successful save.'
|
|
8564
|
+
description: 'Snapshots kept per space (the session occupant) (`WORKSPACE_SNAPSHOT_KEEP`, an integer in [1, 50], default 3); older ones are deleted after each successful save. Present-iff the snapshot store; moves with `persist`.'
|
|
8565
|
+
timeoutMs:
|
|
8566
|
+
type: integer
|
|
8567
|
+
minimum: 30000
|
|
8568
|
+
maximum: 3600000
|
|
8569
|
+
description: 'server >= 7.126.0 — the snapshot time bound (`WORKSPACE_SNAPSHOT_TIMEOUT_MS`, milliseconds, an integer in [30000, 3600000], default 300000): the wall-clock bound of the end-of-run upload and of the restore when the sandbox connects, and the longest the next run waits for the previous run to finish saving. A shell tells the user the "snapshot bound" from it. Present-iff the snapshot store (and, when present, `persist` / `keep` are present too); absent on server 7.125.x.'
|
|
8570
|
+
cache:
|
|
8571
|
+
allOf: [{ $ref: '#/components/schemas/WorkspaceCacheCapability' }]
|
|
8572
|
+
description: >
|
|
8573
|
+
server >= 7.126.0 — the per-space BUILD-CACHE VOLUME (`WORKSPACE_CACHE=volume`): one cache volume per space (session occupant) mounted at `mount` OUTSIDE the workspace (never in the snapshot, disposable), the tool caches
|
|
8574
|
+
(Gradle / Maven / npm / pip / uv / Go; Rust is not covered) are pointed there through pod env. A run that cannot get the volume still starts without it (slower builds, no failure); delegated children / background agents
|
|
8575
|
+
do not mount it. Present-iff the cache volume is on, independent of the snapshot store.
|
|
8576
|
+
WorkspaceCacheCapability:
|
|
8577
|
+
type: object
|
|
8578
|
+
additionalProperties: false
|
|
8579
|
+
required: [mount, size]
|
|
8580
|
+
description: 'server >= 7.126.0 — `Capabilities.workspaceSync.cache`: the per-space build-cache volume (`WORKSPACE_CACHE=volume`), key-for-key the server''s `WorkspaceCacheCapability`.'
|
|
8581
|
+
properties:
|
|
8582
|
+
mount: { type: string, description: 'The absolute path of the cache volume inside the pod (default `/cache`, outside the workspace mount).' }
|
|
8583
|
+
size: { type: string, description: 'The capacity requested per volume, a k8s quantity string (default `20Gi`).' }
|
|
8465
8584
|
StoreCapability:
|
|
8466
8585
|
type: object
|
|
8467
8586
|
description: >
|
|
@@ -10312,13 +10431,14 @@ components:
|
|
|
10312
10431
|
server >= 7.125.0 (contract appendix B.1 / B.1a) — WORKSPACE KEPT ACROSS RUNS: the k8s lane's `/workspace` is stored in object storage per session OCCUPANT (the session incarnation: delete the session and re-register the same id = a NEW space, starting from an empty directory). Each run's end
|
|
10313
10432
|
snapshots the workspace into `<prefix>/<incarnation>/space/` (a sub-prefix this lane owns; the park-suspend snapshots live outside it and are never pruned), moves the `space/latest` pointer and keeps only
|
|
10314
10433
|
the newest `keep`; the next run's start (when it connects the sandbox) restores from `latest`. A replica that cannot read the session occupant neither restores nor saves for that run (an operator line) and does NOT fall back to the session id.
|
|
10315
|
-
A shell / center renders "work files kept across turns" only when `persist` is `"space"` (the default is `off
|
|
10434
|
+
A shell / center renders "work files kept across turns" only when `persist` is `"space"` (the default is `space` since server 7.126.0; it was `off` in 7.125.0) — read `persist`, not "the object is present".
|
|
10316
10435
|
🔴 PRESENT-IFF — one of the three per-key exceptions on this surface (with `sealedKey` and `centerWiring`, contract appendix B.1): the facility = the k8s lane AND a snapshot store (the three
|
|
10317
|
-
`MINIO_*` keys). ABSENT is a missing key, never `false` / `null` / `{}`, and means one of TWO things with the SAME action: an older server (< 7.125.0, does not know this bit), or a deployment that
|
|
10318
|
-
is not the k8s lane / has
|
|
10319
|
-
`persist: "off"` means the store is present and the capability is present but
|
|
10320
|
-
FAILURE IS LOUD: failing to read `latest` or the commit marker, a
|
|
10321
|
-
directory; a partial directory is not handed to tools and is not snapshotted back); a
|
|
10436
|
+
`MINIO_*` keys), OR (server >= 7.126.0) the k8s lane AND the build-cache volume on. ABSENT is a missing key, never `false` / `null` / `{}`, and means one of TWO things with the SAME action: an older server (< 7.125.0, does not know this bit), or a deployment that
|
|
10437
|
+
is not the k8s lane / has neither a snapshot store nor the cache volume (the same body's `version` tells them apart) — either way do NOT promise "last run's files are still there"; treat each run's workspace as an empty directory.
|
|
10438
|
+
`persist: "off"` means the store is present and the capability is present but the operator switched persistence off, so nothing is retained today — different from the member being absent. Covers `/workspace` only (process / memory state does not cross runs).
|
|
10439
|
+
FAILURE IS LOUD: failing to read `latest` or the commit marker, or a restore that fails midway (the snapshot is there but the download / unpack / time bound failed — the refusal names two exits: raise `WORKSPACE_SNAPSHOT_TIMEOUT_MS`, or run one turn with
|
|
10440
|
+
`WORKSPACE_PERSIST=off`) fails THAT run's sandbox connect (never a silent empty directory; a partial directory is not handed to tools and is not snapshotted back); a `latest` that points at a missing snapshot object (cleared by a bucket lifecycle rule)
|
|
10441
|
+
is, since server 7.126.0, an operator line plus deleting the dangling pointer, and that run starts from an empty directory (in 7.125.0 it failed the sandbox connect). A failed end-of-run snapshot puts the residual key `workspaceSnapshot: "failed"` on the fleet terminal `task` frame
|
|
10322
10442
|
(`FleetTaskRow.workspaceSnapshot`), and the next run restores the PREVIOUS `latest`.
|
|
10323
10443
|
background:
|
|
10324
10444
|
type: object
|
|
@@ -11220,7 +11340,7 @@ components:
|
|
|
11220
11340
|
[model, runsActive, tasks, tokensTotal, costUsd, costUsdByModel, costUnknown, unpricedCalls,
|
|
11221
11341
|
taskDurationAvgSec, brainFirstTokenAvgMs, brainCallAvgMs, cacheHitRateAvg, promptCacheLowHit,
|
|
11222
11342
|
rateLimited, costQuotaRejected, budgetExceeded, degraded, degenerate, memoryConsolidationOps,
|
|
11223
|
-
planCacheRecurrence, cascade, verifications,
|
|
11343
|
+
planCacheRecurrence, cascade, verifications, toolErrors]
|
|
11224
11344
|
additionalProperties: true
|
|
11225
11345
|
properties:
|
|
11226
11346
|
model: { type: string }
|
|
@@ -11254,7 +11374,6 @@ components:
|
|
|
11254
11374
|
hitRate: { type: [number, 'null'] }
|
|
11255
11375
|
cascade: { type: object, additionalProperties: { type: integer } }
|
|
11256
11376
|
verifications: { type: object, additionalProperties: { type: integer } }
|
|
11257
|
-
councilRuns: { type: object, additionalProperties: { type: integer } }
|
|
11258
11377
|
toolErrors: { type: object, additionalProperties: { type: integer } }
|
|
11259
11378
|
limitCeilingAfterAnswer:
|
|
11260
11379
|
type: object
|
|
@@ -11331,6 +11450,38 @@ components:
|
|
|
11331
11450
|
Upgrade window (as it is): an on-disk LKG written by server <= 7.122.x only recorded the dropped entries that had a name AND were
|
|
11332
11451
|
enabled; while serving from it with the center still unreachable this key lists only those rows (possibly `[]`) and the first pull after the
|
|
11333
11452
|
center is reachable fills it in. An unknown `reasonCode` word reads as "dropped, reason unknown".
|
|
11453
|
+
candidateRejected:
|
|
11454
|
+
allOf: [{ $ref: '#/components/schemas/CandidateRejected' }]
|
|
11455
|
+
description: >
|
|
11456
|
+
server >= 7.126.0, PRESENT-IFF: the conclusion of the most recent configuration candidate the candidate judge rejected as a whole.
|
|
11457
|
+
Present exactly when the configuration now in force is the fallback one (the on-disk LKG / the previously adopted candidate / env) BECAUSE the judge
|
|
11458
|
+
rejected the latest candidate; a later candidate judged clean, a deployment that never judged a rejection / has no configuration pipeline (pure env), and
|
|
11459
|
+
a dry-run posture all leave it ABSENT. Never minted as `null` / `[]` (unlike the always-present `droppedEntries`). So ABSENT does NOT mean "the
|
|
11460
|
+
configuration is clean" (it is also an earlier server): render the real cause only when the key is present; keep the old behaviour when absent.
|
|
11461
|
+
Same read as `models`: key present => this `models` is the fallback generation (none of the candidate's models are in it). No capability bit
|
|
11462
|
+
(the endpoint is always there; the presence of the key is the presence rule).
|
|
11463
|
+
|
|
11464
|
+
CandidateRejected:
|
|
11465
|
+
type: object
|
|
11466
|
+
additionalProperties: false
|
|
11467
|
+
required: [domains, at, source]
|
|
11468
|
+
description: >
|
|
11469
|
+
`ModelsResponse.candidateRejected` (server >= 7.126.0): the conclusion of the most recent configuration candidate the candidate judge
|
|
11470
|
+
rejected as a whole (one failing domain, or a malformed prompts plane, rejects the WHOLE candidate: no domain of it is applied).
|
|
11471
|
+
ZERO free text: no rejection sentence, no file path, no version number (those stay in the server log).
|
|
11472
|
+
properties:
|
|
11473
|
+
domains:
|
|
11474
|
+
type: array
|
|
11475
|
+
items: { type: string }
|
|
11476
|
+
description: 'The configuration domain names (the contract package''s domain keys, e.g. `mcp` / `models` / `prompts`) that failed the shape judgement; sorted, de-duplicated. An unknown word is rendered as-is.'
|
|
11477
|
+
at:
|
|
11478
|
+
type: string
|
|
11479
|
+
format: date-time
|
|
11480
|
+
description: 'ISO 8601: when THIS process''s judge judged this candidate (re-judging the same candidate with the same failing domains does not refresh it).'
|
|
11481
|
+
source:
|
|
11482
|
+
type: string
|
|
11483
|
+
enum: [local, remote]
|
|
11484
|
+
description: 'Which configuration source the candidate was read from: `local` = the local config directory, `remote` = the center. A shell says "edit your config file" vs "ask the administrator" from it.'
|
|
11334
11485
|
|
|
11335
11486
|
DroppedEntry:
|
|
11336
11487
|
type: object
|
|
@@ -12615,7 +12766,9 @@ components:
|
|
|
12615
12766
|
description: 'server >= 7.102.0 (S-755 / cli L-695): WHO raised this ask, read once together with `frame.origin` when the entry is minted. The durable `pending[]` rows of the same response carry it top-level too — one reading for both row families. OPEN set (see AskOrigin).'
|
|
12616
12767
|
fromSubagent: { type: boolean, enum: [true], description: 'The ask originates from a delegated subagent.' }
|
|
12617
12768
|
originTaskId: { type: string, description: 'S-52 C2 (server ≥7.52, A-075.87): the delegated child taskId (= the child''s core runSourceTaskId, uuid) — correlates this live ask to the child run row. Minted by the SAME conditional spread as `fromSubagent`: the two keys are always both present or both absent (三键恒等亲证在案).' }
|
|
12618
|
-
|
|
12769
|
+
approvalCard:
|
|
12770
|
+
allOf: [{ $ref: '#/components/schemas/ToolApprovalCardWord' }]
|
|
12771
|
+
description: 'server >= 7.126.0 (core 7.49.0 #1414): which card this ask renders on — the engine-minted card word, the SAME value as `frame.approvalCard` (the row reads the frame''s own seat, no second read), same layer and shape as the operator queue row''s `approvalCard`. It REPLACES `contentKind` (server <= 7.125.x derived it from the tool name; deleted at 7.126.0, no alias). ABSENT = the engine minted none. Display / triage only; it NEVER takes part in decision routing.'
|
|
12619
12772
|
frame:
|
|
12620
12773
|
allOf: [{ $ref: '#/components/schemas/ToolApprovalFrame' }]
|
|
12621
12774
|
description: >-
|
|
@@ -12958,6 +13111,9 @@ components:
|
|
|
12958
13111
|
origin:
|
|
12959
13112
|
allOf: [{ $ref: '#/components/schemas/AskOrigin' }]
|
|
12960
13113
|
description: 'server >= 7.102.0 (S-755 / cli L-695 / C-R111): WHO raised this ask — the park-row twin seat `PendingAction.tool_approval.origin` read through `readClosedWordSeat(…, "origin")` (core `isAskOrigin`). Same word as the live card frame and the inbox row. Absent = an old row (parked before core 7.5.0) or an out-of-set word — NOT "policy".'
|
|
13114
|
+
approvalCard:
|
|
13115
|
+
allOf: [{ $ref: '#/components/schemas/ToolApprovalCardWord' }]
|
|
13116
|
+
description: 'server >= 7.126.0 (core 7.49.0 #1414): which card this row renders on — the engine-minted `gate.approvalCard` (closed eight-word set; the park-row twin seat reads the same word core''s `summarizeCheckpoint` projects onto `CheckpointSummary.approvalCard`; an out-of-set word reads as absent and is counted), the same word as the live frame / `livePending` row. It REPLACES `contentKind` (deleted at 7.126.0, no alias). ABSENT = the engine minted none: a row parked before engine 7.49.0 (core never derives a card from the tool name: no card = not a question, so an old question row carries no card word and is swept by the SLA at its deadline), a non-approval gate, or an older engine. Display / triage only; NEVER part of resume / gate / CAS; the inbox row does not carry it.'
|
|
12961
13117
|
ruleOffersAbsence:
|
|
12962
13118
|
allOf: [{ $ref: '#/components/schemas/RuleOffersAbsence' }]
|
|
12963
13119
|
description: 'server >= 7.100.0 (S-700): WHY the park row offers no rule — the same narrow read and closed three-word set as the live card frame and `card_json`.'
|
|
@@ -13012,11 +13168,6 @@ components:
|
|
|
13012
13168
|
(they carry a RiskDescriptor); ABSENT for resource_limit/needs_review/plan_review — UI tolerates undefined.
|
|
13013
13169
|
spentMicroUsd: { type: number, description: 'cumulative spend on the suspend chain (when a resource ledger is attached).' }
|
|
13014
13170
|
deadline: { type: integer, description: 'awaiting-human SLA deadline (epoch ms).' }
|
|
13015
|
-
contentKind:
|
|
13016
|
-
type: string
|
|
13017
|
-
description: >
|
|
13018
|
-
Open enum (known value `content_ask`) distinguishing WHAT is being asked about, for gates whose payload
|
|
13019
|
-
is content rather than a tool call. Treat unknown values as opaque.
|
|
13020
13171
|
sourceTaskId: { type: string, description: 'The task that produced this checkpoint (when distinct from sessionId).' }
|
|
13021
13172
|
principal: { type: string, description: 'The submitting principal, when the deployment records one.' }
|
|
13022
13173
|
createdAt: { type: integer, description: 'Creation time, epoch ms (NOTE — SessionRecord.createdAt is an ISO string).' }
|
|
@@ -13030,7 +13181,7 @@ components:
|
|
|
13030
13181
|
ASSISTANT-WIRE-CONTRACT §2 — an inbox row (server >=3.4.0 EXPLICIT-projection form): the §1 mirror keys
|
|
13031
13182
|
of a CheckpointSummary (token stripped; no rich per-tool fields) + two nullable enrichments.
|
|
13032
13183
|
NARROWING RECORD (2026-07-30, board [2027]->[2029]): rows used to also carry
|
|
13033
|
-
toolName/toolCallId/preview/principal/sourceTaskId
|
|
13184
|
+
toolName/toolCallId/preview/principal/sourceTaskId (handler spread the whole projection) and
|
|
13034
13185
|
this spec over-declared decide bindings that never appeared on inbox wire at all. Four client repos were
|
|
13035
13186
|
structurally zero-consumers, so server 3.4.0 narrowed the wire and this schema follows. For the tool face
|
|
13036
13187
|
and decide bindings use /v1/approvals (PendingCheckpoint); for task attribution use /v1/assistant/tasks.
|
|
@@ -13318,6 +13469,13 @@ components:
|
|
|
13318
13469
|
decision: { type: string, enum: [approve, edit, reject] }
|
|
13319
13470
|
editedPlan: { type: string, description: 'the operator''s revised plan — required iff decision==="edit".' }
|
|
13320
13471
|
reason: { type: string }
|
|
13472
|
+
decidedBy:
|
|
13473
|
+
allOf: [{ $ref: '#/components/schemas/ApprovalDecidedBy' }]
|
|
13474
|
+
description: >
|
|
13475
|
+
server >= 7.126.0 (engine 7.49.0 gave the plan-review outcome a required decision-fact seat, the same seat as tool approvals) — WHO MADE THIS DECISION, the same closed set and the same single
|
|
13476
|
+
reading as the three tool-approval decision doors: absent => `person`; `policy` is accepted; a word outside the closed set (including `sla_timeout`, which only the server's own deadline sweep can say)
|
|
13477
|
+
=> `400 request.field_invalid`; on a direct-door (D-G) deployment ANY value => `400 decided_by_not_in_proof` (the key is not in the decision proof's signed payload). Not echoed in the response. NO capability bit
|
|
13478
|
+
covers this door (`approvalDecidedBy` is >= 7.118.0 and does not cover plan_review): send it by server version; <= 7.125.x answers `400 request.body_shape` and lists it in `unsupportedKeys`.
|
|
13321
13479
|
permissionModeAfter:
|
|
13322
13480
|
type: string
|
|
13323
13481
|
enum: [default, acceptEdits]
|
|
@@ -14721,6 +14879,13 @@ components:
|
|
|
14721
14879
|
# 真发 `label`(core 展示名,与 tool_end 同待遇),spec 此前漏声明 —— 封闭前必须先补,否则真帧变假红。
|
|
14722
14880
|
label: { type: string, description: 'core 展示名(缺席 ⇒ 用 toolName 渲染)。' }
|
|
14723
14881
|
args: {}
|
|
14882
|
+
recovered:
|
|
14883
|
+
type: boolean
|
|
14884
|
+
enum: [true]
|
|
14885
|
+
description: >
|
|
14886
|
+
server >= 7.126.0 (core 7.49.0 `tool_start.recovered`, contract table B `recovered` row, passed through verbatim): present, always the literal `true`, when the engine CLOSED a call whose start
|
|
14887
|
+
frame was never emitted by minting this start frame after the fact (an interrupted run's reconciliation / a resumed process closing a call the dead process had announced), keeping "every
|
|
14888
|
+
`tool_end` is preceded by a `tool_start` of the same id". Absent on the loop's own announced start frames (the vast majority). Does NOT assert whether the tool executed — read the paired `tool_end.notExecuted`.
|
|
14724
14889
|
eventId: { type: string }
|
|
14725
14890
|
parentToolCallId: { type: string }
|
|
14726
14891
|
sourceTaskId: { type: string }
|
|
@@ -15250,6 +15415,18 @@ components:
|
|
|
15250
15415
|
# 🔴 census 轴一(2026-07-30)回填:`toolEndEventData`(trace/project.ts)真发 `label` 与
|
|
15251
15416
|
# `structured`,spec 此前两者都漏 —— SDK 的 events.ts 早已声明,漂移只在 spec 这一侧。
|
|
15252
15417
|
label: { type: string, description: 'core 展示名(同 tool_start.label)。' }
|
|
15418
|
+
notExecuted:
|
|
15419
|
+
type: boolean
|
|
15420
|
+
enum: [true]
|
|
15421
|
+
description: >
|
|
15422
|
+
server >= 7.126.0 (core 7.49.0, contract table B `notExecuted` row, passed through verbatim) — ABSENT IS NEVER "it ran": present, always the literal `true` (never `false`), when the engine has
|
|
15423
|
+
POSITIVE evidence the call was never executed; absent only means the engine has no such evidence (a call interrupted mid-execution, or one closed by the reconciliation on the next process start, does not carry it —
|
|
15424
|
+
telling the model "it did not run" there could invite a replay of a write that already took effect). Read it together with the paired `tool_start.recovered`.
|
|
15425
|
+
wireName:
|
|
15426
|
+
type: string
|
|
15427
|
+
description: >
|
|
15428
|
+
server >= 7.126.0 (core 7.49.0, contract table B `wireName` row, passed through verbatim) — the tool name this call resolved to on the LIVE roster (the name the gate judged). `toolName` stays the model's spelling (an alias /
|
|
15429
|
+
a retired name the roster still answers to). Present ONLY on a refused call (`gate.disposition.kind === "denied"`), and absent when the station that refused it did not know the roster name; per-tool refusal accounting reads this, not `toolName`.
|
|
15253
15430
|
structured: {} # core 1.203 CC 卡片明细;与 output 同一 UNTRUSTED RAW 待遇(已 redactDeep),形状开放
|
|
15254
15431
|
isError: { type: boolean }
|
|
15255
15432
|
output: {} # NON-UNIFORM: string | (TextContent|ImageContent)[] | (truncated) string. Absent ⇒ no body.
|
|
@@ -15471,6 +15648,8 @@ components:
|
|
|
15471
15648
|
maxRetries: { type: number, description: "retry budget of the lane in force (refused-connect short lane = 2)" }
|
|
15472
15649
|
retryInMs: { type: number, description: "same number as retryInSec at ms precision (countdown rendering)" }
|
|
15473
15650
|
errClass: { type: string, description: "connect_refused | transport | rate_limit | server | http | output_cap — retry-wait frames ONLY; never inferred from phase" }
|
|
15651
|
+
providerCondition: { type: string, description: "server >= 7.126.0 (core 7.49.0 #1454, passed through verbatim): what the provider said about the account / capacity — core's closed `PROVIDER_CONDITIONS`; a retry frame carries only the three retryable words `throttled | overloaded | unknown` (`quota_exhausted` / `stop_other` do not retry and ride the terminal `detail.providerCondition`). Presence law as `errorStatus`; read as an OPEN set (keep a default arm). ABSENT = not judged, read the same as `unknown` (back off, do not assert quota). Moves with `providerConditionSource`." }
|
|
15652
|
+
providerConditionSource: { type: string, description: "server >= 7.126.0 (core 7.49.0 #1454): the evidence the `providerCondition` verdict rests on — `unified_header | provider_code | status`; present exactly when `providerCondition` is; read as an OPEN set." }
|
|
15474
15653
|
eventId: { type: string }
|
|
15475
15654
|
parentToolCallId: { type: string }
|
|
15476
15655
|
sourceTaskId: { type: string }
|
|
@@ -16230,6 +16409,12 @@ components:
|
|
|
16230
16409
|
switch itself became the WORD `"disabled"` instead of `null` (a string is not nullish, so the ordinary
|
|
16231
16410
|
coalesce is the whole resolution rule and no reader has to remember a null test). A consumer still
|
|
16232
16411
|
matching `task_store_null` matches nothing.
|
|
16412
|
+
server 7.126.0 (the user-visible whitelist grows 35 -> 37 codes; contract appendix D.3): `task.tool_turn_incomplete` gains an optional `detail.outcome` (core 7.49.1) —
|
|
16413
|
+
`{cause, count, toolCallIds?, outcome?, sessionId, runId}`, `outcome` in {`terminal` (the dropped calls ended the run with `model_output_invalid`), `reissued` (the model was asked to reissue)}, present only when
|
|
16414
|
+
the turn's own message can say it, ABSENT = not said; two NEW codes (core 7.49.0, audience `user`, zero body text): `route.finish_reason_unknown` `{finishReason, sessionId, runId}` — the provider ended the turn
|
|
16415
|
+
with a finish reason the engine does not understand, so the text above may be cut short (`finishReason` = the provider's own word, an OPEN string, passed through verbatim; once per run per word); and
|
|
16416
|
+
`route.stream_end_ignored` `{statement, word, frames, sessionId, runId}` — the provider had already ended the turn and its stream sent more (`statement` in {`ending`, `error`, `content`}, `word` = the late first
|
|
16417
|
+
frame's ending reason / error word / content kind, `frames` = how many frames came after the end; the first ending counts, anything later never entered the turn; once per run per (statement, word)).
|
|
16233
16418
|
A notice whose `detail.sessionId` is absent is HONESTLY NOT DELIVERED (the server never guesses a session),
|
|
16234
16419
|
so the frame's absence does NOT mean "did not happen" — the operator-facing structured log always has the
|
|
16235
16420
|
full family. `detail` is already redacted + size-bounded by the server; still treat it as external text.
|
|
@@ -16877,6 +17062,15 @@ components:
|
|
|
16877
17062
|
deployment read the bit at all. Present ⇒ every automatic allowance (remembered rules,
|
|
16878
17063
|
bypassPermissions posture) stands down.
|
|
16879
17064
|
origin: { $ref: '#/components/schemas/AskOrigin' }
|
|
17065
|
+
approvalCard:
|
|
17066
|
+
allOf: [{ $ref: '#/components/schemas/ToolApprovalCardWord' }]
|
|
17067
|
+
description: >
|
|
17068
|
+
"tool_approval" only, ADDITIVE (server >= 7.126.0 / core 7.49.0 #1414, contract table B `approvalCard` row) — WHICH CARD THIS ASK RENDERS ON: the one word the engine minted at the gate
|
|
17069
|
+
(closed set `ToolApprovalCardWord`, eight words), passed through verbatim after a closed-set narrow read (an out-of-set word reads as absent). The ONLY card-word source — it REPLACES the
|
|
17070
|
+
second card word `contentKind` that server <= 7.125.x derived from the tool name (deleted at 7.126.0, no alias: a consumer reading `contentKind === "content_ask"` reads
|
|
17071
|
+
`approvalCard === "question"`). ABSENT = the engine minted none (a host-built ask / an older engine / a non-approval gate) — never `generic` by default. Display / triage only; it NEVER
|
|
17072
|
+
takes part in resume / gate / CAS. The same word rides the `livePending` row top level (= this frame's own value), the operator queue row and the `/v1/approvals/stream` `pending` /
|
|
17073
|
+
`live_pending` frames; the `card_json` card face and the `approval_request` frame's `card` do NOT carry it (`ApprovalCard` is `.strict()`).
|
|
16880
17074
|
inputHasBidi:
|
|
16881
17075
|
type: boolean
|
|
16882
17076
|
enum: [true]
|
|
@@ -18048,6 +18242,22 @@ components:
|
|
|
18048
18242
|
400 `request.field_invalid`; any value on a direct-door worker ⇒ 400 `decided_by_not_in_proof`. An older server
|
|
18049
18243
|
(no `approvalDecidedBy` bit) has a strict body here ⇒ 400 `request.body_shape`, nothing decided.
|
|
18050
18244
|
|
|
18245
|
+
ApprovalDecideGateKind:
|
|
18246
|
+
type: string
|
|
18247
|
+
enum: [human, irreversible_ask]
|
|
18248
|
+
description: >
|
|
18249
|
+
server >= 7.126.0 (sdk 21.1.0 `APPROVAL_DECIDE_GATE_KINDS`, verbatim and in order; single owner = server
|
|
18250
|
+
`APPROVAL_GATE_KINDS`) — the parked gate kinds the DURABLE decision door `POST /v1/approvals/{sessionId}/decide`
|
|
18251
|
+
accepts (the live `POST /v1/tool-approvals/{approvalId}/respond` answers the same card family). A parked row of
|
|
18252
|
+
kind `plan_review` goes to the plan-review door instead (`PlanReviewGateKind`); `resource_limit` / `needs_review` /
|
|
18253
|
+
`task_done` have no human decision door (resume / terminal). Clients route a pending row by reading this set,
|
|
18254
|
+
never by a hand-written copy of it.
|
|
18255
|
+
PlanReviewGateKind:
|
|
18256
|
+
type: string
|
|
18257
|
+
enum: [plan_review]
|
|
18258
|
+
description: >
|
|
18259
|
+
server >= 7.126.0 (sdk 21.1.0 `PLAN_REVIEW_GATE_KINDS`) — the parked gate kind the plan-review door
|
|
18260
|
+
`POST /v1/assistant/tasks/{taskId}/plan_review` accepts (3-state approve | edit | reject).
|
|
18051
18261
|
ApprovalDecidedBy:
|
|
18052
18262
|
type: string
|
|
18053
18263
|
enum: [person, policy]
|
|
@@ -18062,7 +18272,17 @@ components:
|
|
|
18062
18272
|
"the wait ran out with nobody answering" is said only by the server's own deadline sweep — and the old `human` / `timeout`
|
|
18063
18273
|
words) ⇒ 400 before the decision. It REPLACES the 7.93.3–7.117.x key `settledBy` (deny-only, the same fact), deleted
|
|
18064
18274
|
by server 7.118.0 with no alias: sending `settledBy` ⇒ 400 `request.body_shape` on all three doors.
|
|
18065
|
-
`plan_review`
|
|
18275
|
+
`plan_review` (`POST /v1/assistant/tasks/{taskId}/plan_review`): server >= 7.126.0 takes it too, with the same reading and the same refusals; server <= 7.125.x answers 400 `request.body_shape`
|
|
18276
|
+
(listed in `unsupportedKeys`), and `approvalDecidedBy` does not cover that door — send it by server version.
|
|
18277
|
+
|
|
18278
|
+
ToolApprovalCardWord:
|
|
18279
|
+
type: string
|
|
18280
|
+
enum: [file-edit, file-write, notebook-edit, shell, fetch, plan, question, generic]
|
|
18281
|
+
description: >
|
|
18282
|
+
server >= 7.126.0 (core 7.49.0 `TOOL_APPROVAL_CARDS`, verbatim and in order; contract table B `approvalCard` row) — WHICH CARD an approval ask renders on: the one word the engine mints at the gate, the
|
|
18283
|
+
ONLY card-word source (it replaces the tool-name-derived `contentKind`). `question` = a question put to the user (the engine's reserved question tool — not a side-effecting tool; a consumer that read
|
|
18284
|
+
`contentKind === "content_ask"` reads `approvalCard === "question"`); `generic` = a card with no dedicated renderer. CLOSED set; new words join with a core minor, so a switch on it keeps a default arm.
|
|
18285
|
+
At expiry a parked `question` gate is voided and every other approval gate goes to the SLA refusal sweep (the judge is the engine's `facetOf(gate)`).
|
|
18066
18286
|
|
|
18067
18287
|
ApprovalReach:
|
|
18068
18288
|
type: string
|
|
@@ -18741,6 +18961,9 @@ components:
|
|
|
18741
18961
|
origin:
|
|
18742
18962
|
allOf: [{ $ref: '#/components/schemas/AskOrigin' }]
|
|
18743
18963
|
description: '`pending` / `live_pending` frames (server >= 7.102.0 / S-755) — see PendingCheckpoint.origin / LivePendingRow.origin. OPEN set.'
|
|
18964
|
+
approvalCard:
|
|
18965
|
+
allOf: [{ $ref: '#/components/schemas/ToolApprovalCardWord' }]
|
|
18966
|
+
description: '`pending` / `live_pending` frames (server >= 7.126.0 / core 7.49.0 #1414) — see PendingCheckpoint.approvalCard / LivePendingRow.approvalCard. Replaces `contentKind`.'
|
|
18744
18967
|
ruleOffersAbsence:
|
|
18745
18968
|
allOf: [{ $ref: '#/components/schemas/RuleOffersAbsence' }]
|
|
18746
18969
|
description: '`pending` frames only (server >= 7.100.0 / S-700) — see PendingCheckpoint.ruleOffersAbsence.'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "21.1.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",
|