@sema-agent/sdk 23.1.0 → 25.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 +201 -4
- package/dist/client.d.ts +6 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +8 -1
- package/dist/client.js.map +1 -1
- package/dist/device/index.d.ts +76 -12
- package/dist/device/index.d.ts.map +1 -1
- package/dist/device/index.js +90 -31
- package/dist/device/index.js.map +1 -1
- package/dist/errors.d.ts +318 -6
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +121 -10
- package/dist/errors.js.map +1 -1
- package/dist/events.d.ts +165 -23
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +19 -0
- package/dist/events.js.map +1 -1
- package/dist/health.d.ts +29 -1
- package/dist/health.d.ts.map +1 -1
- package/dist/health.js.map +1 -1
- package/dist/index.d.ts +38 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -4
- package/dist/index.js.map +1 -1
- package/dist/model-route-env/index.d.ts +129 -0
- package/dist/model-route-env/index.d.ts.map +1 -0
- package/dist/model-route-env/index.js +131 -0
- package/dist/model-route-env/index.js.map +1 -0
- package/dist/registry/errors.d.ts +3 -0
- package/dist/registry/errors.d.ts.map +1 -1
- package/dist/registry/errors.js +3 -2
- package/dist/registry/errors.js.map +1 -1
- package/dist/registry/me-config.d.ts +1 -0
- package/dist/registry/me-config.d.ts.map +1 -1
- package/dist/registry/me-config.js +1 -1
- package/dist/registry/me-config.js.map +1 -1
- package/dist/registry/scope-config-feedback.d.ts +1 -0
- package/dist/registry/scope-config-feedback.d.ts.map +1 -1
- package/dist/registry/scope-config-feedback.js +1 -1
- package/dist/registry/scope-config-feedback.js.map +1 -1
- package/dist/resources/adoption.d.ts +8 -2
- package/dist/resources/adoption.d.ts.map +1 -1
- package/dist/resources/adoption.js.map +1 -1
- package/dist/resources/approvals.d.ts +22 -2
- package/dist/resources/approvals.d.ts.map +1 -1
- package/dist/resources/approvals.js +12 -2
- package/dist/resources/approvals.js.map +1 -1
- package/dist/resources/elicitations.d.ts +2 -1
- package/dist/resources/elicitations.d.ts.map +1 -1
- package/dist/resources/elicitations.js.map +1 -1
- package/dist/resources/fleet.d.ts +65 -6
- package/dist/resources/fleet.d.ts.map +1 -1
- package/dist/resources/fleet.js.map +1 -1
- package/dist/resources/ops.d.ts +113 -0
- package/dist/resources/ops.d.ts.map +1 -1
- package/dist/resources/ops.js +10 -0
- package/dist/resources/ops.js.map +1 -1
- package/dist/resources/principal-inbox.d.ts +62 -0
- package/dist/resources/principal-inbox.d.ts.map +1 -0
- package/dist/resources/principal-inbox.js +51 -0
- package/dist/resources/principal-inbox.js.map +1 -0
- package/dist/resources/questions.d.ts +2 -1
- package/dist/resources/questions.d.ts.map +1 -1
- package/dist/resources/questions.js.map +1 -1
- package/dist/resources/session-sync.d.ts +4 -2
- package/dist/resources/session-sync.d.ts.map +1 -1
- package/dist/resources/session-sync.js +4 -2
- package/dist/resources/session-sync.js.map +1 -1
- package/dist/resources/tool-approvals.d.ts +201 -22
- package/dist/resources/tool-approvals.d.ts.map +1 -1
- package/dist/resources/tool-approvals.js +183 -36
- package/dist/resources/tool-approvals.js.map +1 -1
- package/dist/settings.d.ts +73 -1
- package/dist/settings.d.ts.map +1 -1
- package/dist/sse.d.ts +8 -1
- package/dist/sse.d.ts.map +1 -1
- package/dist/sse.js +9 -5
- package/dist/sse.js.map +1 -1
- package/dist/types.d.ts +475 -113
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +11 -5
- package/dist/types.js.map +1 -1
- package/openapi.yaml +1296 -153
- package/package.json +6 -2
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: `) and — server >= 7.126.0 — `config.tool_face_control` (400: `allowTools: ["mcp__*"]`, `excludeTools: ["*"]` (and, on server 7.126.0–7.128.x only, a name in `allowTools` / `excludeTools` that no tool of this run answers to — server >= 7.129.0 runs those as written and announces each once with the operator row `runner_config_advisory`), 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
|
|
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: `allowTools: ["mcp__*"]`, `excludeTools: ["*"]` (and, on server 7.126.0–7.128.x only, a name in `allowTools` / `excludeTools` that no tool of this run answers to — server >= 7.129.0 runs those as written and announces each once with the operator row `runner_config_advisory`), 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) and — server >= 7.132.0, BREAKING (200 + failed body before) — `config.agent.unknown_tool` (400: a delegated agent's `allowTools` names a near-miss / a retired name with a successor / an impossible spelling, judged by the engine before the run; the intake refusal of `agents[i].denyTools` entries that read as nothing has answered this 400 since 7.131.0) and `config.legacy_tool_name` (400: a stored session-rule row names a tool the engine reads as nothing) and `prompt.assembled_role_refused` (400: `systemPrompt` / `appendSystemPrompt` — `settings.outputStyle` folded in — carries the engine's locked prompt text verbatim; send role text only) and — server >= 7.131.0 — `config.user_attachment_invalid` (400; server >= 7.132.0 the body adds `detail: { path, index? }`), `corrupt_session`; these registered codes answer 400 on all three submit legs without spending the `Idempotency-Key` (async / live legs: 2xx with the same code on the terminal run row); 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
|
|
@@ -3424,7 +3424,7 @@ paths:
|
|
|
3424
3424
|
`synced` (and `synced.count` still counts ONLY the durable queue).
|
|
3425
3425
|
🔴 THE TWO WORDS DELIBERATELY DO NOT REUSE `pending`/`resolved`: those are keyed by
|
|
3426
3426
|
`(sessionId, toolCallId)` and decided at `POST /v1/approvals/{sessionId}/decide`, while a live row is
|
|
3427
|
-
keyed by `approvalId` and decided at `POST /v1/tool-approvals/{
|
|
3427
|
+
keyed by `approvalId` and decided at `POST /v1/tool-approvals/{id}/respond`. Sharing one word
|
|
3428
3428
|
would eventually send a live card to the decide door — a 404 with no wire evidence of the mistake.
|
|
3429
3429
|
⚠️ Both live words come from an IN-PROCESS window projection, so their cross-replica reach is exactly
|
|
3430
3430
|
that of `GET /v1/approvals`'s `livePending` — narrower than the durable pair above. The deployment
|
|
@@ -4393,6 +4393,38 @@ paths:
|
|
|
4393
4393
|
'404': { description: no pending question for this id (non-owner, answered, expired, or wrong replica) — no existence oracle. }
|
|
4394
4394
|
'501': { description: AskUserQuestion is not enabled on this worker (ASK_QUESTION_ENABLED). }
|
|
4395
4395
|
|
|
4396
|
+
/v1/tool-approvals/{id}:
|
|
4397
|
+
parameters:
|
|
4398
|
+
- $ref: '#/components/parameters/PrincipalHeader'
|
|
4399
|
+
- { name: id, in: path, required: true, schema: { type: string }, description: 'The ask''s `approvalId` (server >= 7.133.0 always equal to its `askId`; an opaque string).' }
|
|
4400
|
+
get:
|
|
4401
|
+
tags: [questions]
|
|
4402
|
+
operationId: toolApprovalRead
|
|
4403
|
+
x-status: live # server >= 7.133.0; SDK toolApprovals.get consumes it
|
|
4404
|
+
summary: Read ONE live-card ask — where is it now (pending, decided, parked or void)? Pure read.
|
|
4405
|
+
description: >
|
|
4406
|
+
server >= 7.133.0 — the by-ask read door. Same root and same gate as POST /v1/tool-approvals/{id}/respond (one `gatedPrincipal`; an owner-gate miss answers the SAME 404 as an unknown
|
|
4407
|
+
id — no existence oracle), and the state is read the way the answer door reads it: a live registration on THIS replica waiting for the ask => `pending` (the body is the `livePending[]` row projection +
|
|
4408
|
+
`state`); otherwise the row is read by id: `DECIDED` => `decided`, `PARKING` / `PARKED` => `parked`, `DENIED` / `VOID` => `void`. A row still `STREAM_PENDING` with no local registration lives on
|
|
4409
|
+
another replica => 404 `tool_approval.not_pending` + `cause: "unknown_or_other_replica"` (the same answer as a late respond); a deployment with no ask ledger answers the same 404 WITHOUT `cause`.
|
|
4410
|
+
Pure read: zero writes, no settlement, the local registration is untouched. Use it to ask "is this card still alive / was it decided by anyone" instead of inferring it from a respond 404.
|
|
4411
|
+
An older server (<= 7.132.x) has no such door: routing-level 404 `not_found.route` — tell it apart from this door's 404 by `errorCode`, never by status.
|
|
4412
|
+
responses:
|
|
4413
|
+
'200':
|
|
4414
|
+
description: The ask's current state.
|
|
4415
|
+
content:
|
|
4416
|
+
application/json:
|
|
4417
|
+
schema: { $ref: '#/components/schemas/ToolApprovalReadBody' }
|
|
4418
|
+
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
4419
|
+
'404':
|
|
4420
|
+
description: >
|
|
4421
|
+
`tool_approval.not_pending` — unknown / not yours (byte-identical) / still pending on another replica (`cause: unknown_or_other_replica`). Past the owner gate the body may carry the additive `cause`
|
|
4422
|
+
(see ToolApprovalNotPendingCause); no ask ledger => no `cause`.
|
|
4423
|
+
content:
|
|
4424
|
+
application/json:
|
|
4425
|
+
schema: { $ref: '#/components/schemas/ToolApprovalNotPendingBody' }
|
|
4426
|
+
'501': { description: 'Live tool-approval HITL not enabled (TOOL_APPROVAL_ENABLED) — `feature.tool_approval_disabled`.' }
|
|
4427
|
+
|
|
4396
4428
|
/v1/tool-approvals/{id}/respond:
|
|
4397
4429
|
parameters:
|
|
4398
4430
|
- $ref: '#/components/parameters/PrincipalHeader'
|
|
@@ -5799,6 +5831,70 @@ paths:
|
|
|
5799
5831
|
'403': { description: 'Multi-tenant worker: outcomes view is operator-only.' }
|
|
5800
5832
|
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
5801
5833
|
|
|
5834
|
+
/v1/config/catalog:
|
|
5835
|
+
parameters:
|
|
5836
|
+
- $ref: '#/components/parameters/PrincipalHeader'
|
|
5837
|
+
get:
|
|
5838
|
+
tags: [admin]
|
|
5839
|
+
operationId: configCatalog
|
|
5840
|
+
x-status: live # operator lane (capabilities.configCatalog); SDK configCatalog.get consumes it
|
|
5841
|
+
summary: Deployment configuration catalog — every env knob's declaration and this process's effective reading (operator-only).
|
|
5842
|
+
description: >
|
|
5843
|
+
The deployment's configuration catalog (operator lane; probe `capabilities.configCatalog` first). One row per env knob: its declared semantics, which lanes can write it, which lane is in force, the
|
|
5844
|
+
process's effective DISPLAY value and the centre seat (`center`) when the knob is centre-publishable; plus the `retired` tombstone list (env names this process refuses to start on). `Cache-Control: no-store`.
|
|
5845
|
+
Gate: `OPERATOR_PRINCIPALS` — outside the list 403 `auth.operator_only`; empty list on a multi-tenant deployment 501 `capability.operator_principals_required`; `CONFIG_CATALOG_ENABLED=false` 501
|
|
5846
|
+
`feature.config_catalog_disabled`. A server older than 7.53 has no such route (404).
|
|
5847
|
+
`effectiveValue` is a DISPLAY value, never the raw env: `secret` / `opaque` rows report only `{ present, length? }`, a `url` row goes through the display mint (userinfo landed, query values become
|
|
5848
|
+
tokens). Two VERDICT bits on a row are true-only (never `false`; ABSENT = this cell has no such matter): `effectiveValueInvalid` (the effective value falls outside the row's own echo set; `effectiveValue` is then
|
|
5849
|
+
`null`) and, server >= 7.133.0, `effectiveValueWithheld` (a `url` row whose display mint WITHHELD a part — a credential-shaped piece in a query / path segment — so the shown value is not the whole value).
|
|
5850
|
+
responses:
|
|
5851
|
+
'200':
|
|
5852
|
+
description: The catalog.
|
|
5853
|
+
content:
|
|
5854
|
+
application/json:
|
|
5855
|
+
schema: { $ref: '#/components/schemas/ConfigCatalog' }
|
|
5856
|
+
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
5857
|
+
'403': { description: 'The caller is not in OPERATOR_PRINCIPALS (`auth.operator_only`).' }
|
|
5858
|
+
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
5859
|
+
|
|
5860
|
+
/v1/principal-inbox/messages:
|
|
5861
|
+
parameters:
|
|
5862
|
+
- $ref: '#/components/parameters/PrincipalHeader'
|
|
5863
|
+
post:
|
|
5864
|
+
tags: [admin]
|
|
5865
|
+
operationId: principalInboxSend
|
|
5866
|
+
x-status: live # server >= 7.133.0; SDK principalInbox.send consumes it
|
|
5867
|
+
summary: Deliver one letter to another principal's inbox in the same organization (cross-principal delivery; default OFF).
|
|
5868
|
+
description: >
|
|
5869
|
+
server >= 7.133.0 — one letter is appended to the recipient principal's `principal.inbox` ONLY by the organization delivery gate: membership judgement -> mint -> inbox bound -> quota -> append, all inside one gate that answers
|
|
5870
|
+
with a receipt or one of four refusal codes. The SENDER is always your verified identity (`from` is not a body key: sending `from` or any unknown key => 400 `request.body_shape` + `unknownKeys`). DEFAULT OFF: without env
|
|
5871
|
+
`PRINCIPAL_INBOX_ASSISTANT` the route answers 501 `capability.unavailable` (no delivery gate is mounted) — probe `capabilities.principalInboxDelivery` (true <=> this door works). THIS VERSION SHIPS THE DELIVERY HALF ONLY:
|
|
5872
|
+
a delivered letter sits in the recipient's box (at most 50 unconfirmed envelopes) and no read verb exists yet. Judging order: the sender's ATTEMPT bound (every attempt is recorded, succeeded or not, BEFORE membership) ->
|
|
5873
|
+
membership (including the mailbox-key judge) -> mint (a sender that cannot be spelled into the envelope's sender slot answers the same `not_member`, no quota consumed) -> inbox bound -> quota deduction -> append. A refused
|
|
5874
|
+
delivery appends nothing. Not auto-retried by the SDK (every attempt consumes the sender's attempt quota).
|
|
5875
|
+
The four refusal codes: `org_delivery.not_member` 404 (ONE sentence, byte-identical body for: different organization / no such person / directory could not answer / `to` is not a principal shape / the recipient cannot be a
|
|
5876
|
+
mailbox key / the sender cannot be spelled into the envelope — the gate is never an existence probe); `org_delivery.rate_limited` 429 (one sentence for three bounds: 60 attempts per sender per hour — a typo'd recipient costs an
|
|
5877
|
+
attempt —, 10 letters per (sender, recipient) pair per hour, 30 letters per recipient per hour; fixed clock-hour windows, up to double across a boundary; hard-coded, no knob); `org_delivery.inbox_full` 409 (the recipient's box already holds
|
|
5878
|
+
50 unconfirmed envelopes — judged BEFORE quota so a full box burns none); `org_delivery.recipient_tombstoned` 410 (the recipient's mailbox is in its pre-delete state).
|
|
5879
|
+
requestBody:
|
|
5880
|
+
required: true
|
|
5881
|
+
content:
|
|
5882
|
+
application/json:
|
|
5883
|
+
schema: { $ref: '#/components/schemas/PrincipalInboxMessage' }
|
|
5884
|
+
responses:
|
|
5885
|
+
'200':
|
|
5886
|
+
description: The letter was appended; `receiptId` is the gate's delivery receipt id.
|
|
5887
|
+
content:
|
|
5888
|
+
application/json:
|
|
5889
|
+
schema: { $ref: '#/components/schemas/PrincipalInboxReceipt' }
|
|
5890
|
+
'400': { description: 'Malformed body: `request.field_invalid` (not an object / empty `to` / empty or over-long `content` / non-boolean `urgent`) or `request.body_shape` (unknown key incl. `from`; body carries `unknownKeys`).' }
|
|
5891
|
+
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
5892
|
+
'404': { description: '`org_delivery.not_member` — one byte-identical body for six causes (see the description); the gate is not an existence probe.' }
|
|
5893
|
+
'409': { description: '`org_delivery.inbox_full` — the recipient''s box holds 50 unconfirmed envelopes.' }
|
|
5894
|
+
'410': { description: '`org_delivery.recipient_tombstoned` — the recipient''s mailbox is in its pre-delete state.' }
|
|
5895
|
+
'429': { description: '`org_delivery.rate_limited` — one sentence for the sender-attempt bound, the pair bound and the recipient aggregate bound.' }
|
|
5896
|
+
'501': { description: 'No delivery gate mounted (`PRINCIPAL_INBOX_ASSISTANT` off) — `capability.unavailable`.' }
|
|
5897
|
+
|
|
5802
5898
|
/v1/diagnostics/wiring:
|
|
5803
5899
|
parameters:
|
|
5804
5900
|
- $ref: '#/components/parameters/PrincipalHeader'
|
|
@@ -7064,6 +7160,7 @@ components:
|
|
|
7064
7160
|
promptSummary: { type: string, description: 'a human-readable prompt DIGEST — NOT the full prompt.' }
|
|
7065
7161
|
enabled: { type: boolean }
|
|
7066
7162
|
available: { type: boolean, description: 'whether this deployment can actually RUN the scenario right now — same predicate as the 501 rejection arm on submit; false ⟺ submitting is guaranteed to 501. Independent axis from `enabled` (declared vs runnable).' }
|
|
7163
|
+
attachmentSupplies: { type: array, items: { type: string, enum: [path, content_text, content_image] }, description: 'server >= 7.133.0, always present there: the attachment SUPPLY words this scenario actually carries — a subset of `capabilities.userAttachments.supplies` (`path` only on hands scenarios, where a workspace lives somewhere; a no-hands scenario drops `path`, and a `path` entry is refused by the engine with `config.user_attachment_invalid`). ABSENT = server <= 7.132.x: fall back to `userAttachments.supplies` plus the existing 400 handling.' }
|
|
7067
7164
|
unavailableReason: { type: string, description: 'machine-readable reason, present ONLY when available:false (absent = no reason). Closed set, currently the single member `git_client_unconfigured`; branch on the key, never match the English prose. Additive-open: treat an unknown word as "unavailable, reason unknown".' }
|
|
7068
7165
|
|
|
7069
7166
|
RunStatus:
|
|
@@ -7704,11 +7801,20 @@ components:
|
|
|
7704
7801
|
`permissions.defaultMode`'s specific fold is documented on `TaskRequest.permissionMode`.
|
|
7705
7802
|
🔴 ON THIS SUBMIT FACE THE KEY SET IS CLOSED (server >= 7.57.0 for the sub-tree): accepted top-level keys
|
|
7706
7803
|
are `env` / `hooks` / `model` / `outputStyle` / `permissions` / `skillListingBudgetFraction` /
|
|
7707
|
-
`skillListingMaxDescChars` / `ultracode` / `webSearch
|
|
7708
|
-
`allow` / `ask` / `defaultMode` / `deny` / `disableAutoMode
|
|
7804
|
+
`skillListingMaxDescChars` / `ultracode` / `webSearch` (server >= 7.133.0 adds the three TIGHTEN-ONLY seats `complianceAdditionalDenies` / `readDenyPatterns` / `writeProtectedExtra`), and accepted `permissions.*` keys are
|
|
7805
|
+
`allow` / `ask` / `defaultMode` / `deny` / `disableAutoMode` (server >= 7.133.0 adds `neverAuto`); anything else is 400 `request.body_shape`
|
|
7709
7806
|
with the names in the refusal's `unknownKeys` / `unsupportedKeys` arrays (REFUSED, not dropped — a dropped
|
|
7710
7807
|
key reads as "in effect" to the caller). The object stays OPEN here because the same `SemaSettings`
|
|
7711
7808
|
schema also serves the local `settings.json` wiring, where deferred CC keys are legal.
|
|
7809
|
+
🔴 TIGHTEN-ONLY SEATS (server >= 7.133.0; probe `capabilities.taskSettings.tightenOnlySeats`, an absent bit = an older server that answers 400 `request.body_shape` for these four keys): `readDenyPatterns` (entries: a bare
|
|
7810
|
+
pattern string, or `{ pattern, caseSensitive? }`), `writeProtectedExtra` (a bare name — no `/` reads as `segment`, a `/` reads as `segment-run` — or `{ name, kind: basename | segment | segment-run }`),
|
|
7811
|
+
`complianceAdditionalDenies` (`mcp_servers` | `workflows` | `web_fetch` | `org_memory_mount`) and `permissions.neverAuto` (tool names that ALWAYS ask a human). Each seat = the deployment table UNION the request list, ONLY EVER GROWING
|
|
7812
|
+
(the request face has no loosening arm); an empty array is the same as not sent. Bad value => 400 `request.field_invalid` with `field` + `reason` (`over_cap` + `count` + `cap` / `bad_entry` + the first bad `index`).
|
|
7813
|
+
Caps: 1000 entries per seat, EXCEPT `readDenyPatterns`: at most 32 entries, at most 2 `*` per path segment and 16 `*` in the whole table (every star counts, nothing is folded). A `neverAuto` name that can never match any tool => 422.
|
|
7814
|
+
A resume replay of a stored body whose seat went bad => 409 `resume_blocked_by_policy`. A compliance deny is a REFUSAL, not a narrowing: a request denying `web_fetch` is refused whole where the default tool surface still mounts `WebFetch` (the single-user default does).
|
|
7815
|
+
🔴 `settings.hooks[]` (server >= 7.133.0; probe `capabilities.taskSettings.pluginHooks` / `managedHookGroups` — an absent or false bit = the keys are STRIPPED SILENTLY): group key `source` (closed: `managedPolicy` / `user` / `project` / `local` / `flag` /
|
|
7816
|
+
`managedPlugin:<name>` / `plugin:<name>`; absent = unmanaged; managed groups run in an independent lane after the unmanaged rewrites), command-entry keys `plugin { name, root, dataDir?, options? }` and exec-form `args`; a malformed one =>
|
|
7817
|
+
400 `request.field_invalid` with `detail: { reason: "wire_key_invalid", key, path }`; the plugin context has one 8192-character budget.
|
|
7712
7818
|
🔴 `skillListingBudgetFraction` (number in (0,1]) / `skillListingMaxDescChars` (positive integer),
|
|
7713
7819
|
server >= 7.78.1: the SKILL-LISTING RENDER BUDGET, passed to the engine with ZERO processing
|
|
7714
7820
|
(no clamping, no conversion, no folding) — ABSENT means the key is not written at all (the server does
|
|
@@ -8374,6 +8480,10 @@ components:
|
|
|
8374
8480
|
cause (`terminal`), not the eight parallel plane keys — see `TerminalCause`.
|
|
8375
8481
|
required: [taskId, sessionId, terminal, stats]
|
|
8376
8482
|
properties:
|
|
8483
|
+
warnings:
|
|
8484
|
+
type: array
|
|
8485
|
+
items: { $ref: '#/components/schemas/EntryProblem' }
|
|
8486
|
+
description: 'server >= 7.133.0, top level of the sync `POST /v1/tasks` 200 body (beside `notice`), present only when non-empty: the accept-time NOTICES for allow-side selector-list entries the engine reads as nothing or that are not in the roster. ABSENT = no notice (older servers too).'
|
|
8377
8487
|
taskId: { type: string }
|
|
8378
8488
|
sessionId: { type: string }
|
|
8379
8489
|
wiringManifest:
|
|
@@ -8676,6 +8786,10 @@ components:
|
|
|
8676
8786
|
taskId: { type: string }
|
|
8677
8787
|
sessionId: { type: string }
|
|
8678
8788
|
status: { $ref: '#/components/schemas/RunStatus' }
|
|
8789
|
+
warnings:
|
|
8790
|
+
type: array
|
|
8791
|
+
items: { $ref: '#/components/schemas/EntryProblem' }
|
|
8792
|
+
description: 'server >= 7.133.0, present only when non-empty: the accept-time NOTICES for allow-side selector-list entries the engine reads as nothing or that are not in the roster (acceptance is unchanged — the engine takes them, only the operator hears afterwards; this makes "this name will not take effect" visible at the call). Same list as the stream `meta` frame''s and the sync 200 body''s. ABSENT = no notice (older servers too).'
|
|
8679
8793
|
|
|
8680
8794
|
SealedKeyCapability:
|
|
8681
8795
|
type: object
|
|
@@ -9657,6 +9771,16 @@ components:
|
|
|
9657
9771
|
a child process spawned on this host NEVER inherits a name the deployment declared as its own credential — every `inheritEnv` policy (`"all"` and `"scrub"` alike) subtracts that list first, and an allow list naming one is
|
|
9658
9772
|
refused. It speaks of INHERITANCE only (the engine process's own environment stays readable to same-user processes on the host; a credential that never enters it remains the root fix).
|
|
9659
9773
|
ABSENT = an old server (<= 7.128.x) or a word this deployment does not wire: read it as "not promised", not as "absent capability". A shell gates on the word, never on a version number.
|
|
9774
|
+
inherit_env.own_credential_values_withheld:
|
|
9775
|
+
type: boolean
|
|
9776
|
+
description: >-
|
|
9777
|
+
ENGINE CAPABILITY WORD (core `ENGINE_CAPABILITIES`' second word, core 7.52.0; server >= 7.132.0 projects it; the key IS the word, dotted):
|
|
9778
|
+
a child process spawned on this host does NOT inherit a variable whose VALUE equals one of this deployment's credential values (whole-string equality, whatever
|
|
9779
|
+
the variable is called) — a key copied into another variable name is withheld under `inheritEnv: "all"` too. 🔴 A FACT, not a promise — it can be `false`:
|
|
9780
|
+
true <=> every credential variable of the live configuration that has a value in the environment went into the engine's value arm; the engine refuses a value it
|
|
9781
|
+
reads as "not a credential" (blank / a placeholder word / one repeated character / under 8 characters) or "the value of a variable every child process gets"
|
|
9782
|
+
(startup does not refuse; the name arm still withholds) => `false`. A credential resolved only per request is not in the value arm. INHERITANCE only, like the first word.
|
|
9783
|
+
ABSENT = an old server (<= 7.131.x withholds by name only — a same-value copy under another name reaches the child under `"all"`). Gate on `=== true`.
|
|
9660
9784
|
asyncRuns: { type: boolean }
|
|
9661
9785
|
artifacts: { type: boolean }
|
|
9662
9786
|
approvals: { type: boolean }
|
|
@@ -9793,6 +9917,11 @@ components:
|
|
|
9793
9917
|
store backend deliberately wires no image index (the pool is cloud/fleet-only) ⇒ false there.
|
|
9794
9918
|
SCOPE: P1 only — `/v1/images/bakes*` (the P2 bake control plane) is a separate dependency and an
|
|
9795
9919
|
operator/runner-internal face, NOT promised by this bit.
|
|
9920
|
+
principalInboxDelivery:
|
|
9921
|
+
type: boolean
|
|
9922
|
+
description: >-
|
|
9923
|
+
server >= 7.133.0 — the cross-principal delivery door `POST /v1/principal-inbox/messages` is wired (delivery gate present: env `PRINCIPAL_INBOX_ASSISTANT` on and the gate's dependencies in place).
|
|
9924
|
+
True iff that route works; absent gate => the route answers 501 `capability.unavailable`. ABSENT key = server <= 7.132.x (no such route; routing-level 404). Probe this bit; do not trial-by-501.
|
|
9796
9925
|
sharedMemory:
|
|
9797
9926
|
type: boolean
|
|
9798
9927
|
description: >
|
|
@@ -9963,6 +10092,12 @@ components:
|
|
|
9963
10092
|
lane) or 422 (hosted).
|
|
9964
10093
|
mcp: { type: boolean, description: "MCP servers can be attached." }
|
|
9965
10094
|
mcpInjection: { type: boolean, description: "Per-request MCP injection is accepted." }
|
|
10095
|
+
mcpAssertionHeaderSent:
|
|
10096
|
+
type: boolean
|
|
10097
|
+
description: >-
|
|
10098
|
+
server >= 7.133.0 — the SEND seat self-report (a boolean, today ALWAYS `false`): whether `mcpServers[].transport.assertionHeader` (accepted since server 7.128.0, mutually exclusive with `principalHeader`)
|
|
10099
|
+
is actually SENT to the MCP peer. `false` = the declaration is carried but NOT sent (the same switch drives the key stripping, the operator info line and the probe-door refusal; the disclosure sentences leave when it turns true).
|
|
10100
|
+
ABSENT = an older server, which does not send either — treat it as `false`; never rely on the header for peer authentication.
|
|
9966
10101
|
mcpProbe:
|
|
9967
10102
|
type: boolean
|
|
9968
10103
|
description: >
|
|
@@ -10002,6 +10137,17 @@ components:
|
|
|
10002
10137
|
⚠️ ABSENT = an older server (<7.87.1) ⇒ cannot tell whether the push face carries the live family;
|
|
10003
10138
|
do NOT read "no `live_pending` frame arrived yet" as "this deployment never pushes live" — the two
|
|
10004
10139
|
are indistinguishable on an older server. Fall back to `GET /v1/approvals`'s `livePending` pull face.
|
|
10140
|
+
approvalFrameFamilies:
|
|
10141
|
+
type: array
|
|
10142
|
+
maxItems: 1
|
|
10143
|
+
items: { type: string, enum: [tool_approval, approval_request] }
|
|
10144
|
+
description: >-
|
|
10145
|
+
server >= 7.133.0, ALWAYS present (the projection of the same judgement as `streamApproval`) — which FRAME FAMILY this worker's approval opening frames belong to:
|
|
10146
|
+
a closed-word array with AT MOST ONE member. `["approval_request"]` = the card protocol is on: one ask travels only `approval_request` -> `approval_complete` / `approval_revoke`
|
|
10147
|
+
(the legacy `tool_approval` / `tool_approval_complete` pair is NOT sent — BREAKING vs <= 7.132.x, which sent both families for one ask and relied on `approvalId` de-duplication;
|
|
10148
|
+
remedy on the worker: `STREAM_APPROVAL_ENABLED=false`). `["tool_approval"]` = the card protocol is not on (`STREAM_APPROVAL_ENABLED=false`, no store backend, or no checkpoint store) but the live card leg is.
|
|
10149
|
+
`[]` = per-call approvals are off altogether (`TOOL_APPROVAL_ENABLED=false`): no card is presented. Dispatch frame families off THIS array, never off `streamApproval`.
|
|
10150
|
+
KEY ABSENT (not `[]`) = server <= 7.132.x — there a `streamApproval: true` leg sends BOTH families for one ask.
|
|
10005
10151
|
streamApproval:
|
|
10006
10152
|
type: boolean
|
|
10007
10153
|
description: >
|
|
@@ -10056,6 +10202,13 @@ components:
|
|
|
10056
10202
|
a server <= 7.118.x returns the archive as written; a 7.119.x server already redacts but does not report the bit. A true
|
|
10057
10203
|
bit does not mean the read face exists (that is `sessions`; without a session audit face that door answers 501 and this
|
|
10058
10204
|
bit is still true), nor that the archive holds no credential (the redaction is read-side only).
|
|
10205
|
+
approvalReadRootGrant:
|
|
10206
|
+
type: boolean
|
|
10207
|
+
description: >-
|
|
10208
|
+
server >= 7.133.0, ALWAYS present, a FACT that varies by deployment — whether this deployment accepts the reply-body key `readRootGrant` ("Yes, and add directory": the card's
|
|
10209
|
+
`readRootCandidate.dir` is registered as a read root together with this one allow). True iff the single-user host-lane posture (the same predicate as `projectContext` / the cwd face); false elsewhere.
|
|
10210
|
+
A client shows the option only when the card carries `readRootCandidate` AND this bit is true. On a non-accepting posture a reply carrying `readRootGrant` is refused
|
|
10211
|
+
`400 request.body_shape` (the ask stays unsettled — answer again without the key). ABSENT = server <= 7.132.x = not accepted; do not send the key.
|
|
10059
10212
|
approvalReach:
|
|
10060
10213
|
type: boolean
|
|
10061
10214
|
description: >-
|
|
@@ -10168,6 +10321,9 @@ components:
|
|
|
10168
10321
|
outputStyle: { type: boolean }
|
|
10169
10322
|
env: { type: boolean, description: 'TRUE on the single-user host lane (server emits `cwdHonored(config)`). It is NOT hard-coded false any more — the old always-false value predated the per-task shellEnv seam and hid a live capability.' }
|
|
10170
10323
|
hooks: { type: boolean, description: 'Single-user deployments only (`requirePrincipal !== true`).' }
|
|
10324
|
+
pluginHooks: { type: boolean, description: 'server >= 7.133.0 — the request `settings.hooks[]` PLUGIN-CONTEXT keys (command entry `plugin { name, root, dataDir?, options? }` / exec-form `args`) are accepted; same predicate as `hooks` (single-user true, multi-tenant false). ABSENT or false = the keys are stripped silently — send only on sight of the bit.' }
|
|
10325
|
+
managedHookGroups: { type: boolean, description: 'server >= 7.133.0 — the request `settings.hooks[]` GROUP `source` key (managed lanes `managedPolicy` / `managedPlugin:<name>`) is accepted; same predicate as `hooks`. ABSENT or false = stripped silently (the managed-lane semantics do not apply, it is not a refusal).' }
|
|
10326
|
+
tightenOnlySeats: { type: boolean, description: 'server >= 7.133.0, constant true — the four tighten-only request seats `settings.readDenyPatterns` / `settings.writeProtectedExtra` / `settings.complianceAdditionalDenies` / `settings.permissions.neverAuto` are accepted (each seat = deployment table UNION request list, only ever growing; an empty array is the same as not sent). ABSENT = server <= 7.132.x, which answers 400 `request.body_shape` for those keys — send only on sight of the bit.' }
|
|
10171
10327
|
settings:
|
|
10172
10328
|
type: object
|
|
10173
10329
|
description: >
|
|
@@ -10196,6 +10352,7 @@ components:
|
|
|
10196
10352
|
properties:
|
|
10197
10353
|
allowGrant: { type: boolean, description: 'Constant `true` on server >= 7.115.0: `settings.permissions.allow` is read as allow RULES, not as a list. The whole `settings` key being absent = an older server.' }
|
|
10198
10354
|
allowLayer: { type: boolean, description: 'Constant `true` on server >= 7.117.0 (core 7.42.0): the whole `settings.permissions.allow` list goes to the engine allow layer (listed calls are not asked; content forms accepted; entries read as nothing get an `engine_notice` `permission.allowed_tool_not_granted`). Absent = a server without it (7.115.0–7.116.x: allow is a statement; older: a list).' }
|
|
10355
|
+
callerTrust: { type: string, description: 'server >= 7.133.0 — THIS caller''s trust tier (per caller / per credential, NOT a version bit). Request rule tables that take effect without a person answering (`settings.permissions` buckets; a named-invoked skill''s `allowedTools` / `disallowedTools`) are admitted by it: `allow` loosens the no-ask surface and needs `global`; `deny` / `ask` only tighten and are admitted at any tier. Today `global` (single-user turnkey; multi-tenant with the deployment service credential; multi-tenant sign-in token whose scope role >= the governance write role) or `project` (everything else). Read OPEN: an unknown word is treated as `project` (fail-closed). A request below the floor is refused whole with 400 `request.field_invalid` (`detail.problems[].reason: below_trust_floor`, `detail.callerTrust`). ABSENT = server <= 7.132.x: no per-tier admission.' }
|
|
10199
10356
|
memoryWrite:
|
|
10200
10357
|
type: boolean
|
|
10201
10358
|
description: >
|
|
@@ -10258,7 +10415,7 @@ components:
|
|
|
10258
10415
|
additionalProperties: true
|
|
10259
10416
|
properties:
|
|
10260
10417
|
enabled: { type: boolean, enum: [true] }
|
|
10261
|
-
protocolVersion: { type: integer }
|
|
10418
|
+
protocolVersion: { type: integer, description: 'The protocol REVISION this server speaks (the `challenge` frame carries the same value; accepted window [1, 2] on server >= 7.133.0). Server >= 7.133.0 reads 2 (<= 7.132.x read 1). An executor declares the SMALLER of its own highest revision and this value, and takes its outcome-code set from the declared revision (revision 2 added `liveness_no_output`).' }
|
|
10262
10419
|
maxInflightPerDevice: { type: integer }
|
|
10263
10420
|
wsPath: { type: string }
|
|
10264
10421
|
management: { type: boolean, description: 'server >= 7.88.0. `/v1/devices/*` admin verbs present. PRESENT-IFF — absent means a pre-7.88.0 peer (unknown), not false.' }
|
|
@@ -10752,9 +10909,9 @@ components:
|
|
|
10752
10909
|
server >= 7.65.0 (S-167) — the READ containment rung of this deployment AND WHO SET IT (operator face
|
|
10753
10910
|
`GET /v1/diagnostics/wiring` -> `readFace`). `face` is the same boot artefact as the tenant-facing
|
|
10754
10911
|
`capabilities.readFace` (`null` = nothing pinned by this deployment, the engine default is in force).
|
|
10755
|
-
`source` is a CLOSED
|
|
10912
|
+
`source` is a CLOSED five-word set on the server (exhaustive switch — adding a word is a compile error
|
|
10756
10913
|
there): `env` = this machine's READ_FACE env var (wins over everything) · `center` = the config-center
|
|
10757
|
-
readFace domain (restart-to-apply) · `posture` = derived from the single-user turnkey posture
|
|
10914
|
+
readFace domain (restart-to-apply) · `lane` = (server >= 7.133.0) the isolated execution lane's default — with `READ_FACE` absent, e2b / k8s / local-docker mint `open` · `posture` = derived from the single-user turnkey posture
|
|
10758
10915
|
(REQUIRE_PRINCIPAL unset ⇒ `open`; server >= 7.65.0 behaviour change) · `engine-default` = not pinned.
|
|
10759
10916
|
`note` is a human-facing pointer for operators. Minimal disclosure: the deny table is never on this face.
|
|
10760
10917
|
required: [face, source, note]
|
|
@@ -10764,7 +10921,7 @@ components:
|
|
|
10764
10921
|
enum: [open, roots, null]
|
|
10765
10922
|
source:
|
|
10766
10923
|
type: string
|
|
10767
|
-
enum: [env, center, posture, engine-default]
|
|
10924
|
+
enum: [env, center, lane, posture, engine-default]
|
|
10768
10925
|
note:
|
|
10769
10926
|
type: string
|
|
10770
10927
|
|
|
@@ -10781,9 +10938,9 @@ components:
|
|
|
10781
10938
|
`DURABLE_APPROVAL` ON and a 24h approval window when neither is set, so a default FLIP has to be visible
|
|
10782
10939
|
on an operator surface or nobody sees it.
|
|
10783
10940
|
|
|
10784
|
-
`source` is the CLOSED
|
|
10941
|
+
`source` is the CLOSED five-word set (exhaustive switch on the server — adding a word is a compile error
|
|
10785
10942
|
there), in PRECEDENCE order: `env` = pinned by this machine's env var (deployment sovereignty; beats any
|
|
10786
|
-
published value) · `center` = applied from the config-center (restart-to-apply) · `posture` = derived from
|
|
10943
|
+
published value) · `center` = applied from the config-center (restart-to-apply) · `lane` = (server >= 7.133.0) derived from the isolated execution lane (e2b / k8s / local-docker mint a lane default, e.g. `READ_FACE` -> `open`) · `posture` = derived from
|
|
10787
10944
|
the deployment shape (single-user turnkey) · `engine-default` = nothing pinned, the built-in default is in
|
|
10788
10945
|
force. Only `env`/`center` count as "an operator asked for this"; a posture-derived `true` does not.
|
|
10789
10946
|
`note` is PROSE for a human (per-knob, and on the `posture` arm it is that knob's own fact sentence) —
|
|
@@ -10798,7 +10955,7 @@ components:
|
|
|
10798
10955
|
description: 'The knob''s effective value. Typed by the referencing site (boolean / integer / …).'
|
|
10799
10956
|
source:
|
|
10800
10957
|
type: string
|
|
10801
|
-
enum: [env, center, posture, engine-default]
|
|
10958
|
+
enum: [env, center, lane, posture, engine-default]
|
|
10802
10959
|
note: { type: string }
|
|
10803
10960
|
|
|
10804
10961
|
SkillSpec:
|
|
@@ -10892,7 +11049,19 @@ components:
|
|
|
10892
11049
|
`principalHeader` (both set => 400 request.body_shape); a non-string value => 400 request.field_invalid.
|
|
10893
11050
|
7.128.x accepts and carries the declaration but does NOT send an assertion yet (engine seat pending;
|
|
10894
11051
|
operator line `mcp_assertion_header_not_sent`).
|
|
10895
|
-
allowTools:
|
|
11052
|
+
allowTools:
|
|
11053
|
+
type: array
|
|
11054
|
+
items: { type: string }
|
|
11055
|
+
description: >-
|
|
11056
|
+
Which of this server's tools to MOUNT (bare tool names, as the server lists them). Three sentences (server >= 7.132.0 contract; read off the engine's
|
|
11057
|
+
`intakeListedTools`, passed through verbatim, never checked against the live list): ABSENT = every listed tool mounts; `[]` = NONE mounts (the server is
|
|
11058
|
+
still connected, still probed, still on the `GET /v1/capabilities/mcp` status face) — `[]` MUST NOT be folded into absence (two facts on the wire;
|
|
11059
|
+
do not drop an empty array when serializing); a name the server does not list = SILENTLY NO MATCH (no 400, no warning — a narrowing mismatch mounts
|
|
11060
|
+
less, never more; for "loud on a typo" name the same tool in `toolFaces`, which notices an unknown name as `config.tool_face_undeclared`; `toolAxes`
|
|
11061
|
+
checks shape only). The engine's one loud case: a server without the `tools` capability and a non-empty list ⇒ operator warning
|
|
11062
|
+
`mcp.tools_capability_absent`. The list also gates the server's MCP RESOURCES: absent ⇒ list / read stay open; a list ⇒ open only if it names the
|
|
11063
|
+
reserved `list_resources` / `read_resource` (so `[]` closes them too). Bad shape (not a string array) ⇒ 400 `request.field_invalid` naming
|
|
11064
|
+
`mcpServers[i].allowTools`.
|
|
10896
11065
|
elicitation: { type: boolean }
|
|
10897
11066
|
toolAxes:
|
|
10898
11067
|
type: object
|
|
@@ -10908,6 +11077,15 @@ components:
|
|
|
10908
11077
|
server >= 7.66.0 — per-tool face overlays keyed by BARE tool name (see McpToolFace). Any malformed
|
|
10909
11078
|
face drops the whole server.
|
|
10910
11079
|
additionalProperties: { $ref: '#/components/schemas/McpToolFace' }
|
|
11080
|
+
startupTimeoutMs:
|
|
11081
|
+
type: number
|
|
11082
|
+
description: >-
|
|
11083
|
+
server >= 7.132.0 (an accepted key; core `McpServerSpec.startupTimeoutMs`): THIS server's startup bound in whole milliseconds — the handshake
|
|
11084
|
+
(connect + initialize) and the initial tool listing each carry it. One read order: this member, else the process-level `MCP_TIMEOUT`, else the MCP
|
|
11085
|
+
SDK's own 60 000 ms. Range 1 000 – 2 147 483 647. The value-shape judge lives ONLY in the engine: neither server door (new submit / probe) checks
|
|
11086
|
+
it at intake; a bad value (a string, a fraction, 0, a negative, NaN, `null`, out of range) refuses ONLY THIS server at its dial
|
|
11087
|
+
(`config.mcp_startup_timeout_invalid`; siblings mount) — never clamped, never read as the default. A <= 7.131.x server answers `400
|
|
11088
|
+
request.body_shape` (named in `unknownKeys`).
|
|
10911
11089
|
|
|
10912
11090
|
A2aServerSpec:
|
|
10913
11091
|
type: object
|
|
@@ -11599,6 +11777,24 @@ components:
|
|
|
11599
11777
|
`"other"`). This is the "where did those 180 404s actually land" cell. Empty object = zero failures;
|
|
11600
11778
|
key absent = an older server.
|
|
11601
11779
|
|
|
11780
|
+
ModelPlane:
|
|
11781
|
+
type: object
|
|
11782
|
+
additionalProperties: false
|
|
11783
|
+
description: >
|
|
11784
|
+
`GET /v1/models.modelPlane` (server >= 7.133.0; always present; conditional keys are absent, never `null` / empty string) — the single read for "which model table is this engine serving".
|
|
11785
|
+
Two axes. SERVED TABLE: `servedTable` = `env` (the env table minted from MODEL_ID / MODEL_CHEAP_ID — no catalog is in charge: none configured / source unreachable with no last-known-good / the candidate was refused /
|
|
11786
|
+
no enabled entry) | `catalog` (a catalog's model plane landed and replaced the whole env table). CANDIDATE OUTCOME: `catalog` = `refused` (the latest candidate was refused whole — by the candidate judge or the model-plane
|
|
11787
|
+
group; with no previous generation the env table serves, with one the catalog table still serves — who serves is `servedTable`'s answer, NOT merged into this field) | `adopted` (no whole refusal and the catalog table
|
|
11788
|
+
serves; NOT "the latest candidate landed" — that question belongs to the /health generation ledger) | `absent` (no whole refusal and the env table serves). START-UP ROUTE VERDICT: `refusalCode` / `gap` (both ABSENT when the
|
|
11789
|
+
judge passes — the normal state of a running process): `refusalCode` = `config.model_route_endpoint_missing` | `config.gateway_fallback_without_primary`; `gap` = `endpoint_missing` (set MODEL_GATEWAY_BASEURL or the entry's
|
|
11790
|
+
own `baseUrl`) | `lane_credential_missing` (an anthropic-lane choice with neither ANTHROPIC_API_KEY nor ANTHROPIC_AUTH_TOKEN fell into the endpoint-less openai leg). No sentence is carried. Words are server-owned — read OPEN
|
|
11791
|
+
(an unknown word is "unknown", never "passed").
|
|
11792
|
+
required: [servedTable, catalog]
|
|
11793
|
+
properties:
|
|
11794
|
+
servedTable: { type: string, description: '`env` | `catalog` (open on read).' }
|
|
11795
|
+
catalog: { type: string, description: '`absent` | `adopted` | `refused` (open on read).' }
|
|
11796
|
+
refusalCode: { type: string, description: '`config.model_route_endpoint_missing` | `config.gateway_fallback_without_primary` (open on read); ABSENT = the judge passed.' }
|
|
11797
|
+
gap: { type: string, description: '`endpoint_missing` | `lane_credential_missing` (open on read); ABSENT = the judge passed.' }
|
|
11602
11798
|
ModelsResponse:
|
|
11603
11799
|
type: object
|
|
11604
11800
|
description: >
|
|
@@ -11646,6 +11842,11 @@ components:
|
|
|
11646
11842
|
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
|
|
11647
11843
|
enabled; while serving from it with the center still unreachable this key lists only those rows (possibly `[]`) and the first pull after the
|
|
11648
11844
|
center is reachable fills it in. An unknown `reasonCode` word reads as "dropped, reason unknown".
|
|
11845
|
+
modelPlane:
|
|
11846
|
+
allOf: [{ $ref: '#/components/schemas/ModelPlane' }]
|
|
11847
|
+
description: >-
|
|
11848
|
+
server >= 7.133.0, ALWAYS present there (appended last): which model table this engine SERVES, whether the catalog was adopted, and what the start-up route judge says — read this instead of predicting
|
|
11849
|
+
(the judge's inputs are the serving process's facts; mirroring two of its judgements drifts). ABSENT = an earlier server (<= 7.132.x). Field reading: ModelPlane.
|
|
11649
11850
|
candidateRejected:
|
|
11650
11851
|
allOf: [{ $ref: '#/components/schemas/CandidateRejected' }]
|
|
11651
11852
|
description: >
|
|
@@ -11836,12 +12037,16 @@ components:
|
|
|
11836
12037
|
x-open-enum: true
|
|
11837
12038
|
description: >-
|
|
11838
12039
|
A model row's key<->URL pairing posture (core `RoutePairingStatus`; server >= 7.45). OPEN on read —
|
|
11839
|
-
the
|
|
12040
|
+
the eight words below are today's set (core `RoutePairingStatus`), branch on the known ones and keep a `default` arm. NON-SECRET — no
|
|
11840
12041
|
URL, no credential.
|
|
11841
12042
|
`ok:per-model` this model has its own credential · `ok:paired` deployment credential, and the model's URL
|
|
11842
12043
|
is on the deployment's declared root · `ok:keyless` no credential anywhere (a local unauthenticated
|
|
11843
12044
|
gateway) · `broken:credential_mismatch` / `broken:credential_missing` a real request WILL be refused by
|
|
11844
|
-
the engine (flag it red) ·
|
|
12045
|
+
the engine (flag it red) · server >= 7.132.0 / engine 7.52.0 adds two `broken:` words, same reading:
|
|
12046
|
+
`broken:credential_origin_mismatch` (this model's own credential is bound to the host it first went to and the row now points at another
|
|
12047
|
+
host — configure a credential for the new host or point it back; the same refusal on a stream is the `engine_notice`
|
|
12048
|
+
`route.credential_origin_mismatch`) and `broken:credential_answer_conflict` (the per-model credential hook answers the key twice — `apiKey`
|
|
12049
|
+
AND the lane's own key header; answer one of them) · `unknown` could not be adjudicated — render "unknown", NEVER "good" or "bad".
|
|
11845
12050
|
🔴 sdk 23.0.0 BREAKING (server >= 7.129.0 / engine 7.51.0): `ok:unpinned` (a deployment credential on a deployment that declared no root, so the pairing was unverifiable) is RETIRED with no alias —
|
|
11846
12051
|
on such a deployment the engine now judges the deployment credential `broken:credential_mismatch`. A server <= 7.128.x still sends `ok:unpinned`: it falls in the open tail, render it as
|
|
11847
12052
|
"pairing not verified", never as good.
|
|
@@ -11851,11 +12056,11 @@ components:
|
|
|
11851
12056
|
|
|
11852
12057
|
ResumeStartupCause:
|
|
11853
12058
|
type: string
|
|
11854
|
-
enum: [environment, session_gone, tool_unavailable, configuration, decision_rejected]
|
|
12059
|
+
enum: [environment, session_gone, transcript_corrupt, tool_unavailable, configuration, decision_rejected]
|
|
11855
12060
|
description: >-
|
|
11856
|
-
WHY a parked resume could not start its approved action — the engine's closed `RESUME_STARTUP_CAUSES` (core 7.51.0), word for word and in order. The body key of the 422 `parked_resume.startup_failed`
|
|
12061
|
+
WHY a parked resume could not start its approved action — the engine's closed `RESUME_STARTUP_CAUSES` (core 7.51.0; six words since core 7.52.0, server >= 7.132.0), word for word and in order. The body key of the 422 `parked_resume.startup_failed`
|
|
11857
12062
|
(`ErrorResponse.cause`; SDK `ParkedResumeStartupError.startupCause`). Server >= 7.129.0 screens the engine's word against this set before it goes out (a word the engine did not say, or one outside the set => the key is absent).
|
|
11858
|
-
`environment` the leg's infrastructure failed (workspace restore, an abort) — the decision is untouched, retrying replays it · `session_gone` the resumed agent's transcript session is missing ·
|
|
12063
|
+
`environment` the leg's infrastructure failed (workspace restore, an abort) — the decision is untouched, retrying replays it · `session_gone` the resumed agent's transcript session is missing · `transcript_corrupt` (core 7.52.0) the transcript is there but damaged (no header its store wrote, a leaf or parent entry missing, a lost tail the checkpoint was cut inside) — it reopens as `session_gone` does, only the receipt now names it ·
|
|
11859
12064
|
`tool_unavailable` the approved tool is not available to the resumed leg (gone, or replaced by a different contract) — this approval cannot run, decide afresh · `configuration` the deployment's
|
|
11860
12065
|
configuration refuses the resumed leg; a retry under the same configuration fails the same way · `decision_rejected` the decision does not fit the checkpoint (another gate's answer, an input the constraints
|
|
11861
12066
|
refuse) — correct it and resubmit. The shared `ErrorResponse.cause` stays an open string in this document because the key is shared by other codes and by servers <= 7.128.x (which relay the engine's word unscreened).
|
|
@@ -12863,14 +13068,14 @@ components:
|
|
|
12863
13068
|
ts: { type: integer }
|
|
12864
13069
|
FleetFrame_hook_notice:
|
|
12865
13070
|
description: >
|
|
12866
|
-
Hook observability frame,
|
|
13071
|
+
Hook observability frame, FOUR kinds (server >= 7.133.0 added the third and fourth; all pure observe — never block, resume, or inject anything;
|
|
12867
13072
|
visibility fail-CLOSED like bg_notification: the owner keys ownerScope/ownerSessionId gate delivery
|
|
12868
13073
|
and are STRIPPED before send; wire is FLAT — `send("hook_notice", { type, ...wire, ts })`, the
|
|
12869
13074
|
server-internal `{notice}` nesting never reaches it). codex R1-F4: modeled as the discriminated union
|
|
12870
13075
|
it really is — the common `{type, ts}` frame base composed with each kind's payload arm — so a
|
|
12871
13076
|
generated client gets the SAME per-kind narrowing as the TS type (a second-family frame missing
|
|
12872
|
-
hookName/entryType is invalid, not silently accepted). `kind` is CLOSED
|
|
12873
|
-
OPEN ON READ: degrade an unknown future kind to a generic observability row.
|
|
13077
|
+
hookName/entryType is invalid, not silently accepted). `kind` is CLOSED four-member on the server but
|
|
13078
|
+
OPEN ON READ: degrade an unknown future kind to a generic observability row. DISPATCH on `kind`; never infer a call's outcome from any hook_notice frame (read the tool / approval frames).
|
|
12874
13079
|
oneOf:
|
|
12875
13080
|
- allOf:
|
|
12876
13081
|
- $ref: '#/components/schemas/FleetHookNoticeFrameBase'
|
|
@@ -12878,10 +13083,16 @@ components:
|
|
|
12878
13083
|
- allOf:
|
|
12879
13084
|
- $ref: '#/components/schemas/FleetHookNoticeFrameBase'
|
|
12880
13085
|
- $ref: '#/components/schemas/FleetHookNonBlockingFailure'
|
|
13086
|
+
- allOf:
|
|
13087
|
+
- $ref: '#/components/schemas/FleetHookNoticeFrameBase'
|
|
13088
|
+
- $ref: '#/components/schemas/FleetHookManagedUnrun'
|
|
13089
|
+
- allOf:
|
|
13090
|
+
- $ref: '#/components/schemas/FleetHookNoticeFrameBase'
|
|
13091
|
+
- $ref: '#/components/schemas/FleetHookVerdictUntrusted'
|
|
12881
13092
|
|
|
12882
13093
|
FleetHookNoticeFrameBase:
|
|
12883
13094
|
type: object
|
|
12884
|
-
description: 'The hook_notice frame envelope shared by
|
|
13095
|
+
description: 'The hook_notice frame envelope shared by all four kinds: the SSE frame discriminant and the server timestamp.'
|
|
12885
13096
|
required: [type, ts]
|
|
12886
13097
|
properties:
|
|
12887
13098
|
type: { const: hook_notice }
|
|
@@ -12930,7 +13141,7 @@ components:
|
|
|
12930
13141
|
# #315(server ≥7.43):第二顶层键 `livePending` = streamApproval 窗内的流内 ask(此前对轮询消费端
|
|
12931
13142
|
# 结构性不可见)。ADDITIVE / tolerate-absent:键缺席=「协调器未装配(本部署无 live 审批面)」或
|
|
12932
13143
|
# 旧 server;空数组=「有面、此刻无待批」——两义可判别,消费端测 presence。**分数组不混编**:
|
|
12933
|
-
# live 行的决议口=POST /v1/tool-approvals/{
|
|
13144
|
+
# live 行的决议口=POST /v1/tool-approvals/{id}/respond,durable 行=decide 口;数组名即路由判据。
|
|
12934
13145
|
# 22.0.0:第三、四顶层键此前漏声明 —— 封闭 schema 上一个真键 = 合法信封被严格校验器拒收。
|
|
12935
13146
|
additionalProperties: false
|
|
12936
13147
|
required: [pending]
|
|
@@ -12985,7 +13196,7 @@ components:
|
|
|
12985
13196
|
type: object
|
|
12986
13197
|
description: >-
|
|
12987
13198
|
A live (in-stream) pending ask inside its streamApproval window (#315, server ≥7.43). Decide it via
|
|
12988
|
-
POST /v1/tool-approvals/{
|
|
13199
|
+
POST /v1/tool-approvals/{id}/respond — NOT the /decide route (that is the durable rows' door).
|
|
12989
13200
|
Optional flags are only-if-true (absent is NEVER encoded as false).
|
|
12990
13201
|
🔴 THE "tool input/args are NOT listed" NARROWING IS GONE (server >= 7.87.0 / S-454 P1). The old reason
|
|
12991
13202
|
was "details ride the stream frame" — but a SUSPENDED ask never has a stream frame (at mint time it had
|
|
@@ -13003,7 +13214,15 @@ components:
|
|
|
13003
13214
|
additionalProperties: true
|
|
13004
13215
|
required: [approvalId, toolName, ts, expiresAtMs]
|
|
13005
13216
|
properties:
|
|
13006
|
-
approvalId: { type: string, description: 'The SAME id the respond endpoint takes (wire uuidv7
|
|
13217
|
+
approvalId: { type: string, description: 'The SAME id the respond endpoint takes. server >= 7.133.0: for an ask that has a ledger row it is ALWAYS the row''s key `askId` (a 64-character lowercase hexadecimal string — an OPAQUE string, never a uuid); on <= 7.132.x a wire uuidv7.' }
|
|
13218
|
+
consumerState:
|
|
13219
|
+
type: string
|
|
13220
|
+
enum: [absent]
|
|
13221
|
+
description: >-
|
|
13222
|
+
server >= 7.133.0, TRUE-ONLY (present as `absent`): no engine leg on THIS replica is waiting for this ask. Present <=> the row was ADOPTED from the ask ledger at start-up (minted by a previous
|
|
13223
|
+
process / another replica, the row still undecided — a "zombie card"): it lists and can be answered (the row becomes decided; the answer ack carries the same bit), but that decision resumes
|
|
13224
|
+
nothing running on this replica — read the run surface to learn whether anything continued. The `live_pending` stream frame and the `pending` arm of GET /v1/tool-approvals/{id} carry it too. After a restart an
|
|
13225
|
+
ask still undecided on the ledger RETURNS to `livePending[]` (it used to vanish and answer 404). Absent = this replica has an engine leg waiting, or an older server.
|
|
13007
13226
|
toolName: { type: string }
|
|
13008
13227
|
ts: { type: number, description: 'Registration time (ms epoch).' }
|
|
13009
13228
|
expiresAtMs: { type: number, description: 'Absolute window deadline — the SAME number minted once for the tool_approval frame (never recomputed).' }
|
|
@@ -13028,9 +13247,13 @@ components:
|
|
|
13028
13247
|
allOf: [{ $ref: '#/components/schemas/ToolApprovalCardWord' }]
|
|
13029
13248
|
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.'
|
|
13030
13249
|
frame:
|
|
13031
|
-
|
|
13250
|
+
oneOf:
|
|
13251
|
+
- $ref: '#/components/schemas/ToolApprovalFrame'
|
|
13252
|
+
- $ref: '#/components/schemas/ApprovalRequestFrame'
|
|
13032
13253
|
description: >-
|
|
13033
|
-
server >= 7.87.0 (S-454 P1; cli L-397) — THE CARD FRAME THIS ASK WOULD HAVE EMITTED.
|
|
13254
|
+
server >= 7.87.0 (S-454 P1; cli L-397) — THE CARD FRAME THIS ASK WOULD HAVE EMITTED. TWO SHAPES, by leg (sdk 25.0.0 declares the union; discriminant
|
|
13255
|
+
`frame.type`): on a leg that speaks the card protocol (`capabilities.approvalFrameFamilies` contains `approval_request`, server >= 7.133.0) it is the
|
|
13256
|
+
`approval_request` frame (card facts under `frame.card`, the ten off-card live facts flat at the top); on a legacy-family leg it is the `tool_approval` frame. It is the SAME
|
|
13034
13257
|
OBJECT as the server's `PendingApproval.frame` (the one construction site in `askBroadcast`, already
|
|
13035
13258
|
redacted / byte-capped / window-keys filled), shared by the suspended and the reachable path — so
|
|
13036
13259
|
this is NOT a second card projection computed for the list, and there is no second redaction surface.
|
|
@@ -13250,6 +13473,7 @@ components:
|
|
|
13250
13473
|
required: [sessionId, scope, createdAt]
|
|
13251
13474
|
additionalProperties: true
|
|
13252
13475
|
properties:
|
|
13476
|
+
checkpointId: { type: string, minLength: 1, maxLength: 128, description: 'server >= 7.133.0: the NON-SECRET stable identity of the pause this row parks on — the join key where the token cannot go; the SAME value as `PausedCause.checkpointId`. Carried on three durable read surfaces (GET /v1/approvals `pending[]` rows, the /v1/approvals/stream `pending` frame, GET /v1/assistant/inbox rows). A row whose value is unreadable or untrusted (non-string / empty / over 128 / contains the token / an old row / an older server) is STILL LISTED with the key ABSENT — read absence as "this row has no joinable identity", never as a required key.' }
|
|
13253
13477
|
sessionId: { type: string, description: 'The decide handle: POST /v1/approvals/:sessionId/decide.' }
|
|
13254
13478
|
scope: { type: string, description: 'Principal; "_" = submitted without one.' }
|
|
13255
13479
|
taskId: { type: ['string', 'null'], description: 'Suspended run holding the session claim (service-pinned) — join key to trace tool-call blocks + context link.' }
|
|
@@ -13265,7 +13489,11 @@ components:
|
|
|
13265
13489
|
🔴 OPEN SET — deliberately NOT an enum: observed values include `human`, `irreversible_ask`,
|
|
13266
13490
|
`plan_review`, `needs_review`, `resource_limit`, and core keeps adding. Pinning an enum would make a
|
|
13267
13491
|
new gate kind "not exist" for generated clients.
|
|
13268
|
-
|
|
13492
|
+
🔴 ALWAYS PRESENT on server >= 7.132.0 (a wire narrowing): every park stamps it, the one-time migration M21 filled the stored rows that lacked it
|
|
13493
|
+
(a row whose gate names no registered kind is expired), and a SQL row that still carries none is NOT LISTED (counted under
|
|
13494
|
+
`server.approvals.queue-row-gate-kind-missing`; no decide route can bind it) rather than served without the key. On a <= 7.131.x server it is
|
|
13495
|
+
absent on a pre-`gate_kind` legacy SQL row (column NULL). Either way the reading of an absent key is "unreadable — fail closed": never assume
|
|
13496
|
+
`human`, never route it. Deliberately still not in `required` while the supported floor (3.0.0) is below 7.132.0.
|
|
13269
13497
|
input:
|
|
13270
13498
|
description: >
|
|
13271
13499
|
The pending tool call's args (post-hook), REDACTED + size-bounded — for a tool gate the write
|
|
@@ -13457,6 +13685,7 @@ components:
|
|
|
13457
13685
|
additionalProperties: false
|
|
13458
13686
|
properties:
|
|
13459
13687
|
sessionId: { type: string, description: 'The suspended task/session id.' }
|
|
13688
|
+
checkpointId: { type: string, minLength: 1, maxLength: 128, description: 'server >= 7.133.0: the NON-SECRET stable identity of the pause this row parks on — the join key where the token cannot go; the SAME value as `PausedCause.checkpointId`. Carried on three durable read surfaces (GET /v1/approvals `pending[]` rows, the /v1/approvals/stream `pending` frame, GET /v1/assistant/inbox rows). A row whose value is unreadable or untrusted (non-string / empty / over 128 / contains the token / an old row / an older server) is STILL LISTED with the key ABSENT — read absence as "this row has no joinable identity", never as a required key.' }
|
|
13460
13689
|
scope: { type: string, description: 'Multi-tenant owner scope.' }
|
|
13461
13690
|
createdAt: { type: number, description: 'Ask creation time (epoch ms).' }
|
|
13462
13691
|
gateKind:
|
|
@@ -13780,6 +14009,17 @@ components:
|
|
|
13780
14009
|
⚠️ The key name is final: `permissionModeAfter` (the build brief once said `nextPermissionMode`,
|
|
13781
14010
|
which never shipped — zero aliases).
|
|
13782
14011
|
|
|
14012
|
+
SessionAgent:
|
|
14013
|
+
type: object
|
|
14014
|
+
additionalProperties: false
|
|
14015
|
+
description: >-
|
|
14016
|
+
The placement-tuple projection of a delegated subagent's transcript (`SessionRecord.agent`, server >= 7.133.0). Each member is independently optional (only what was stored is projected); `{}` is a legal value
|
|
14017
|
+
(the tuple held only a `kind`). `id` = the tuple's `handle` (the durable agent row's `a…` key — the SAME string as the fleet row's `id` and `GET /v1/agents/roster`'s `handle`); `parentSessionId` = the host
|
|
14018
|
+
session that spawned it; `rootSessionId` = the delegation tree's root host session (a nested grandchild anchors to the root).
|
|
14019
|
+
properties:
|
|
14020
|
+
id: { type: string }
|
|
14021
|
+
parentSessionId: { type: string }
|
|
14022
|
+
rootSessionId: { type: string }
|
|
13783
14023
|
SessionRecord:
|
|
13784
14024
|
type: object
|
|
13785
14025
|
description: >
|
|
@@ -13812,6 +14052,14 @@ components:
|
|
|
13812
14052
|
$ref: '#/components/schemas/SessionWindow'
|
|
13813
14053
|
promptEpoch:
|
|
13814
14054
|
$ref: '#/components/schemas/PromptEpoch'
|
|
14055
|
+
agent:
|
|
14056
|
+
allOf: [{ $ref: '#/components/schemas/SessionAgent' }]
|
|
14057
|
+
description: >-
|
|
14058
|
+
server >= 7.133.0, top-level additive key — WHICH delegated subagent's transcript this session is (read by terminal side-chain projections that join a fleet frame's `transcriptId`). Only the stored placement
|
|
14059
|
+
tuple is projected (minted by the engine when a BACKGROUND subagent with a durable agent row creates the session on a store that declares placements; a synchronously delegated subagent's transcript is not in
|
|
14060
|
+
the host store and has no tuple); the three members are each optional. 🔴 READ IT AS "WAS IT STORED", NEVER AS "IS IT A SUBAGENT": key PRESENT = a delegated subagent's transcript (even `{}` when the tuple held only a
|
|
14061
|
+
kind); key ABSENT has three causes — an older server (<= 7.132.x) / an ordinary session / a deployment whose store keeps no placement tuple (the local backend: the copy parked from the private short-TTL store is an
|
|
14062
|
+
ordinary session row). Absence is NOT "not a subagent": fall back to the identity the fleet row (`id`) / `GET /v1/agents/roster` (`handle`) already carry.
|
|
13815
14063
|
userInputUndrained:
|
|
13816
14064
|
type: array
|
|
13817
14065
|
description: >-
|
|
@@ -13975,23 +14223,67 @@ components:
|
|
|
13975
14223
|
message: { description: 'OPEN — the message payload as stored; shape belongs to the transcript format, not to this envelope. server >= 7.125.0: a `role: "user"` message carries the same present-iff rewind handle `taskId` as on the whole-record read (see `SessionRecord.messages`).' }
|
|
13976
14224
|
|
|
13977
14225
|
PromptEpoch:
|
|
13978
|
-
type: object
|
|
13979
14226
|
description: >
|
|
13980
|
-
A session's prompt-epoch
|
|
13981
|
-
|
|
13982
|
-
|
|
13983
|
-
|
|
13984
|
-
|
|
14227
|
+
A session's prompt-epoch record on `GET /v1/sessions/:id` (absent = a pre-epoch session — never null). 🔴 server >= 7.132.0 BREAKING (no alias): the value
|
|
14228
|
+
is the engine's `StoredPromptEpoch` reading VERBATIM (the server neither reads nor projects it) — a v3 pin `{ kind: "pin", descriptor }`, or a record of a
|
|
14229
|
+
retired shape recognized by its field names `{ kind: "legacy", centerPinned }` (the engine reads only whether it pinned a center artifact; the next run
|
|
14230
|
+
replaces it with a v3 record). The <= 7.131.x shape `{ epoch, artifactDigest, packId, assemblyApi, activatedBy }` is retired: `epoch` / `activatedBy` live
|
|
14231
|
+
in `descriptor`, `descriptor.identity` takes the identity role (a different digest over different inputs — not comparable), `packId` / `assemblyApi` have
|
|
14232
|
+
no successor. IDs / digests only — never prompt text.
|
|
14233
|
+
oneOf:
|
|
14234
|
+
- $ref: '#/components/schemas/PromptEpochPin'
|
|
14235
|
+
- $ref: '#/components/schemas/PromptEpochLegacy'
|
|
14236
|
+
discriminator:
|
|
14237
|
+
propertyName: kind
|
|
14238
|
+
mapping:
|
|
14239
|
+
pin: '#/components/schemas/PromptEpochPin'
|
|
14240
|
+
legacy: '#/components/schemas/PromptEpochLegacy'
|
|
14241
|
+
PromptEpochPin:
|
|
14242
|
+
type: object
|
|
14243
|
+
additionalProperties: false
|
|
14244
|
+
required: [kind, descriptor]
|
|
13985
14245
|
properties:
|
|
13986
|
-
|
|
13987
|
-
|
|
13988
|
-
|
|
13989
|
-
|
|
14246
|
+
kind: { const: pin }
|
|
14247
|
+
descriptor: { $ref: '#/components/schemas/PromptEpochDescriptor' }
|
|
14248
|
+
PromptEpochLegacy:
|
|
14249
|
+
type: object
|
|
14250
|
+
additionalProperties: false
|
|
14251
|
+
required: [kind, centerPinned]
|
|
14252
|
+
properties:
|
|
14253
|
+
kind: { const: legacy }
|
|
14254
|
+
centerPinned: { type: boolean, description: 'whether the retired-shape record pinned a center artifact.' }
|
|
14255
|
+
PromptEpochDescriptor:
|
|
14256
|
+
type: object
|
|
14257
|
+
description: 'A v3 epoch record (core `PromptEpochDescriptor`), persisted as a session entry and restated in every compaction entry.'
|
|
14258
|
+
additionalProperties: false
|
|
14259
|
+
required: [epoch, identity, layers, activatedBy]
|
|
14260
|
+
properties:
|
|
14261
|
+
epoch: { type: integer, description: 'monotonic per-session record counter.' }
|
|
14262
|
+
identity: { type: string, description: 'the run''s prompt identity digest (= the manifest''s `identity.artifact`).' }
|
|
14263
|
+
layers: { $ref: '#/components/schemas/PromptIdentityLayers' }
|
|
13990
14264
|
activatedBy:
|
|
13991
14265
|
type: string
|
|
13992
|
-
|
|
13993
|
-
|
|
13994
|
-
|
|
14266
|
+
enum: [session_start, compaction, code_change, selection_change]
|
|
14267
|
+
description: 'how the record came to be — core `PROMPT_EPOCH_ACTIVATIONS`: `session_start` / `compaction` (legal boundaries), `code_change` (code or input layers moved), `selection_change` (only the selector values moved). CLOSED: the engine''s judge (`normalizePromptEpoch`) checks membership, a record with any other word does not read as a pin.'
|
|
14268
|
+
changed:
|
|
14269
|
+
type: array
|
|
14270
|
+
items: { type: string, enum: [catalog, renderers, deploy, task, published_schema] }
|
|
14271
|
+
description: 'only on a `code_change` record whose changed layers are known — core `PROMPT_EPOCH_CHANGES` (closed, judged by the engine like `activatedBy`).'
|
|
14272
|
+
sourceRevision: { type: string, description: 'opaque publish provenance of the pinned center layer — present only beside `layers.center`; never digested.' }
|
|
14273
|
+
PromptIdentityLayers:
|
|
14274
|
+
type: object
|
|
14275
|
+
description: >
|
|
14276
|
+
The inputs of a run's prompt identity (core `PromptIdentityLayers`; the epoch record's `layers` and the manifest's `identity.layers` are this one shape).
|
|
14277
|
+
Only `center` is pinned (resolved by digest on resume); the rest are what the run computed. Absent `center` / `deploy` / `task` = that layer contributed nothing.
|
|
14278
|
+
additionalProperties: false
|
|
14279
|
+
required: [catalog, renderers, binding]
|
|
14280
|
+
properties:
|
|
14281
|
+
catalog: { type: string }
|
|
14282
|
+
renderers: { type: object, additionalProperties: { type: number }, description: 'renderer id -> version.' }
|
|
14283
|
+
center: { type: string, description: 'the adopted center artifact''s digest.' }
|
|
14284
|
+
deploy: { type: string }
|
|
14285
|
+
task: { type: string }
|
|
14286
|
+
binding: { type: string, description: 'digest of the run''s selector values (the plain form is the manifest''s `selectors`).' }
|
|
13995
14287
|
|
|
13996
14288
|
SessionListPage:
|
|
13997
14289
|
type: object
|
|
@@ -14097,14 +14389,45 @@ components:
|
|
|
14097
14389
|
# 封闭(census 批2 第三段,2026-07-30):三个铸造臂(`routes/sessions.ts` 的空面板 / 超时 degraded / 正常)键集并集恰是这 3 键;degraded 只在超时臂铸。
|
|
14098
14390
|
# sdk 9.4.0:第 4 键 `lastLegMcp`(server ≥7.77.0)—— 同一个铸造点上按调用方裁的可选顶层键,不在
|
|
14099
14391
|
# 面板那张短 TTL 单飞缓存里(缓存键=场景×principal,与会话无关)。
|
|
14100
|
-
|
|
14392
|
+
# server >= 7.131.0:第 5 键 `scenarioRefusal`(场景门拒时在场,此时 `servers` 缺席)⇒ `servers` 出 required。
|
|
14393
|
+
# 两臂恰一(server 7.132.0 三只铸造臂):served = `servers`(+ `degraded` 只在超时臂)/ refused = `scenarioRefusal`(无 `servers` / `degraded`)⇒ `oneOf` 判(sdk `McpStatusPanelServed` / `McpStatusPanelRefused`)。
|
|
14394
|
+
# 每一臂自己禁掉对方的键(不靠「另一臂恰好不过」:混合体 `{ servers, scenarioRefusal, degraded }` 曾因 refused 臂被 `degraded` 判掉而恰一臂过)。
|
|
14395
|
+
required: [asOf]
|
|
14101
14396
|
additionalProperties: false
|
|
14397
|
+
oneOf:
|
|
14398
|
+
- required: [servers]
|
|
14399
|
+
not: { required: [scenarioRefusal] }
|
|
14400
|
+
- required: [scenarioRefusal]
|
|
14401
|
+
not: { anyOf: [{ required: [servers] }, { required: [degraded] }] }
|
|
14102
14402
|
properties:
|
|
14103
14403
|
asOf: { type: string }
|
|
14104
14404
|
servers:
|
|
14105
14405
|
type: array
|
|
14106
14406
|
items: { $ref: '#/components/schemas/McpServerStatus' }
|
|
14407
|
+
description: >-
|
|
14408
|
+
The scenario half: what this principal's scenario would mount NOW. server >= 7.131.0: ABSENT only when the scenario gate refused (then
|
|
14409
|
+
`scenarioRefusal` is present) — distinct from `[]` (the gate passed and that scenario configures no MCP). Always present on older servers.
|
|
14107
14410
|
degraded: { type: boolean }
|
|
14411
|
+
scenarioRefusal:
|
|
14412
|
+
type: object
|
|
14413
|
+
description: >-
|
|
14414
|
+
server >= 7.131.0 — present ONLY when the scenario gate refused (and then `servers` is absent); the panel still answers 200 because the ledger half
|
|
14415
|
+
(`lastLegMcp`) does not depend on the scenario. Exactly one of `servers` / `scenarioRefusal` is present (the `oneOf` above; `degraded` only beside `servers`). Members = the body of the same refusal answered
|
|
14416
|
+
whole-face (503 on `GET /v1/capabilities/mcp` / `GET /v1/sessions/{id}/a2a`), byte-equal (one sentence builder): today `errorCode`
|
|
14417
|
+
`state.scenario_assignment_unknown`, `error` naming the scenario and this deployment's roster, `detail: { scenario, source }` with `source` one of
|
|
14418
|
+
`ruling` (the center assigned this principal a scenario this deployment does not have) / `deployment` (a dangling `DEFAULT_SCENARIO`; sema-server refuses
|
|
14419
|
+
to boot on it, only an embedder's own `resolveSpec` reaches it). A gate that throws something that is not a typed refusal is still a 500.
|
|
14420
|
+
required: [errorCode, error]
|
|
14421
|
+
additionalProperties: true
|
|
14422
|
+
properties:
|
|
14423
|
+
errorCode: { type: string }
|
|
14424
|
+
error: { type: string }
|
|
14425
|
+
detail:
|
|
14426
|
+
type: object
|
|
14427
|
+
required: [scenario, source]
|
|
14428
|
+
properties:
|
|
14429
|
+
scenario: { type: string }
|
|
14430
|
+
source: { type: string, description: '`ruling` / `deployment` today; read open.' }
|
|
14108
14431
|
lastLegMcp:
|
|
14109
14432
|
type: object
|
|
14110
14433
|
description: >
|
|
@@ -14636,6 +14959,10 @@ components:
|
|
|
14636
14959
|
row (`status` / `instanceId`) — zero extra reads — and a cross-principal caller never reaches these codes
|
|
14637
14960
|
(the owner gate answers `not_found.run`, same code and text as the unknown arm). Both dispositions are the
|
|
14638
14961
|
same: stop retrying the handle, read the run's own outcome via GET /v1/runs/{taskId}.
|
|
14962
|
+
SettingsHooksConfigPath:
|
|
14963
|
+
type: array
|
|
14964
|
+
items: { type: [string, integer] }
|
|
14965
|
+
description: 'the coordinate of a `settings.hooks` verdict — segments relative to the request body''s `settings` (caller-text segments echo-bounded). SDK `SettingsHooksConfigPath`.'
|
|
14639
14966
|
ErrorResponse:
|
|
14640
14967
|
type: object
|
|
14641
14968
|
description: >
|
|
@@ -14766,7 +15093,9 @@ components:
|
|
|
14766
15093
|
unreadable) / `unreachable` (unreachable / 5xx / timeout / bad body / any status other than 200 / 409 / 400 / 401 / 403 —
|
|
14767
15094
|
center 404 / 429 / 3xx included). On 400 `request.field_invalid` for a `settings.permissions` bucket (server >= 7.106.0 /
|
|
14768
15095
|
S-904): `over_cap` (more than `cap` entries; beside `count` + `cap`) / `bad_entry` (a non-string or empty item; beside
|
|
14769
|
-
`index`)
|
|
15096
|
+
`index`); server >= 7.132.0 widens that group to every tool-name list on the body, the agent definitions and the two host-path lists, and adds
|
|
15097
|
+
`too_long` (a text over its character cap; beside `count` + `cap`) — closed words `over_cap` / `too_long` / `bad_entry` (SDK `RequestFieldRefusalExtra`); server >= 7.133.0 adds `too_large` (a payload over its BYTE cap, only on 413 `request.payload_too_large`: `{ field: "body", reason: "too_large", cap }` — `count` ABSENT when the read stopped at the cap and cannot measure; a request body over 8 MiB is now always that 413) and the `request.invalid_json` reasons `not_json` | `not_object` (400, every JSON-body door; formerly `request.rejected`/`request.body_shape` by door).
|
|
15098
|
+
On 409 refusals of a resume (server >= 7.132.0): the engine's `CheckpointErrorReason` arm (`detail.reason` passed through; see `blockedBy`). On 400 `rules.inert_entry` (server >= 7.129.0): the engine's `ALLOW_ENTRY_INERT_REASONS` (`tool_name` / `wildcard_all` / `namespace_wildcard` / `content_unsupported` / `grammar` / `near_miss` / `earlier_grammar`). Out-of-vocabulary word ⇒ treat as unknown. (Other codes carry their own `reason` words.)
|
|
14770
15099
|
retryAfterSec:
|
|
14771
15100
|
type: number
|
|
14772
15101
|
description: >-
|
|
@@ -14782,7 +15111,10 @@ components:
|
|
|
14782
15111
|
carry their own `field`: the bucket on `rules.inert_entry`, the offending key on `rules.invalid_shape`.) Resume legs carry the same group on 409 `resume_blocked_by_policy`
|
|
14783
15112
|
(`blockedBy: "request.field_invalid"`). Also on 409 `checkpoint.config_refused` (server >= 7.113.0): which part of the
|
|
14784
15113
|
row's configuration was refused — `taskConfig` (change the configuration, then decide the SAME card again) or
|
|
14785
|
-
`inheritedGate` (the row's recorded mode seed is bad — the run can only be cancelled).
|
|
15114
|
+
`inheritedGate` (the row's recorded mode seed is bad — the run can only be cancelled) and — core 7.53.0 / server >= 7.132.0 — `deps` (the deployment's OWN
|
|
15115
|
+
seat is broken: fix the deployment, then decide the SAME card again). server >= 7.132.0: on 400 `request.field_invalid` cap / bad-entry refusals `field` is
|
|
15116
|
+
the IN-BODY COORDINATE of the capped / bad place (`skills[1].allowedTools`, `agents[0].denyTools[3]`, `agents`, `allowTools`, `additionalDirectories` …) —
|
|
15117
|
+
the same group as `reason` / `count` / `cap` / `index`. Also on 400 `request.field_invalid` for a
|
|
14786
15118
|
`settings.hooks` tool-event matcher that selects an engine alias but not its canonical name (server >= 7.115.0 / S-1025):
|
|
14787
15119
|
`field` is always the literal `settings.hooks` (see `detail`). Also on 400 `request.body_shape` (server >= 7.119.0), on the THREE
|
|
14788
15120
|
tool-approval decision doors (`POST /v1/tool-approvals/{id}/respond`, `POST /v1/tasks/{taskId}/asks/{askId}/decision`,
|
|
@@ -14800,33 +15132,163 @@ components:
|
|
|
14800
15132
|
`request.field_invalid` for a `settings.hooks` tool-event matcher (server >= 7.115.0 / S-1025; additive, the sentence and the code
|
|
14801
15133
|
are unchanged): an OBJECT `{ event, alias, canonical }` — `event` = the tool event of the refused group (the first refused one when
|
|
14802
15134
|
several are), `alias` / `canonical` = the engine catalog's alias and canonical name (closed strings, never the caller's raw bytes),
|
|
14803
|
-
beside `field: "settings.hooks"
|
|
15135
|
+
beside `field: "settings.hooks"`; 🔴 server >= 7.126.0 adds `reason` (`dead_alias` / `over_budget` / `invalid_regex`) and server >= 7.132.0 makes EVERY
|
|
15136
|
+
`settings.hooks` refusal carry this object with `path` ALWAYS present (the coordinate of the verdict, a segment array relative to the body's `settings`):
|
|
15137
|
+
the matcher forms (+ `budget_exceeded` with `totalMs`), the config reader's piece codes (+ `key`), `unsupported_entry_type` (+ `type`), the service caps
|
|
15138
|
+
`over_cap` / `too_long` (+ `count` / `cap`) and `unnamed_refusal` — see the hooks branch below and SDK `SettingsHooksRefusalDetail`. On 400
|
|
15139
|
+
`config.user_attachment_invalid` (server >= 7.132.0 / core 7.53.0): an OBJECT `{ path, index? }` — the field the engine names at the head of the sentence,
|
|
15140
|
+
`index` (0-based) only when the sentence names one attachment (SDK `UserAttachmentRefusalExtra`). On 400 `request.field_invalid` for the two `POST /v1/adoption` principal sentences (adoption):
|
|
14804
15141
|
a human-readable STRING. Other codes (core `checkpoint.*` mirrors; `rules.*` refusals carry no `detail` — their keys are `field` / `entry` / `reason` / `verdict` / `currentName` / `guidance` / `got` at the top level) carry their
|
|
14805
15142
|
own `detail`; read it by `errorCode`. SDK: `err.extra.detail` (verbatim, unnamed).
|
|
14806
15143
|
oneOf:
|
|
14807
15144
|
- type: object
|
|
14808
|
-
|
|
15145
|
+
description: 'the `settings.hooks` refusal detail (beside `field: "settings.hooks"`), one shape per `reason` — branch on `reason`, exhaustively (SDK `SettingsHooksRefusalDetail`). server >= 7.132.0: every hooks refusal carries it and `path` is always present; in-floor older servers: the three matcher shapes without `path` (7.126.0–7.131.x) and the reason-less dead-alias shape (7.115.0–7.125.x).'
|
|
15146
|
+
oneOf:
|
|
15147
|
+
- type: object
|
|
15148
|
+
description: 'matcher: selects an engine alias but not its canonical name (`path` absent on server 7.126.0–7.131.x).'
|
|
15149
|
+
required: [reason, event, alias, canonical]
|
|
15150
|
+
additionalProperties: false
|
|
15151
|
+
properties:
|
|
15152
|
+
reason: { type: string, enum: [dead_alias] }
|
|
15153
|
+
event: { type: string }
|
|
15154
|
+
alias: { type: string }
|
|
15155
|
+
canonical: { type: string }
|
|
15156
|
+
path: { $ref: '#/components/schemas/SettingsHooksConfigPath' }
|
|
15157
|
+
- type: object
|
|
15158
|
+
description: 'matcher: one regex evaluation over the per-evaluation budget (`path` absent on server 7.126.0–7.131.x).'
|
|
15159
|
+
required: [reason, event, groupIndex, budgetMs]
|
|
15160
|
+
additionalProperties: false
|
|
15161
|
+
properties:
|
|
15162
|
+
reason: { type: string, enum: [over_budget] }
|
|
15163
|
+
event: { type: string }
|
|
15164
|
+
groupIndex: { type: integer }
|
|
15165
|
+
budgetMs: { type: integer }
|
|
15166
|
+
path: { $ref: '#/components/schemas/SettingsHooksConfigPath' }
|
|
15167
|
+
- type: object
|
|
15168
|
+
description: 'matcher (server >= 7.132.0): the completed regex evaluations of one admission summed over `totalMs`.'
|
|
15169
|
+
required: [reason, event, groupIndex, totalMs, path]
|
|
15170
|
+
additionalProperties: false
|
|
15171
|
+
properties:
|
|
15172
|
+
reason: { type: string, enum: [budget_exceeded] }
|
|
15173
|
+
event: { type: string }
|
|
15174
|
+
groupIndex: { type: integer }
|
|
15175
|
+
totalMs: { type: integer }
|
|
15176
|
+
path: { $ref: '#/components/schemas/SettingsHooksConfigPath' }
|
|
15177
|
+
- type: object
|
|
15178
|
+
description: 'matcher: the regex does not compile (`path` absent on server 7.126.0–7.131.x).'
|
|
15179
|
+
required: [reason, event, groupIndex]
|
|
15180
|
+
additionalProperties: false
|
|
15181
|
+
properties:
|
|
15182
|
+
reason: { type: string, enum: [invalid_regex] }
|
|
15183
|
+
event: { type: string }
|
|
15184
|
+
groupIndex: { type: integer }
|
|
15185
|
+
path: { $ref: '#/components/schemas/SettingsHooksConfigPath' }
|
|
15186
|
+
- type: object
|
|
15187
|
+
description: 'the config reader''s classifier code verbatim (server >= 7.132.0; SDK `SETTINGS_HOOKS_PIECE_CODES`), `key` = the key that broke that piece when named.'
|
|
15188
|
+
required: [reason, path]
|
|
15189
|
+
additionalProperties: false
|
|
15190
|
+
properties:
|
|
15191
|
+
reason: { type: string, enum: [guard-outside-hooks, hooks-is-matcher, guard-under-unknown-event, guard-event-not-array, guard-matcher-invalid, guard-entry-invalid, hooks-not-object, unknown-event, event-not-array, matcher-invalid, entry-invalid] }
|
|
15192
|
+
path: { $ref: '#/components/schemas/SettingsHooksConfigPath' }
|
|
15193
|
+
key: { type: string }
|
|
15194
|
+
- type: object
|
|
15195
|
+
description: 'an entry type this service does not execute (server >= 7.132.0).'
|
|
15196
|
+
required: [reason, path, type]
|
|
15197
|
+
additionalProperties: false
|
|
15198
|
+
properties:
|
|
15199
|
+
reason: { type: string, enum: [unsupported_entry_type] }
|
|
15200
|
+
path: { $ref: '#/components/schemas/SettingsHooksConfigPath' }
|
|
15201
|
+
type: { type: string }
|
|
15202
|
+
- type: object
|
|
15203
|
+
description: 'a service cap (server >= 7.132.0).'
|
|
15204
|
+
required: [reason, path, count, cap]
|
|
15205
|
+
additionalProperties: false
|
|
15206
|
+
properties:
|
|
15207
|
+
reason: { type: string, enum: [over_cap, too_long] }
|
|
15208
|
+
path: { $ref: '#/components/schemas/SettingsHooksConfigPath' }
|
|
15209
|
+
count: { type: integer }
|
|
15210
|
+
cap: { type: integer }
|
|
15211
|
+
- type: object
|
|
15212
|
+
description: 'the classifier refused without naming a piece — contract drift, fail-closed (server >= 7.132.0).'
|
|
15213
|
+
required: [reason, path]
|
|
15214
|
+
additionalProperties: false
|
|
15215
|
+
properties:
|
|
15216
|
+
reason: { type: string, enum: [unnamed_refusal] }
|
|
15217
|
+
path: { $ref: '#/components/schemas/SettingsHooksConfigPath' }
|
|
15218
|
+
- type: object
|
|
15219
|
+
description: 'one of the three wire keys this service reads itself is malformed (server >= 7.133.0): the group `source` / a command entry''s `plugin` / `args`; `key` names it, `path` is its coordinate. The whole request is refused (they used to be stripped silently as unknown keys).'
|
|
15220
|
+
required: [reason, key, path]
|
|
15221
|
+
additionalProperties: false
|
|
15222
|
+
properties:
|
|
15223
|
+
reason: { type: string, enum: [wire_key_invalid] }
|
|
15224
|
+
key: { type: string }
|
|
15225
|
+
path: { $ref: '#/components/schemas/SettingsHooksConfigPath' }
|
|
15226
|
+
- type: object
|
|
15227
|
+
description: 'server 7.115.0–7.125.x: the dead-alias matcher refusal before `reason` existed.'
|
|
15228
|
+
required: [event, alias, canonical]
|
|
15229
|
+
additionalProperties: false
|
|
15230
|
+
properties:
|
|
15231
|
+
event: { type: string }
|
|
15232
|
+
alias: { type: string }
|
|
15233
|
+
canonical: { type: string }
|
|
15234
|
+
- type: object
|
|
15235
|
+
description: '400 `config.user_attachment_invalid` (server >= 7.132.0): the field the engine names; `index` only when one attachment is named.'
|
|
15236
|
+
required: [path]
|
|
14809
15237
|
additionalProperties: false
|
|
14810
15238
|
properties:
|
|
14811
|
-
|
|
14812
|
-
|
|
14813
|
-
canonical: { type: string }
|
|
15239
|
+
path: { type: string }
|
|
15240
|
+
index: { type: integer }
|
|
14814
15241
|
- type: object
|
|
14815
15242
|
required: [scenario, source]
|
|
14816
15243
|
additionalProperties: false
|
|
14817
15244
|
properties:
|
|
14818
15245
|
scenario: { type: string }
|
|
14819
15246
|
source: { type: string, enum: [ruling, deployment] }
|
|
15247
|
+
- type: object
|
|
15248
|
+
description: >-
|
|
15249
|
+
server >= 7.133.0 — entry problems on a tool-name list / settings-rule refusal (400 `request.field_invalid`, 422): `problems` (at most 1000, each EntryProblem) + `total` (the true count; `total > problems.length` => cut).
|
|
15250
|
+
With `callerTrust` it is the below-trust-floor refusal: the caller's admission tier (`global` | `project`, read open; the same words as `capabilities.settings.permissions.callerTrust`).
|
|
15251
|
+
required: [problems, total]
|
|
15252
|
+
additionalProperties: false
|
|
15253
|
+
properties:
|
|
15254
|
+
problems: { type: array, items: { $ref: '#/components/schemas/EntryProblem' } }
|
|
15255
|
+
total: { type: integer }
|
|
15256
|
+
callerTrust: { type: string }
|
|
15257
|
+
- type: object
|
|
15258
|
+
description: >-
|
|
15259
|
+
server >= 7.133.0 — 400 `request.field_conflict`: the request body contradicts itself. `kind` = which constraint (a CLOSED fourteen-word set, read open: cascade_verify | image_profile | resume_anchor |
|
|
15260
|
+
system_prompt_fold | file_history_restore | skills_disabled | existing_session | scratchpad_root | ask_answer | policy_person_ask | plan_edit | plan_mode_after | bound_call_door | remember_decision);
|
|
15261
|
+
`fields` = the named body coordinates, subject first (at least one; a dynamic index reads `agents[1].skills`); `count` / `cap` only on the fold-cap kind (the folded total and its cap).
|
|
15262
|
+
required: [kind, fields]
|
|
15263
|
+
additionalProperties: false
|
|
15264
|
+
properties:
|
|
15265
|
+
kind: { type: string }
|
|
15266
|
+
fields: { type: array, items: { type: string } }
|
|
15267
|
+
count: { type: integer }
|
|
15268
|
+
cap: { type: integer }
|
|
15269
|
+
- type: object
|
|
15270
|
+
description: '409 `conflict.session_placed` (server >= 7.133.0): the session sync commit targeted a session that holds a delegated agent''s transcript. `placement_kind` is the stored placement kind (today only `subagent`; read open).'
|
|
15271
|
+
required: [placement_kind]
|
|
15272
|
+
additionalProperties: false
|
|
15273
|
+
properties:
|
|
15274
|
+
placement_kind: { type: string }
|
|
14820
15275
|
- type: string
|
|
14821
15276
|
count:
|
|
14822
15277
|
type: integer
|
|
14823
|
-
description: '
|
|
15278
|
+
description: '`reason: over_cap` / `too_long` / `too_large` — how much was sent (entries / characters / bytes; every capped face since >= 7.132.0). ABSENT on the unmeasured form (a body read that stopped at the cap). SDK: `err.extra.count`.'
|
|
14824
15279
|
cap:
|
|
14825
15280
|
type: integer
|
|
14826
|
-
description: '
|
|
15281
|
+
description: '`reason: over_cap` / `too_long` / `too_large` — the cap (1000 for a permissions bucket; per face otherwise; bytes on a too_large 413). SDK: `err.extra.cap`.'
|
|
14827
15282
|
index:
|
|
14828
15283
|
type: integer
|
|
14829
|
-
description: '
|
|
15284
|
+
description: '`reason: bad_entry` only — the index of the first bad item; ABSENT when the list itself is not an array. SDK: `err.extra.index`.'
|
|
15285
|
+
wallSource:
|
|
15286
|
+
type: string
|
|
15287
|
+
description: >-
|
|
15288
|
+
server >= 7.132.0, on a 413 refused against the database's limits — WHERE THE WALL'S NUMBER CAME FROM. On `request.payload_too_large` (a submit body over
|
|
15289
|
+
the database's single-row / packet wall): `reported` (the database's own number) / `assumed` (not reported — engine facts not established yet, or that
|
|
15290
|
+
wall's read failed and fell back to the documented default; refusing conservatively). On `blob_too_large_for_sql` (`PUT /v1/sessions/{id}/sync/blobs/{hash}`):
|
|
15291
|
+
`operator` (the operator's `SNAPSHOT_BLOB_SQL_MAX_BYTES`) / `reported` / `assumed`. Two closed sets, one per face (SDK `SqlWallSource` / `BlobSqlCapSource`).
|
|
14830
15292
|
blockedBy:
|
|
14831
15293
|
type: string
|
|
14832
15294
|
description: >-
|
|
@@ -14837,11 +15299,19 @@ components:
|
|
|
14837
15299
|
`ResumeBlockedByPolicyError.blockedBy` (`undefined` when the key is absent or not a string — never defaulted).
|
|
14838
15300
|
server >= 7.117.0 adds a third fold source: a stored skill `disallowedTools` entry the engine now reads as nothing (the submit leg's 400 `request.field_invalid` sentence)
|
|
14839
15301
|
⇒ `blockedBy: "request.field_invalid"`, refused before the claim; the terminal-run steer leg answers it before minting the wake card.
|
|
15302
|
+
server >= 7.132.0 / core 7.52.0: also on an ENGINE-refused resume (the five resume legs, the PARKED redemption seat and the SLA deny sweep share one body):
|
|
15303
|
+
the engine's `detail.code` passes through as `blockedBy` (today only `checkpoint.config_refused` carries it — the closed set is core's
|
|
15304
|
+
`CHECKPOINT_CONFIG_REFUSAL_CODES`, 40 words since core 7.53.0; read it as "the errorCode a fresh run would report for the same bad configuration"),
|
|
15305
|
+
next to `field` and `reason`, absent keys not minted (SDK `ResumeRefusalExtra`).
|
|
14840
15306
|
|
|
14841
15307
|
ResumeLegConflictError:
|
|
14842
15308
|
description: >
|
|
14843
15309
|
The 409 body of a RESUME LEG that core refused BEFORE the claim (`POST /v1/approvals/{sessionId}/decide`,
|
|
14844
|
-
`POST /v1/sessions/{sessionId}/wake`): `ErrorResponse` plus the one key those 409s may add, `retriable`.
|
|
15310
|
+
`POST /v1/sessions/{sessionId}/wake`): `ErrorResponse` plus the one key those 409s may add, `retriable`. server >= 7.132.0: ONE writer and one
|
|
15311
|
+
rule — on the three kinds of resume refusal (the server's own stored-body replay refusal, the admission-policy fold `resume_blocked_by_policy`, an
|
|
15312
|
+
engine-refused resume) `retriable: true` is present <=> a pending card is still waiting and the run row stays `suspended`; so `resume_blocked_by_policy`
|
|
15313
|
+
now carries it too, and the terminal-run `POST /v1/runs/{id}/steer` refusal before a wake card is minted carries none (the `checkpoint.unsupported_version`
|
|
15314
|
+
allow-reading / mode-reading arms used to claim `true` there). The key is declared HERE and
|
|
14845
15315
|
not on the shared `ErrorResponse` on purpose (codex r1 [medium], sdk 16.0.0): `ErrorResponse` is the body of every error
|
|
14846
15316
|
response in this document, and declaring `retriable` there would offer a retry signal on 401 / 404 / 422 / 5xx bodies where the
|
|
14847
15317
|
server never mints it. (`ErrorResponse` stays open, so a validator cannot REJECT the key elsewhere; the confinement is that only
|
|
@@ -14920,6 +15390,8 @@ components:
|
|
|
14920
15390
|
- $ref: '#/components/schemas/Event_message_committed'
|
|
14921
15391
|
# [2373]A-2(2026-08-03,server 5.0.0):compaction_outcome 三腿同源批的 spec 半场(SDK 臂 20867e1 同批)。
|
|
14922
15392
|
- $ref: '#/components/schemas/Event_compaction_outcome'
|
|
15393
|
+
# server 7.132.0(core 7.53.0 #2008):压缩开始帧,与 compaction_outcome 同一族的三腿同源白名单构造器。
|
|
15394
|
+
- $ref: '#/components/schemas/Event_compaction_started'
|
|
14923
15395
|
# [2400] ch2(SDK 4.2.0):CB-1 流控帽帧 + TR-7 durable 五臂 —— 两侧同缺,见各 schema 处的注。
|
|
14924
15396
|
- $ref: '#/components/schemas/Event_error'
|
|
14925
15397
|
- $ref: '#/components/schemas/Event_question'
|
|
@@ -14942,6 +15414,11 @@ components:
|
|
|
14942
15414
|
- $ref: '#/components/schemas/Event_tool_approval_complete'
|
|
14943
15415
|
- $ref: '#/components/schemas/Event_approval_request'
|
|
14944
15416
|
- $ref: '#/components/schemas/Event_approval_revoke'
|
|
15417
|
+
# server >= 7.133.0 (sdk 25.0.0): the card family's single-card CLOSE frame (`approval_complete`; one frame family per leg — it replaces the legacy
|
|
15418
|
+
# `tool_approval_complete` on a leg where `capabilities.approvalFrameFamilies` = ["approval_request"]) and the LIVE-ONLY `session_titled` frame (a session
|
|
15419
|
+
# title was written; never ledgered, no eventId).
|
|
15420
|
+
- $ref: '#/components/schemas/Event_approval_complete'
|
|
15421
|
+
- $ref: '#/components/schemas/Event_session_titled'
|
|
14945
15422
|
# sdk 9.1.0: two LIVE-leg arms the service has been emitting while neither this union nor the
|
|
14946
15423
|
# SDK's declared them — `text_end` since server 7.66.0 (segment boundary; retires the idle-flush
|
|
14947
15424
|
# heuristic) and `tool_roster_delta` since server 7.70.0 (run-time roster change). A generated client
|
|
@@ -14990,6 +15467,7 @@ components:
|
|
|
14990
15467
|
needs_review: '#/components/schemas/Event_needs_review'
|
|
14991
15468
|
message_committed: '#/components/schemas/Event_message_committed'
|
|
14992
15469
|
compaction_outcome: '#/components/schemas/Event_compaction_outcome'
|
|
15470
|
+
compaction_started: '#/components/schemas/Event_compaction_started'
|
|
14993
15471
|
error: '#/components/schemas/Event_error'
|
|
14994
15472
|
question: '#/components/schemas/Event_question'
|
|
14995
15473
|
question_complete: '#/components/schemas/Event_question_complete'
|
|
@@ -15002,6 +15480,8 @@ components:
|
|
|
15002
15480
|
tool_approval_complete: '#/components/schemas/Event_tool_approval_complete'
|
|
15003
15481
|
approval_request: '#/components/schemas/Event_approval_request'
|
|
15004
15482
|
approval_revoke: '#/components/schemas/Event_approval_revoke'
|
|
15483
|
+
approval_complete: '#/components/schemas/Event_approval_complete'
|
|
15484
|
+
session_titled: '#/components/schemas/Event_session_titled'
|
|
15005
15485
|
text_end: '#/components/schemas/Event_text_end'
|
|
15006
15486
|
tool_roster_delta: '#/components/schemas/Event_tool_roster_delta'
|
|
15007
15487
|
reasoning_end: '#/components/schemas/Event_reasoning_end'
|
|
@@ -15031,13 +15511,18 @@ components:
|
|
|
15031
15511
|
condition: durable-ledger leg only (no ledger => neither header nor frame). sessionId rides along
|
|
15032
15512
|
(needed to bind subsequent turns when the server minted a fresh session). Always precedes any content
|
|
15033
15513
|
frame. NOT an engine event — server-minted, no EventIdentity.
|
|
15034
|
-
# 封闭:铸造点 routes/tasks.ts 是逐字写死的三键字面量(sessionId 条件在场)。
|
|
15514
|
+
# 封闭:铸造点 routes/tasks.ts 是逐字写死的三键字面量(sessionId 条件在场);server >= 7.133.0 起第四个条件键 `warnings`(有才发)。
|
|
15035
15515
|
additionalProperties: false
|
|
15036
15516
|
required: [type, taskId]
|
|
15037
15517
|
properties:
|
|
15038
15518
|
type: { const: meta }
|
|
15039
15519
|
taskId: { type: string }
|
|
15040
15520
|
sessionId: { type: string }
|
|
15521
|
+
warnings:
|
|
15522
|
+
type: array
|
|
15523
|
+
items: { $ref: '#/components/schemas/EntryProblem' }
|
|
15524
|
+
description: 'server >= 7.133.0, present only when non-empty: the accept-time NOTICES for entries of the allow-side selector lists (root / agent `allowTools`) the engine reads as nothing or that are not in the roster. Same list as the 202 receipt''s and the sync 200 body''s `warnings`. ABSENT = no notice (older servers too).'
|
|
15525
|
+
|
|
15041
15526
|
Event_reasoning:
|
|
15042
15527
|
type: object
|
|
15043
15528
|
description: durable stream only — turn-aggregated thinking.
|
|
@@ -15629,6 +16114,29 @@ components:
|
|
|
15629
16114
|
WHO ASKED. Same-present/same-absent as `settlement` (I1). CLOSED here (archive read, `GateRecordAskOrigin`) — see the
|
|
15630
16115
|
note above.
|
|
15631
16116
|
|
|
16117
|
+
McpProbeFaceRow:
|
|
16118
|
+
# server 7.133.0: the face''s row = the wiring-manifest row projection + TWO face-only optional keys. The manifest row is CLOSED (so an `allOf` over it would reject the two extra keys), hence a
|
|
16119
|
+
# standalone closed schema whose per-key shapes are `$ref`s into WiringManifestMcpEntry's own properties (one source per shape); the key SET is pinned by test (manifest row keys + the two).
|
|
16120
|
+
type: object
|
|
16121
|
+
description: >
|
|
16122
|
+
One row of the no-run MCP status face (GET /v1/capabilities/mcp and POST /v1/capabilities/mcp/probe): the SAME projection a prepared leg pushes onto `wiring_manifest.mcp[]`, PLUS two optional keys only this
|
|
16123
|
+
face carries (server >= 7.133.0). `toolNames` = the tool names this server will mount (the same probe reading `servers[i].tools`, engine namespace form `mcp__<server>__<tool>`, after the schema gate and the per-server
|
|
16124
|
+
allow-list; the server neither composes nor renames), at most 200 per server, the reading-order prefix. ABSENT = an older server or no `tools` in that server's reading — NEVER invent `[]` (it would read as "this server
|
|
16125
|
+
has no tools"); a present `[]` is real. `toolNamesTruncated` = TRUE-ONLY: the list was cut (more than 200; exactly 200 is NOT cut and the key stays absent, never `false`) — when true `toolCount` is the true count, not
|
|
16126
|
+
`toolNames.length`. A misaligned reading (not an array / count differs from the row count) answers 500 `internal.error` on both doors instead of shipping a list that could be paired wrongly.
|
|
16127
|
+
additionalProperties: false
|
|
16128
|
+
required: [name, status]
|
|
16129
|
+
properties:
|
|
16130
|
+
name: { $ref: '#/components/schemas/WiringManifestMcpEntry/properties/name' }
|
|
16131
|
+
status: { $ref: '#/components/schemas/WiringManifestMcpEntry/properties/status' }
|
|
16132
|
+
source: { $ref: '#/components/schemas/WiringManifestMcpEntry/properties/source' }
|
|
16133
|
+
toolCount: { $ref: '#/components/schemas/WiringManifestMcpEntry/properties/toolCount' }
|
|
16134
|
+
errorCode: { $ref: '#/components/schemas/WiringManifestMcpEntry/properties/errorCode' }
|
|
16135
|
+
delivered: { $ref: '#/components/schemas/WiringManifestMcpEntry/properties/delivered' }
|
|
16136
|
+
httpStatus: { $ref: '#/components/schemas/WiringManifestMcpEntry/properties/httpStatus' }
|
|
16137
|
+
liveness: { $ref: '#/components/schemas/WiringManifestMcpEntry/properties/liveness' }
|
|
16138
|
+
toolNames: { type: array, items: { type: string }, maxItems: 200 }
|
|
16139
|
+
toolNamesTruncated: { type: boolean, enum: [true] }
|
|
15632
16140
|
McpProbeFace:
|
|
15633
16141
|
type: object
|
|
15634
16142
|
description: >
|
|
@@ -15654,8 +16162,8 @@ components:
|
|
|
15654
16162
|
description: 'How long this reading may be reused (seconds; 30s per identity + declaration set server-side). A hit inside the window does NOT count against the rate limit.'
|
|
15655
16163
|
servers:
|
|
15656
16164
|
type: array
|
|
15657
|
-
items: { $ref: '#/components/schemas/
|
|
15658
|
-
description: 'One row per declaration,
|
|
16165
|
+
items: { $ref: '#/components/schemas/McpProbeFaceRow' }
|
|
16166
|
+
description: 'One row per declaration, the wiring-manifest row shape plus (server >= 7.133.0) this face''s two optional keys, index-aligned (see this schema''s description).'
|
|
15659
16167
|
|
|
15660
16168
|
McpLivenessState:
|
|
15661
16169
|
type: string
|
|
@@ -15936,6 +16444,9 @@ components:
|
|
|
15936
16444
|
summaryMs: { type: integer }
|
|
15937
16445
|
persistMs: { type: integer }
|
|
15938
16446
|
ptlRetries: { type: integer }
|
|
16447
|
+
pass:
|
|
16448
|
+
type: string
|
|
16449
|
+
description: 'server >= 7.132.0 (core 7.53.0 #2008): the id of the compaction pass that LANDED — the same opaque value its `compaction_started.pass` carried. Pair the start with its end on `pass`, not on "the next `compacted`" (legs interleave on one stream). Absent = an older server / a pass that never announced a start.'
|
|
15939
16450
|
Event_suggestions:
|
|
15940
16451
|
type: object
|
|
15941
16452
|
description: >
|
|
@@ -15969,7 +16480,7 @@ components:
|
|
|
15969
16480
|
type: { const: status }
|
|
15970
16481
|
# 🔴 A-057.27:6 员(此前只列 4,漏 recovered/gave_up 两个**终局**值 —— 一段重试序列恒恰一终局帧,
|
|
15971
16482
|
# 两者对渲染方是同一句话「把重试行撤下来」)。闭集声明、开集读。
|
|
15972
|
-
phase: { type: string, description: "rate_limited | retrying | reconnecting | circuit_open | recovered | gave_up (closed in core, read as open set)" }
|
|
16483
|
+
phase: { type: string, description: "rate_limited | retrying | reconnecting | circuit_open | recovered | gave_up | waiting_first_token (core's seven words since core 7.3.1 — `waiting_first_token` observes a first-token wait before any failure and carries `elapsedMs` / `timeoutMs`, never a retry countdown; closed in core, read as open set)" }
|
|
15973
16484
|
detail: { type: string, description: "neutral human hint (NO provider/HTTP detail)" }
|
|
15974
16485
|
retryInSec: { type: number }
|
|
15975
16486
|
# 🔴 A-057.26:以下四键 server 真在发(builder brainStatusEventData,三腿共享),而本 schema 是
|
|
@@ -15978,7 +16489,7 @@ components:
|
|
|
15978
16489
|
attempt: { type: number, description: "1-based index of the attempt that just FAILED (this wait precedes attempt+1)" }
|
|
15979
16490
|
maxRetries: { type: number, description: "retry budget of the lane in force (refused-connect short lane = 2)" }
|
|
15980
16491
|
retryInMs: { type: number, description: "same number as retryInSec at ms precision (countdown rendering)" }
|
|
15981
|
-
errClass: { type: string, description: "connect_refused | transport | rate_limit | server | http | output_cap — retry-wait frames ONLY; never inferred from phase" }
|
|
16492
|
+
errClass: { type: string, description: "connect_refused | transport | stall | rate_limit | server | http | output_cap (core's seven words since core 7.14.0 — `stall` = this process's own stall watchdog cancelled the request) — retry-wait frames ONLY; never inferred from phase" }
|
|
15982
16493
|
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`." }
|
|
15983
16494
|
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." }
|
|
15984
16495
|
retryAtMs: { type: number, description: "server >= 7.52.0 (core 7.0.0): the WALL-CLOCK end of the wait = `Date.now() + retryInMs` at emit, on the emitting process's clock (not monotonic — never compare it with a local monotonic timer). `retryInMs` stays the authoritative RELATIVE amount; this is the producer's absolute note (a reader several hops away recomputing it would reset the countdown on every replay). Moves with `retryInMs`; absent ⇒ not minted." }
|
|
@@ -16101,9 +16612,12 @@ components:
|
|
|
16101
16612
|
`message_committed` + stream order). Live emissions PRECEDE the commit and omit `entryId`.
|
|
16102
16613
|
SERVICE PROJECTION: core's `principal` is deliberately NOT forwarded (the stream is already owner-scoped —
|
|
16103
16614
|
the frame does not restate the tenant). `issuer` / `actor.id` / `actor.issuer` are host-derived identity
|
|
16104
|
-
strings and arrive SECRET-REDACTED.
|
|
16105
|
-
|
|
16106
|
-
`
|
|
16615
|
+
strings and arrive SECRET-REDACTED. REQUEST-LAYER ATTACHMENTS (server >= 7.131.0 / core 7.50.0): the frame of the objective that declared
|
|
16616
|
+
attachments (`carrier: "objective"`, `delivery: "applied"`) carries `attachments` — one item per attachment, in declared order (submit key
|
|
16617
|
+
`TaskRequest.userAttachments`; probe `Capabilities.userAttachments`). It is the ADMISSION outcome, not delivery: each attachment's message lands as its
|
|
16618
|
+
own `message_committed{role:"user"}`. Attachments ride the objective only: a steer door (run / child / workflow child steer, child resume, interrupt
|
|
16619
|
+
bare or with text) carrying `userAttachments` is 400 `request.body_shape` (named in `unsupportedKeys`), and resume / delivery legs do not rebuild it.
|
|
16620
|
+
(7.127.0 – 7.130.x did not accept `userAttachments` and never carried `attachments`; the capability bit is absent there.)
|
|
16107
16621
|
allOf: [{ $ref: '#/components/schemas/EventIdentity' }]
|
|
16108
16622
|
additionalProperties: false # 封闭 + identity 本地镜像:见 Event_reasoning 处的长注
|
|
16109
16623
|
required: [type, inputId]
|
|
@@ -16134,6 +16648,23 @@ components:
|
|
|
16134
16648
|
hostAsserted: { type: boolean }
|
|
16135
16649
|
issuer: { type: string }
|
|
16136
16650
|
entryId: { type: string, description: 'The committed session entry this input became (absent on the live pre-commit emission).' }
|
|
16651
|
+
attachments:
|
|
16652
|
+
type: array
|
|
16653
|
+
description: >-
|
|
16654
|
+
server >= 7.131.0 (core 7.50.0): the per-attachment ADMISSION outcome of the request-layer attachments this objective declared, one item per
|
|
16655
|
+
attachment in declared order; present only on that objective's frame. The server copies each member key only when well-formed (a non-object member is
|
|
16656
|
+
not minted); `ordinal` / `outcome` / `label` are required members of the engine's `HumanInputAttachment` (core 7.53.0), hence `required` here. `ordinal` 1-based; `kind` the engine-recognized kind (absent when unreadable; read open); `outcome` `attached` / `partial` / `unchanged` /
|
|
16657
|
+
`not_attached` (engine words, verbatim — a file the engine may not read is NOT refused: its message still goes out saying why, and its outcome is
|
|
16658
|
+
`not_attached`); `label` the path or name the caller declared, credential-redacted.
|
|
16659
|
+
items:
|
|
16660
|
+
type: object
|
|
16661
|
+
required: [ordinal, outcome, label]
|
|
16662
|
+
additionalProperties: false
|
|
16663
|
+
properties:
|
|
16664
|
+
ordinal: { type: integer }
|
|
16665
|
+
kind: { type: string }
|
|
16666
|
+
outcome: { type: string }
|
|
16667
|
+
label: { type: string }
|
|
16137
16668
|
eventId: { type: string }
|
|
16138
16669
|
parentToolCallId: { type: string }
|
|
16139
16670
|
sourceTaskId: { type: string }
|
|
@@ -16313,19 +16844,22 @@ components:
|
|
|
16313
16844
|
already owns the single redaction mint point for it). The actionable cause is `errorCode`.
|
|
16314
16845
|
A row missing `name` or `status` is dropped individually — the other servers'' rows still ship.
|
|
16315
16846
|
items: { $ref: '#/components/schemas/WiringManifestMcpEntry' }
|
|
16316
|
-
|
|
16847
|
+
mods:
|
|
16317
16848
|
type: array
|
|
16318
16849
|
description: >
|
|
16319
|
-
core 7.
|
|
16320
|
-
|
|
16321
|
-
|
|
16322
|
-
|
|
16323
|
-
|
|
16324
|
-
|
|
16325
|
-
|
|
16326
|
-
|
|
16327
|
-
|
|
16328
|
-
|
|
16850
|
+
core 7.52.0, server >= 7.132.0 (BREAKING — replaces `hooks[]`, which is gone with no alias) — TENANT-visible: this leg's MODS ADMISSION record, one row
|
|
16851
|
+
per registration of the two seats (deployment, task), in the engine's run order (tier, then deployment before task, then seat order). Two row forms
|
|
16852
|
+
(`WiringManifestModEntry`): a MOUNTED registration `{ name, seat, tier, events, observe?, skipped? }` — `events` / `observe` are the patterns it actually
|
|
16853
|
+
hung (observe-only ones in `observe`), `skipped[]` the judges skipped while it was judged — or a REFUSED one `{ name, seat, tier, refusedBy, reason }`.
|
|
16854
|
+
Registrant strings (`name`, `refusedBy`, `reason`, every `skipped[]` member) go out through the server's one wire-text exit (credential shapes
|
|
16855
|
+
replaced, length-capped) — the same one the `engine_notice` `mods.registration_refused` detail uses, so the same refusal reads byte-equal on both;
|
|
16856
|
+
`seat` / `tier` / `events` / `observe` are engine words passed through verbatim (vocabulary owner core; read open). PRESENT IFF the leg carries a
|
|
16857
|
+
registration — on this server always (it mounts the permission-denied meter on every leg: `server.permission-denied-meter`; `TOOL_TRACE=true` adds
|
|
16858
|
+
`server.tool-trace`, a branded deployment `server.brand-identity`; a single-user request's `settings.hooks` is the task-seat registration
|
|
16859
|
+
`settings.hooks`). 🔴 ABSENCE READS "this leg carries no registration", NOT "no extension judges this leg's calls" (a delegated child can still be
|
|
16860
|
+
screened through an ancestor's chain). A row that reads as neither form is dropped individually; all dropped => key absent. EXCLUDED from
|
|
16861
|
+
`configFingerprint` (the task seat is per task). EFFECTIVE half only.
|
|
16862
|
+
items: { $ref: '#/components/schemas/WiringManifestModEntry' }
|
|
16329
16863
|
lsp:
|
|
16330
16864
|
allOf: [{ $ref: '#/components/schemas/WiringManifestLspSeam' }]
|
|
16331
16865
|
description: >
|
|
@@ -16400,6 +16934,12 @@ components:
|
|
|
16400
16934
|
(`capabilities.rewindFiles`); only a run the REQUEST word turned off cannot restore itself.
|
|
16401
16935
|
OPEN on read: the server does not enumerate the word (a present non-string is dropped), a third word passes
|
|
16402
16936
|
through — treat it as unknown. ABSENT = an older engine / external derivation, never "capturing".
|
|
16937
|
+
permissionMode:
|
|
16938
|
+
allOf: [{ $ref: '#/components/schemas/WiringManifestPermissionMode' }]
|
|
16939
|
+
description: >-
|
|
16940
|
+
server >= 7.133.0 (core 7.53.0; TENANT and OPERATOR faces alike) — this leg's PERMISSION-MODE receipt `{ requested?, effective, foldedBy? }`; the shell renders its mode indicator from `effective`
|
|
16941
|
+
(`foldedBy` present = the requested mode was folded), never from the word it sent. ABSENT = an older engine / server, not an assertion of the default mode. Effective half only (this frame);
|
|
16942
|
+
the same section rides the non-streaming `wiringManifest` receipt and the ledger row. Section shape: WiringManifestPermissionMode.
|
|
16403
16943
|
instructions:
|
|
16404
16944
|
allOf: [{ $ref: '#/components/schemas/WiringManifestInstructions' }]
|
|
16405
16945
|
description: >
|
|
@@ -16722,6 +17262,26 @@ components:
|
|
|
16722
17262
|
was armed but declined/failed (check the store, check authorisation), `false` = there was no lane at all
|
|
16723
17263
|
(wire one up). The two recovery verbs differ, so a consumer MUST render them apart — NEVER fold them into
|
|
16724
17264
|
one "nobody approved it".
|
|
17265
|
+
server 7.132.0 adds three codes to the user whitelist (appendix D.3 38 -> 41; all audience `user` in core's register) and changes one value:
|
|
17266
|
+
`config.session_rules_earlier_grammar` (core 7.53.0) — the session's STORED permission rules hold entries the grammar they were written in reads as nothing
|
|
17267
|
+
(an allow entry admits nothing; a `toolDeny` entry this engine reads as no rule makes those rules REFUSE EVERY CALL until an operator rewrites the row
|
|
17268
|
+
without its rev). `{ bucket, storedGrammar, entries: [{ entry, reader }], rewrite: { by, stampsGrammar }, rulesSessionId, sessionId }` — `entries` every
|
|
17269
|
+
one the engine handed over (the session-stream row passes the generic notice-detail bound: at most the first 32, no truncation mark — the full list is on
|
|
17270
|
+
the ops log line), `entry` the redacted rule text (the same reading as `permission.allowed_tool_not_granted`'s `entries[].entry`), `reader` one of
|
|
17271
|
+
`no_rule` / `named_no_tool`, `rewrite.by` = `operator_write_without_rev` (closed words owned by core, echoed — read open); `rulesSessionId` = whose
|
|
17272
|
+
rules (an ancestor's on a delegated child), `sessionId` = the run that read them. Once per distinct entry set per bucket per rule layer.
|
|
17273
|
+
`mods.registration_refused` (core 7.52.0) — an extension registration was NOT mounted (another registration's `plugin.register` judge refused it); the leg
|
|
17274
|
+
runs without it. `{ name, seat, tier, refusedBy, reason, sessionId }` — `seat` / `tier` engine words (echoed), `reason` the refusing registration's own
|
|
17275
|
+
words (UNTRUSTED-for-display); the same strings read byte-equal with the `wiring_manifest.mods[]` refused row. Unreachable on this server today (it wires
|
|
17276
|
+
no `plugin.register` judge). Once per leg per registration.
|
|
17277
|
+
`route.credential_origin_mismatch` (core 7.52.0) — a request was REFUSED and nothing was sent: this model's own credential is bound to the host it first
|
|
17278
|
+
went to and this request goes to another (the entry's `baseUrl` moved host, the credential stayed; a same-host path move does not count). The request's
|
|
17279
|
+
own failure carries the same code. `{ modelId, boundOrigin, requestOrigin, sessionId, runId }` — both origins in display spelling (scheme + host +
|
|
17280
|
+
port, no userinfo / path), never a credential or a digest of one. Once per run per (modelId, boundOrigin, requestOrigin). It replaces the retired
|
|
17281
|
+
operator code `route.base_url_changed_key_unchanged` (never on this whitelist). `config.credential_not_withheld` is operator-audience — ops log only.
|
|
17282
|
+
Value change: `permission.rule_row_dropped`'s `detail.rows[].rule` is, since core 7.53.0, the rule's original text (the same reading as
|
|
17283
|
+
`allowed_tool_not_granted`'s `entries[].entry`: at most 1 024 code points, longer cut to 1 024 + a truncation mark, CONTROL CHARACTERS RIDE AS DATA —
|
|
17284
|
+
neutralize at render); before it was the engine-neutralized single-line form (at most 201 code points). Same keys.
|
|
16725
17285
|
`server.model_unreachable` (server-minted, audience `user`; server >= 7.108.0, `taskId` added in server 7.121.0) — a model call on
|
|
16726
17286
|
this leg ended in error and its last request failed AT CONNECT (VPN switched mid-session / the proxy read at boot went stale / the
|
|
16727
17287
|
gateway is gone) — not the provider's answer. `{ code, targetHost, proxyInUse?, remedy, sessionId, taskId? }`: `code` one of the
|
|
@@ -16963,56 +17523,78 @@ components:
|
|
|
16963
17523
|
一律按不可分辨处理,消费方不要猜。
|
|
16964
17524
|
|
|
16965
17525
|
PromptManifest:
|
|
16966
|
-
# 新增(2026-07-25 回填批):server ≥1.219 的 prompt-assembly manifest。此前本文件完全没有它(全文 0 次提及),
|
|
16967
|
-
# 尽管它同时是 `AgentEvent.prompt_assembled` 臂和 trace 流 `prompt-assembled` 帧的载荷。
|
|
16968
17526
|
type: object
|
|
16969
17527
|
description: >
|
|
16970
|
-
The prompt
|
|
16971
|
-
|
|
16972
|
-
|
|
16973
|
-
|
|
16974
|
-
|
|
16975
|
-
|
|
16976
|
-
|
|
17528
|
+
The prompt manifest v3 (server >= 7.132.0 = engine 7.52.0 manifest v3; BREAKING): WHICH prompt this leg ran (`identity` + its selector values `selectors`),
|
|
17529
|
+
which blocks and sections it is made of, and where each section's text came from (`chain`; superseded overlays in `superseded`). IDs / sizes / digests
|
|
17530
|
+
only — NEVER prompt text. One row per prepare (cascade / verify re-prepare under one taskId, rows in order). Three exits carry the SAME stored row
|
|
17531
|
+
verbatim: the ledger replay `prompt_assembled`, the turns `prompt-assembled` block, the trace SSE `prompt-assembled` frame. Members = the engine frame
|
|
17532
|
+
minus its envelope (`kind` / `version` / `taskId` / `ts`) and `snapshot` / `lowering` (server `promptManifestRecordOf`).
|
|
17533
|
+
READING: EVERY member may be absent — an optional member absent means "none", never an empty value; a member present but unreadable is not put on the
|
|
17534
|
+
row (`identity` / `selectors` as whole sentences, sections / blocks / `superseded` / tools one row at a time), so a v3 row without `identity` means the
|
|
17535
|
+
engine's identity did not read (dropped and counted), NOT an old row. An empty list is a statement (`tools: []` = zero tools). Words (band names,
|
|
17536
|
+
activations, source classes, renderer ids, host role / form) are engine vocabulary, passed through verbatim — read open.
|
|
17537
|
+
🔴 THE ONE READING OF "WHICH PROMPT DID THIS LEG RUN" IS `identity`. BREAKING (no alias): v2's top-level `constitution` is gone (the constitution band
|
|
17538
|
+
is locked and engine-composed; a prompt carrying locked text verbatim is refused before the run, `prompt.assembled_role_refused`); `sections[]` lost
|
|
17539
|
+
`slot` / `carrier` / `cadence` / `cacheClass`, `hash` became `contentHash` (`sha256:` unsalted for published text, `salted:` for text carrying the task's
|
|
17540
|
+
or the run's own inputs) and gained `band` (always) / `variant?` / `renderer?` / `locale` / `chain`; the row gained `identity` / `selectors` / `superseded?`.
|
|
17541
|
+
⚠️ Rows written by <= 7.131.x keep the v2 shape (the server neither re-reads nor rewrites them) — see PromptManifestRow: a row carrying `constitution`
|
|
17542
|
+
is such an old row. ⚠️ Block `hash` is a PROCESS-SALTED short digest — not comparable across worker restarts.
|
|
17543
|
+
# 不封闭(`additionalProperties: true`):本 schema 是 `Event_prompt_assembled` 的 allOf 目标(帧上多一个 `type`),封闭会把合法帧判成违约(见 Event_reasoning 处的长注)。
|
|
17544
|
+
# 与旧行的互斥由 `not: { required: [constitution] }` 一句写死(v3 行永不带它),`PromptManifestRow` 的 oneOf 因此恰中一臂。
|
|
16977
17545
|
additionalProperties: true
|
|
17546
|
+
not: { required: [constitution] }
|
|
16978
17547
|
properties:
|
|
16979
|
-
|
|
16980
|
-
|
|
16981
|
-
|
|
16982
|
-
|
|
16983
|
-
|
|
17548
|
+
identity: { $ref: '#/components/schemas/PromptManifestIdentity' }
|
|
17549
|
+
selectors:
|
|
17550
|
+
type: object
|
|
17551
|
+
description: 'the run''s selector values (core `PromptManifestSelectors`) — the plain form of `identity.layers.binding`. `binding` = the scenario name (server >= 7.132.0 always writes `TaskSpec.promptBinding`).'
|
|
17552
|
+
additionalProperties: false
|
|
17553
|
+
required: [traits, host, facts]
|
|
17554
|
+
properties:
|
|
17555
|
+
binding: { type: string }
|
|
17556
|
+
traits: { type: array, items: { type: string } }
|
|
17557
|
+
host:
|
|
17558
|
+
type: object
|
|
17559
|
+
additionalProperties: false
|
|
17560
|
+
required: [role, form]
|
|
17561
|
+
properties:
|
|
17562
|
+
role: { type: string, description: 'engine word (`general` / `code` / `coordinator` / `cowork` today); read open.' }
|
|
17563
|
+
form: { type: string, description: 'engine word (`standard` / `minimal` today); read open.' }
|
|
17564
|
+
facts: { type: object, additionalProperties: { type: boolean } }
|
|
16984
17565
|
blocks:
|
|
16985
17566
|
type: array
|
|
16986
17567
|
items:
|
|
16987
17568
|
type: object
|
|
17569
|
+
additionalProperties: false
|
|
16988
17570
|
required: [id, chars, hash]
|
|
16989
|
-
additionalProperties: true
|
|
16990
17571
|
properties:
|
|
16991
17572
|
id: { type: string }
|
|
16992
17573
|
chars: { type: integer }
|
|
16993
|
-
hash: { type: string, description: 'process-salted digest — never compare across restarts.' }
|
|
17574
|
+
hash: { type: string, description: 'process-salted short digest — never compare across restarts.' }
|
|
16994
17575
|
sections:
|
|
16995
17576
|
type: array
|
|
16996
|
-
|
|
17577
|
+
items: { $ref: '#/components/schemas/PromptManifestSection' }
|
|
17578
|
+
superseded:
|
|
17579
|
+
type: array
|
|
17580
|
+
description: 'every overlay the composition superseded (a later one on the same target won, or it changed nothing this run); absent when none was.'
|
|
16997
17581
|
items:
|
|
16998
17582
|
type: object
|
|
16999
|
-
|
|
17000
|
-
|
|
17583
|
+
additionalProperties: false
|
|
17584
|
+
required: [id, source, by, target, supersededBy]
|
|
17001
17585
|
properties:
|
|
17002
17586
|
id: { type: string }
|
|
17003
|
-
|
|
17004
|
-
|
|
17005
|
-
|
|
17006
|
-
|
|
17007
|
-
chars: { type: integer }
|
|
17008
|
-
hash: { type: string }
|
|
17587
|
+
source: { type: string }
|
|
17588
|
+
by: { type: string }
|
|
17589
|
+
target: { type: string }
|
|
17590
|
+
supersededBy: { type: string, description: 'the winning overlay id, or the literal `(absent this run)`.' }
|
|
17009
17591
|
tools:
|
|
17010
17592
|
type: array
|
|
17011
|
-
description: '
|
|
17593
|
+
description: 'the mounted tools plane — per-tool contract identity, durable-replay aliases, shape digest and full wire-schema digest (initial mount face; deferred activations announce via tools_delta).'
|
|
17012
17594
|
items:
|
|
17013
17595
|
type: object
|
|
17596
|
+
additionalProperties: false
|
|
17014
17597
|
required: [wireName, aliases, contractId, implementationRevision, cardId, shapeDigest, wireSchemaDigest]
|
|
17015
|
-
additionalProperties: true
|
|
17016
17598
|
properties:
|
|
17017
17599
|
wireName: { type: string }
|
|
17018
17600
|
aliases: { type: array, items: { type: string } }
|
|
@@ -17021,7 +17603,72 @@ components:
|
|
|
17021
17603
|
cardId: { type: string }
|
|
17022
17604
|
shapeDigest: { type: string }
|
|
17023
17605
|
wireSchemaDigest: { type: string }
|
|
17606
|
+
toolDisclosure:
|
|
17607
|
+
type: object
|
|
17608
|
+
description: 'the resolved deferred-tool disclosure strategy (core `ToolDisclosureManifest`); absent when the leg deferred nothing.'
|
|
17609
|
+
additionalProperties: false
|
|
17610
|
+
required: [deferredTools, strategy, source]
|
|
17611
|
+
properties:
|
|
17612
|
+
deferredTools: { type: integer }
|
|
17613
|
+
strategy: { type: string, description: '`swap` / `static`; read open.' }
|
|
17614
|
+
source: { type: string, description: '`spec` / `env` / `default` / `degraded_no_direct_lane`; read open.' }
|
|
17024
17615
|
totalChars: { type: integer }
|
|
17616
|
+
PromptManifestIdentity:
|
|
17617
|
+
type: object
|
|
17618
|
+
description: 'the run''s prompt identity as the manifest reports it (core `PromptManifestIdentity`): `artifact` = the identity digest, `layers` = its inputs, `epoch` / `activatedBy` = the session epoch record that names it.'
|
|
17619
|
+
additionalProperties: false
|
|
17620
|
+
required: [artifact, layers, epoch, activatedBy]
|
|
17621
|
+
properties:
|
|
17622
|
+
artifact: { type: string }
|
|
17623
|
+
layers: { $ref: '#/components/schemas/PromptIdentityLayers' }
|
|
17624
|
+
epoch: { type: integer }
|
|
17625
|
+
activatedBy: { type: string, description: 'core `PROMPT_EPOCH_ACTIVATIONS` word; read open.' }
|
|
17626
|
+
PromptManifestSection:
|
|
17627
|
+
type: object
|
|
17628
|
+
description: 'one rendered section (core `PromptManifestSection`).'
|
|
17629
|
+
additionalProperties: false
|
|
17630
|
+
required: [id, band, rank, chars, locale, contentHash, chain]
|
|
17631
|
+
properties:
|
|
17632
|
+
id: { type: string }
|
|
17633
|
+
band: { type: string }
|
|
17634
|
+
rank: { type: number }
|
|
17635
|
+
variant: { type: string }
|
|
17636
|
+
renderer:
|
|
17637
|
+
type: object
|
|
17638
|
+
additionalProperties: false
|
|
17639
|
+
required: [id, version]
|
|
17640
|
+
properties:
|
|
17641
|
+
id: { type: string, description: 'core `RENDERER_IDS` word; read open.' }
|
|
17642
|
+
version: { type: number }
|
|
17643
|
+
chars: { type: integer }
|
|
17644
|
+
locale: { type: string, description: '`canonical` (the catalog''s text) / `overlay` (text an overlay author wrote); read open.' }
|
|
17645
|
+
contentHash: { type: string, description: '`sha256:<hex>` unsalted for published text, `salted:<hex>` for text carrying the task''s or the run''s own inputs.' }
|
|
17646
|
+
chain:
|
|
17647
|
+
type: array
|
|
17648
|
+
items:
|
|
17649
|
+
type: object
|
|
17650
|
+
additionalProperties: false
|
|
17651
|
+
required: [source]
|
|
17652
|
+
properties:
|
|
17653
|
+
source: { type: string, description: '`bundled` or an overlay source class; read open.' }
|
|
17654
|
+
overlay: { type: string }
|
|
17655
|
+
op: { type: string }
|
|
17656
|
+
superseded: { const: true }
|
|
17657
|
+
PromptManifestRetiredRow:
|
|
17658
|
+
type: object
|
|
17659
|
+
description: >
|
|
17660
|
+
A `prompt_assembled` row written by a <= 7.131.x server (the v2 shape: top-level `constitution` + slot-keyed sections). The server neither re-reads nor
|
|
17661
|
+
rewrites it, so a run parked before the upgrade and resumed after carries both shapes in its ledger. The ONE discriminator (owned by the server contract):
|
|
17662
|
+
`constitution` present <=> an old row (old rows always carry it, v3 rows never do). Its members are deliberately NOT typed here (the v2 reading is retired).
|
|
17663
|
+
required: [constitution]
|
|
17664
|
+
additionalProperties: true
|
|
17665
|
+
properties:
|
|
17666
|
+
constitution: { type: string }
|
|
17667
|
+
PromptManifestRow:
|
|
17668
|
+
description: 'One row on the three manifest exits: a v3 row (PromptManifest) or an old row (PromptManifestRetiredRow) — tell them apart by the presence of `constitution`.'
|
|
17669
|
+
oneOf:
|
|
17670
|
+
- $ref: '#/components/schemas/PromptManifest'
|
|
17671
|
+
- $ref: '#/components/schemas/PromptManifestRetiredRow'
|
|
17025
17672
|
|
|
17026
17673
|
Event_file_link:
|
|
17027
17674
|
type: object
|
|
@@ -17053,7 +17700,7 @@ components:
|
|
|
17053
17700
|
manifest's own keys sit at the top level next to `type`, they are NOT nested under a `manifest` key).
|
|
17054
17701
|
Lands AHEAD of the first event of the turn it prepared. ⚠️ MULTIPLE per task on cascade/verify runs.
|
|
17055
17702
|
allOf:
|
|
17056
|
-
- $ref: '#/components/schemas/
|
|
17703
|
+
- $ref: '#/components/schemas/PromptManifestRow'
|
|
17057
17704
|
required: [type]
|
|
17058
17705
|
properties:
|
|
17059
17706
|
type: { const: prompt_assembled }
|
|
@@ -17172,7 +17819,7 @@ components:
|
|
|
17172
17819
|
payload carried `type` (the read boundary emits `{type, ...data}`) so runtime discrimination worked,
|
|
17173
17820
|
but a generated client had nothing to switch on and dropped approval cards. That gap is closed.
|
|
17174
17821
|
The shell renders `tool_approval` as the three-choice card and dismisses it on `tool_approval_complete`.
|
|
17175
|
-
Respond via POST /v1/tool-approvals/{
|
|
17822
|
+
Respond via POST /v1/tool-approvals/{id}/respond.
|
|
17176
17823
|
required: [type, approvalId]
|
|
17177
17824
|
additionalProperties: true
|
|
17178
17825
|
properties:
|
|
@@ -17304,15 +17951,16 @@ components:
|
|
|
17304
17951
|
(no alias): the allow-layer members that MATCHED this call and could NOT clear this ask, one `{ member, entries, omitted? }` record per
|
|
17305
17952
|
matching member (see AllowRuleShadow). `member` is one of `hook` / `deployment` / `persisted` / `skill` / `request`; `entries` are the
|
|
17306
17953
|
entries that member matched, as their source spells them (UNTRUSTED for display like `message`, secret-redacted, <= 512 chars each,
|
|
17307
|
-
<= 32 listed; a `hook` record's `entries`
|
|
17954
|
+
<= 32 listed; a `hook` record's `entries` names the answering registration — server >= 7.132.0 / engine 7.52.0 mods: on this server only the
|
|
17955
|
+
request's own `settings.hooks` answers, so `["settings.hooks"]`; it was always the empty list on <= 7.131.x); `omitted` counts the entries not listed.
|
|
17308
17956
|
|
|
17309
17957
|
The explaining sentence ("... matches this call but does not clear the ask — <reason>") is IN `message` (the engine writes it where it builds
|
|
17310
17958
|
the card); this key is the structured twin of the same fact. Render a line from it ("your rule matched, but this call must be confirmed each
|
|
17311
17959
|
time"): without it the only conclusion a user can draw is "my rule broke".
|
|
17312
17960
|
|
|
17313
17961
|
🔴 ABSENT != "you have no rule": present only when a member matched AND could not clear the ask; a match that cleared never becomes an ask.
|
|
17314
|
-
🔴 `member: "hook"`
|
|
17315
|
-
|
|
17962
|
+
🔴 `member: "hook"` names the answering registration in `entries` (server >= 7.132.0; the deployment seat's registrations are observers and never
|
|
17963
|
+
answer — on <= 7.131.x the record could not say whose hook). 🔴 Deliberately SEPARATE from `governanceForced` (that one: "who imposed the gate"; this one: "what happened to YOUR
|
|
17316
17964
|
rule"). What the allow layer can NOT clear: any layer's deny / ask rule, operator `APPROVAL_REQUIRE` / `APPROVAL_NEVER_AUTO` /
|
|
17317
17965
|
`MANUAL_MODE_SHELL_GATE=always`, write protection, sensitive-path writes, governance, a hook's ask, plan-mode asks. The durable dual is
|
|
17318
17966
|
`gate.riskDescriptor.allowRuleShadowed` on the parked row (PendingCheckpoint.riskDescriptor). Rolling-upgrade caveat: a card stored by a
|
|
@@ -17567,8 +18215,8 @@ components:
|
|
|
17567
18215
|
|
|
17568
18216
|
# ── design/172 流内审批协议(#151)—— 已随 server 7.3.0 上线;开关 STREAM_APPROVAL_ENABLED 的默认值
|
|
17569
18217
|
# 分两段:server ≤7.4.0 默认 OFF,≥7.5.0 默认 ON(BREAKING,见 server CHANGELOG)。──
|
|
17570
|
-
# 与上面的 ToolApprovalFrame
|
|
17571
|
-
#
|
|
18218
|
+
# 与上面的 ToolApprovalFrame 是两个帧族,**一条腿只走一个**(server >= 7.133.0,capabilities.approvalFrameFamilies):呈卡协议上场的腿上一只 ask 只出本族的帧、
|
|
18219
|
+
# 旧族一帧都不发,消费端不再按 `approvalId` 去重;≤7.132.x 的呈卡腿两族并发(先 tool_approval、后 approval_request,同带 `approvalId`)⇒ 按它去重、优先渲染新帧。
|
|
17572
18220
|
classifierUnavailable:
|
|
17573
18221
|
$ref: '#/components/schemas/ClassifierUnavailable'
|
|
17574
18222
|
description: >-
|
|
@@ -17610,6 +18258,14 @@ components:
|
|
|
17610
18258
|
(a malformed shape, or a `dir` over 1024 UTF-16 code units ⇒ the key is ABSENT — never truncated,
|
|
17611
18259
|
because a truncated directory is a DIFFERENT directory and adding it would not clear this ask;
|
|
17612
18260
|
see the STRING-LENGTH UNIT convention in `info.description` for this `maxLength`'s counting unit).
|
|
18261
|
+
covers:
|
|
18262
|
+
allOf: [{ $ref: '#/components/schemas/ReadRootCover' }]
|
|
18263
|
+
description: >-
|
|
18264
|
+
Optional (engine core 7.22.0 `ReadRootGrantCandidate.covers`; the server carries it through key by key). ABSENT ⇒ `dir` is a DIRECTORY
|
|
18265
|
+
(adding it to the read roots releases what lies under it). `exact` ⇒ `dir` is the path the command NAMED, offered verbatim
|
|
18266
|
+
(a file or one concrete path, not a directory containing it): the consumer ADDS the string itself — expanding it into a
|
|
18267
|
+
pattern grants nothing — and must not render the offer as "add directory". The domain is the single word `exact`
|
|
18268
|
+
(a word outside it makes the server drop the whole candidate). The `approval_request` frame reads this very definition.
|
|
17613
18269
|
clearsThisAsk:
|
|
17614
18270
|
type: boolean
|
|
17615
18271
|
enum: [true]
|
|
@@ -17690,8 +18346,23 @@ components:
|
|
|
17690
18346
|
approvalId:
|
|
17691
18347
|
type: string
|
|
17692
18348
|
description: >
|
|
17693
|
-
|
|
17694
|
-
|
|
18349
|
+
The id of POST /v1/tool-approvals/{id}/respond and GET /v1/tool-approvals/{id}. server >= 7.133.0: ALWAYS EQUAL TO `askId` (the row's key is the ask's one wire
|
|
18350
|
+
identity; a 64-character lowercase hexadecimal string — treat it as an OPAQUE string, never parse it as a uuid); the matching close frame `approval_complete` carries it too.
|
|
18351
|
+
On server <= 7.132.x it is the legacy bridge / dedupe key (a uuid, the same value as the parallel tool_approval frame).
|
|
18352
|
+
# ── server >= 7.133.0: the TEN off-card LIVE facts on the opening frame's top level (one frame family per leg) ──────────────────────────
|
|
18353
|
+
# Same keys, same shapes, same values as on the legacy `tool_approval` frame (each is a `$ref` into ToolApprovalFrame's own property — one
|
|
18354
|
+
# source per shape). Only the frame minted LIVE carries them (and what the durable ledger recorded of that frame): a disconnect-replay frame
|
|
18355
|
+
# (rebuilt from `card_json`) never does. Absence means "this frame does not carry it", not "there is none". See APPROVAL_REQUEST_LIVE_FACT_KEYS (sdk) / the server's twin.
|
|
18356
|
+
mandated: { $ref: '#/components/schemas/ToolApprovalFrame/properties/mandated' }
|
|
18357
|
+
mandate: { $ref: '#/components/schemas/ToolApprovalFrame/properties/mandate' }
|
|
18358
|
+
origin: { $ref: '#/components/schemas/ToolApprovalFrame/properties/origin' }
|
|
18359
|
+
boundGrantDigest: { $ref: '#/components/schemas/ToolApprovalFrame/properties/boundGrantDigest' }
|
|
18360
|
+
boundGrants: { $ref: '#/components/schemas/ToolApprovalFrame/properties/boundGrants' }
|
|
18361
|
+
classifierNoRuling: { $ref: '#/components/schemas/ToolApprovalFrame/properties/classifierNoRuling' }
|
|
18362
|
+
boundGrantAbsence: { $ref: '#/components/schemas/ToolApprovalFrame/properties/boundGrantAbsence' }
|
|
18363
|
+
approvalCard: { $ref: '#/components/schemas/ToolApprovalFrame/properties/approvalCard' }
|
|
18364
|
+
readRootCandidate: { $ref: '#/components/schemas/ToolApprovalFrame/properties/readRootCandidate' }
|
|
18365
|
+
probeReason: { $ref: '#/components/schemas/ToolApprovalFrame/properties/probeReason' }
|
|
17695
18366
|
|
|
17696
18367
|
ApprovalCard:
|
|
17697
18368
|
type: object
|
|
@@ -17756,7 +18427,7 @@ components:
|
|
|
17756
18427
|
items: { $ref: '#/components/schemas/AllowRuleShadow' }
|
|
17757
18428
|
description: >
|
|
17758
18429
|
ADDITIVE (server >= 7.117.0 / core 7.42.0, BREAKING RENAME of the retired `persistedRuleShadowed`): the allow-layer members that matched this
|
|
17759
|
-
call and could not clear this ask. Semantics, the five members, the
|
|
18430
|
+
call and could not clear this ask. Semantics, the five members, the `hook` record naming its registration (server >= 7.132.0; always empty before), the explaining sentence living in `message`,
|
|
17760
18431
|
the ABSENT != "you have no rule" clause and the separation from `governanceForced` are stated verbatim on ToolApprovalFrame.allowRuleShadowed
|
|
17761
18432
|
— the live frame, the stored `card_json`, the replayed frame and the `approval_request` card carry the SAME material.
|
|
17762
18433
|
fromSubagent: { type: boolean, enum: [true], description: 'Present ⇔ the ask comes from a DELEGATED child — the explicit discriminator (a worker cannot forge it).' }
|
|
@@ -17954,6 +18625,13 @@ components:
|
|
|
17954
18625
|
and a word outside the set all read as ABSENT — a card without this word must not be treated as "approving it grants nothing else"; whether to render "allow for this session" is `rememberRefused`.
|
|
17955
18626
|
Display metadata, never an adjudication input. CLOSED: the server narrows with the engine's members, anything else reads as absent.
|
|
17956
18627
|
|
|
18628
|
+
ReadRootCover:
|
|
18629
|
+
type: string
|
|
18630
|
+
enum: [exact]
|
|
18631
|
+
description: >
|
|
18632
|
+
The closed vocabulary of `readRootCandidate.covers` (engine core 7.22.0 `ReadRootGrantCandidate.covers`; the server's narrow read `readReadRootCandidate` drops the whole
|
|
18633
|
+
candidate for a word outside it). One word today: `exact` — `dir` is the path the command NAMED, not a directory containing it. The SDK exports the same table as
|
|
18634
|
+
`READ_ROOT_COVERS` and its `isApprovalRequestFrameV1` judges `covers` by membership in it; a source-level anchor reads the word off the server's minting site and the engine's type.
|
|
17957
18635
|
PersistedRuleMandate:
|
|
17958
18636
|
type: string
|
|
17959
18637
|
enum: [operator_always, tool_marks, probe_mandate, probe_unanswered, write_protection, target_unresolved]
|
|
@@ -18367,6 +19045,40 @@ components:
|
|
|
18367
19045
|
depth: { type: integer, description: 'Delegation depth (a direct child of the host = 1).' }
|
|
18368
19046
|
agentName: { type: string, description: 'Child agent name. UNTRUSTED — spawning-model free text (server-redacted and length-bounded).' }
|
|
18369
19047
|
|
|
19048
|
+
ApprovalCompleteFrame:
|
|
19049
|
+
type: object
|
|
19050
|
+
description: >
|
|
19051
|
+
The CLOSE frame of the card family (`approval_complete`; server >= 7.133.0; SSE, `type` IS the event name; the durable leg appends the same frame, so it replays through
|
|
19052
|
+
GET /v1/runs/:id/events as the `Event_approval_complete` arm). ONE FRAME FAMILY PER LEG: on a leg where the card protocol is on (`capabilities.approvalFrameFamilies`
|
|
19053
|
+
= `["approval_request"]`) one ask travels only `approval_request` -> `approval_complete` / `approval_revoke`; the legacy `tool_approval` / `tool_approval_complete` pair is NOT sent
|
|
19054
|
+
(BREAKING vs <= 7.132.x, which sent both families for one ask; remedy on the worker: `STREAM_APPROVAL_ENABLED=false`).
|
|
19055
|
+
Same meaning as the legacy `tool_approval_complete` (one settle, one verdict: the `outcome` three words, the non-human `cause`, the park-route `parked`); dismiss the card by the opening frame's
|
|
19056
|
+
`askId`. Division of labour with ApprovalRevokeFrame: the revoke frame is BATCH-level (siblings voided by a winner), this one is the SINGLE card's end (answered / window expired / park route / cancelled);
|
|
19057
|
+
one ask can receive both — clearing by `askId` is enough. The gate is "this connection's opening frame was actually delivered". The frame is a notification, the row is the source of truth: a lost
|
|
19058
|
+
frame is compensated by the open-stream preamble (see ApprovalRequestFrame). THIS SCHEMA DESCRIBES v1 ONLY (read it as ApprovalFrameEnvelope first; the SDK's `isApprovalCompleteFrameV1` narrows).
|
|
19059
|
+
required: [type, schemaVersion, askId, taskId, approvalId, outcome, serverNowMs]
|
|
19060
|
+
additionalProperties: true
|
|
19061
|
+
properties:
|
|
19062
|
+
type: { type: string, enum: [approval_complete] }
|
|
19063
|
+
schemaVersion: { type: integer, enum: [1], description: 'This schema describes v1 only (see ApprovalFrameEnvelope for the unknown-version read).' }
|
|
19064
|
+
askId: { type: string, description: 'The durable identity — dismiss the card by it (the same key as the opening frame''s `askId`).' }
|
|
19065
|
+
taskId: { type: string, description: 'wire run id (same as the opening frame).' }
|
|
19066
|
+
approvalId: { type: string, description: 'Always equal to `askId` (same as the opening frame).' }
|
|
19067
|
+
outcome:
|
|
19068
|
+
type: string
|
|
19069
|
+
enum: [allowed, denied, expired]
|
|
19070
|
+
description: 'How the ask settled — the same three words as the legacy frame: `allowed` / `denied` = a decision; `expired` = a non-human ending (the reason is in `cause`).'
|
|
19071
|
+
cause:
|
|
19072
|
+
allOf: [{ $ref: '#/components/schemas/ApprovalSettleCause' }]
|
|
19073
|
+
description: >-
|
|
19074
|
+
The non-human ending''s cause (present only on `outcome: "expired"`; the fourteen words of the approval seat''s ending-cause set, the same word as on the audit settle row). A human answer carries none.
|
|
19075
|
+
ABSENCE IS NOT EVIDENCE.
|
|
19076
|
+
parked:
|
|
19077
|
+
type: boolean
|
|
19078
|
+
enum: [true]
|
|
19079
|
+
description: 'TRUE-ONLY: this ask itself ended on the park route (row moved to PARKING / PARKED; a late answer is reachable). Absent = no evidence — NEVER read as a real denial.'
|
|
19080
|
+
serverNowMs: { type: integer, description: 'Server clock at mint time.' }
|
|
19081
|
+
|
|
18370
19082
|
ApprovalRevokeFrame:
|
|
18371
19083
|
type: object
|
|
18372
19084
|
description: >
|
|
@@ -18666,7 +19378,7 @@ components:
|
|
|
18666
19378
|
description: >
|
|
18667
19379
|
server >= 7.126.0 (sdk 21.1.0 `APPROVAL_DECIDE_GATE_KINDS`, verbatim and in order; single owner = server
|
|
18668
19380
|
`APPROVAL_GATE_KINDS`) — the parked gate kinds the DURABLE decision door `POST /v1/approvals/{sessionId}/decide`
|
|
18669
|
-
accepts (the live `POST /v1/tool-approvals/{
|
|
19381
|
+
accepts (the live `POST /v1/tool-approvals/{id}/respond` answers the same card family). A parked row of
|
|
18670
19382
|
kind `plan_review` goes to the plan-review door instead (`PlanReviewGateKind`); `resource_limit` / `needs_review` /
|
|
18671
19383
|
`task_done` have no human decision door (resume / terminal). Clients route a pending row by reading this set,
|
|
18672
19384
|
never by a hand-written copy of it.
|
|
@@ -18681,7 +19393,7 @@ components:
|
|
|
18681
19393
|
enum: [person, policy]
|
|
18682
19394
|
description: >
|
|
18683
19395
|
server >= 7.118.0 (`APPROVAL_DECIDED_BY`, verbatim and in order) — WHO made an approval decision, one key on all three decision
|
|
18684
|
-
doors (live `POST /v1/tool-approvals/{
|
|
19396
|
+
doors (live `POST /v1/tool-approvals/{id}/respond`, durable `POST /v1/tasks/{taskId}/asks/{askId}/decision`, durable
|
|
18685
19397
|
`POST /v1/approvals/{sessionId}/decide`). `person` = a person decided through the approval channel (ABSENT means this);
|
|
18686
19398
|
`policy` = this deployment's own policy decided (a rule / posture answering on someone's behalf, a headless lane) — BOTH
|
|
18687
19399
|
directions: the engine records `tool_end.gate.settlement.kind` = `policy_allowed` / `policy_refused` (`who.party: "policy"`).
|
|
@@ -18773,6 +19485,20 @@ components:
|
|
|
18773
19485
|
`updatedInputForwarded` this field IS persisted, so an idempotent replay DOES promise byte-identity.
|
|
18774
19486
|
The 409 `conflict.ask_decided` body echoes the same field — and there it is always the FIRST
|
|
18775
19487
|
decision's note, not the one the rejected request carried.
|
|
19488
|
+
noteRecorded:
|
|
19489
|
+
type: boolean
|
|
19490
|
+
description: >
|
|
19491
|
+
server >= 7.133.0, ADDITIVE: did the `note` THIS request carried land as the row's text? Present ONLY when the request carried a `note`. `true` <=> the row's `decisionNote` is
|
|
19492
|
+
verbatim the text this request submitted (text that happens to be identical counts even if someone else wrote it first); `false` = not confirmed (the row holds another reason /
|
|
19493
|
+
the store could not be read back). Same shape and meaning as `noteRecorded` on the live respond ack and on its replayed arm (one judgement for the three doors). Carried by the
|
|
19494
|
+
first-decision and idempotent-replay forms; the PARKED redemption leg does not carry it (read it as unknown). ABSENT is not `false`.
|
|
19495
|
+
consumerState:
|
|
19496
|
+
type: string
|
|
19497
|
+
enum: [absent]
|
|
19498
|
+
description: >
|
|
19499
|
+
TRUE-ONLY disclosure (present as `absent`): no engine leg on THIS replica is waiting for this ask — the decision is on the row (an idempotent replay will read it, the audit surface keeps it)
|
|
19500
|
+
but nothing running here resumes because of it (the holder of the suspended promise may be another replica, or this replica restarted and its local window is empty). Read the RUN surface to
|
|
19501
|
+
learn whether anything continued; NEVER take a 200 without this key as proof the run continued (older servers never send it). Not a 409 / 410: the decision DID take effect.
|
|
18776
19502
|
|
|
18777
19503
|
QuestionFrame:
|
|
18778
19504
|
type: object
|
|
@@ -19067,6 +19793,31 @@ components:
|
|
|
19067
19793
|
outcome: { type: string }
|
|
19068
19794
|
trigger: { type: string, description: 'engine-shaped; current emitters send auto | manual | forced' }
|
|
19069
19795
|
reason: { type: string }
|
|
19796
|
+
pass:
|
|
19797
|
+
type: string
|
|
19798
|
+
description: >-
|
|
19799
|
+
server >= 7.132.0 (core 7.53.0 #2008): the id of the pass this frame CONCLUDES (= its `compaction_started.pass`). PRESENT <=> that pass announced a start,
|
|
19800
|
+
so only on `failed` / `mooted` (a pass that ran its summary and did not land, or was cut while it ran — `mooted` with `reason: "task_ending"` = the task's
|
|
19801
|
+
own end cut the running summary, a form this frame closes since core 7.53.0). `blocked` / `suppressed` / `disabled` / `noop` and a manual request no
|
|
19802
|
+
boundary served carry none (those passes never started).
|
|
19803
|
+
eventId: { type: string }
|
|
19804
|
+
parentToolCallId: { type: string }
|
|
19805
|
+
Event_compaction_started:
|
|
19806
|
+
type: object
|
|
19807
|
+
description: >
|
|
19808
|
+
server >= 7.132.0 (core 7.53.0 #2008) — a compaction pass is UNDER WAY: announced at the pass's commit point (trigger gate passed, a cut point exists,
|
|
19809
|
+
`preCompact` did not block), BEFORE the summary call, so a summary waiting out a provider's retries is no longer silent on the stream. Projected verbatim by
|
|
19810
|
+
ONE whitelist builder (server `compactionStartedEventData`) on the live stream and both durable ledgers (bg / resume; `GET /v1/runs/{id}/events`); the
|
|
19811
|
+
§2.3 trace stream does not carry it. PAIRING: exactly one frame concludes the pass with the SAME `pass` — `compacted` when it lands,
|
|
19812
|
+
`compaction_outcome` (`failed` / `mooted`) when it does not; "compacting" runs from this frame to that one (or the stream's end), elapsed = now − startedAt.
|
|
19813
|
+
A segment boundary, like `compacted` / `compaction_outcome`. Servers <= 7.131.x never send it. Identity: the same TWO keys as `compaction_outcome`.
|
|
19814
|
+
additionalProperties: false # 封闭:铸造点 `compactionStartedEventData` 只投这三键 + 身份两键
|
|
19815
|
+
required: [type, trigger, pass, startedAt]
|
|
19816
|
+
properties:
|
|
19817
|
+
type: { const: compaction_started }
|
|
19818
|
+
trigger: { type: string, description: 'the same vocabulary (and the same value) as the frame that concludes the pass — engine-shaped, read open; today auto | manual | forced.' }
|
|
19819
|
+
pass: { type: string, description: 'the pass identity: an opaque engine-minted id, unique across runs — pair on it alone.' }
|
|
19820
|
+
startedAt: { type: integer, description: 'engine clock, epoch ms, at the moment the pass committed.' }
|
|
19070
19821
|
eventId: { type: string }
|
|
19071
19822
|
parentToolCallId: { type: string }
|
|
19072
19823
|
Event_config_assembled:
|
|
@@ -19282,7 +20033,7 @@ components:
|
|
|
19282
20033
|
Event_tool_approval:
|
|
19283
20034
|
description: >
|
|
19284
20035
|
DURABLE-leg replay of the legacy tool-approval OPEN frame. Same payload as ToolApprovalFrame with the
|
|
19285
|
-
discriminant narrowed to `tool_approval`. Settle it via POST /v1/tool-approvals/{
|
|
20036
|
+
discriminant narrowed to `tool_approval`. Settle it via POST /v1/tool-approvals/{id}/respond.
|
|
19286
20037
|
Anchor the card on `toolCallId` (NOT `approvalId`); render `governanceForced` as a non-bypassable
|
|
19287
20038
|
"forced by governance" badge. UNTRUSTED for display: `message`/`args` are redacted but model-authored.
|
|
19288
20039
|
allOf:
|
|
@@ -19305,9 +20056,11 @@ components:
|
|
|
19305
20056
|
type: { type: string, enum: [tool_approval_complete] }
|
|
19306
20057
|
Event_approval_request:
|
|
19307
20058
|
description: >
|
|
19308
|
-
The design/172 in-stream approval card as an AgentEvent arm.
|
|
19309
|
-
|
|
19310
|
-
`
|
|
20059
|
+
The design/172 in-stream approval card as an AgentEvent arm. ONE FRAME FAMILY PER LEG (server >= 7.133.0,
|
|
20060
|
+
`capabilities.approvalFrameFamilies`): on a leg where the card protocol is on, one ask emits only this family
|
|
20061
|
+
(`approval_request` -> `approval_complete` / `approval_revoke`) and none of the legacy `tool_approval` family,
|
|
20062
|
+
so there is nothing to deduplicate. On server <= 7.132.x the two families ran side by side (legacy first) carrying
|
|
20063
|
+
the SAME `approvalId` — there, dedupe on it and prefer this arm. The decision key is `askId`; settle via
|
|
19311
20064
|
POST /v1/tasks/{taskId}/asks/{askId}/decision.
|
|
19312
20065
|
|
|
19313
20066
|
🔴 THIS ARM IS THE OPEN ENVELOPE, NOT `ApprovalRequestFrame`, AND THAT IS DELIBERATE. The v1 frame
|
|
@@ -19354,6 +20107,37 @@ components:
|
|
|
19354
20107
|
properties:
|
|
19355
20108
|
type: { type: string, enum: [approval_revoke] }
|
|
19356
20109
|
|
|
20110
|
+
Event_approval_complete:
|
|
20111
|
+
description: >
|
|
20112
|
+
The card family's single-card CLOSE frame as an AgentEvent arm (server >= 7.133.0). One frame family per leg: with `capabilities.approvalFrameFamilies` = `["approval_request"]` this frame
|
|
20113
|
+
REPLACES the legacy `tool_approval_complete` (one ask no longer travels two families). Live SSE and the durable ledger replay carry the same shape (same settle, same verdict: `outcome`,
|
|
20114
|
+
non-human `cause`, `parked`).
|
|
20115
|
+
🔴 THIS ARM IS THE OPEN ENVELOPE, NOT `ApprovalCompleteFrame` — same ruling as Event_approval_request / Event_approval_revoke: narrow with `schemaVersion == 1` (SDK:
|
|
20116
|
+
`isApprovalCompleteFrameV1`) before touching `outcome` / `cause` / `parked`; a frame that does not narrow still dismisses the card by its `askId` (when it has one) — never guess the outcome.
|
|
20117
|
+
🔴 Consumption discipline: (a) dismiss by the opening frame's `askId`; (b) a ledger-replayed frame is for TIMELINE RENDERING ONLY — the card-set baseline stays the open-stream preamble;
|
|
20118
|
+
(c) NEVER derive the run's fate from this frame (read the run row / checkpoint face); (d) it does not conflict with ApprovalRevokeFrame — one ask can receive both.
|
|
20119
|
+
allOf:
|
|
20120
|
+
- $ref: '#/components/schemas/ApprovalFrameEnvelope'
|
|
20121
|
+
- type: object
|
|
20122
|
+
required: [type]
|
|
20123
|
+
properties:
|
|
20124
|
+
type: { type: string, enum: [approval_complete] }
|
|
20125
|
+
Event_session_titled:
|
|
20126
|
+
description: >
|
|
20127
|
+
server >= 7.133.0 — the session title was WRITTEN (contract §4a-ttl): the title generator wrote the title into the session row and minted this frame on THE RUN'S LIVE STREAM afterwards.
|
|
20128
|
+
🔴 LIVE-ONLY, NEVER STORED: the session row (`GET /v1/sessions` list row `title`) is the single source of the title; this frame only says "the row just changed". It is not ledgered
|
|
20129
|
+
(GET /v1/runs/:id/events replay never carries it), not part of any replay surface, and has NO `eventId` (no SSE `id:` line, no part in the `Last-Event-ID` cursor). Only a leg holding a live stream
|
|
20130
|
+
receives it (today `POST /v1/tasks/stream`); the sync-JSON leg and the durable background leg structurally cannot. NOT sent when the session already has a title, on a user rename / pin
|
|
20131
|
+
(`PATCH /v1/sessions/{id}` does not go through the generator), with `SESSION_AUTO_TITLE=false`, after `done`, or once the connection is gone. THE FRAME MAY NOT ARRIVE — the title is whatever
|
|
20132
|
+
the session row says: refresh on the frame, read the row on cold start / another window / reconnect. `title` has passed the generator's redaction and cleaning and is the SAME value as the row's
|
|
20133
|
+
(still UNTRUSTED for display — model-authored text).
|
|
20134
|
+
type: object
|
|
20135
|
+
required: [type, sessionId, title]
|
|
20136
|
+
additionalProperties: false
|
|
20137
|
+
properties:
|
|
20138
|
+
type: { type: string, enum: [session_titled] }
|
|
20139
|
+
sessionId: { type: string, description: 'The session whose row was just written.' }
|
|
20140
|
+
title: { type: string, description: 'The title that landed in the session row (redacted and cleaned; bounded by the server''s TITLE_MAX_CHARS).' }
|
|
19357
20141
|
# ── resources/*.ts schema backfill, batch 2 (2026-07-28) — the 28-item WIRE_PENDING ratchet zeroed.
|
|
19358
20142
|
# Each schema below is cross-checked against the server source (file:line cited in its description
|
|
19359
20143
|
# or in the SDK resource JSDoc it mirrors). Wire objects are OPEN sets (additionalProperties: true).
|
|
@@ -19378,6 +20162,10 @@ components:
|
|
|
19378
20162
|
sessionId: { type: string, description: '`resolved` frames: which pending settled.' }
|
|
19379
20163
|
toolCallId: { type: string, description: '`resolved` frames: the settled pending''s bound tool-call id (absent when the pending carried none).' }
|
|
19380
20164
|
count: { type: integer, description: '`synced` frames: how many pendings the connect-time snapshot carried.' }
|
|
20165
|
+
checkpointId: { type: string, description: '`pending` frames only (server >= 7.133.0): the spread PendingCheckpoint row''s `checkpointId` (key absent when the row has no trusted value — read as "no joinable identity").' }
|
|
20166
|
+
consumerState: { type: string, enum: [absent], description: '`live_pending` frames only (server >= 7.133.0): the spread LivePendingRow''s true-only `consumerState` (no engine leg on this replica is waiting for the ask).' }
|
|
20167
|
+
errorCode: { type: string, description: '`error` frames: the machine code (`STREAM_MAX_DURATION` / `draining` / server >= 7.133.0 `approvals.read_unavailable` — the stream STAYS open, do NOT reconnect on it — / `approvals.read_corrupt` — a corrupt row was read, the server closes the stream after the frame).' }
|
|
20168
|
+
message: { type: string, description: '`error` frames: the human sentence (redacted); never match on it.' }
|
|
19381
20169
|
hasBidiControls:
|
|
19382
20170
|
type: boolean
|
|
19383
20171
|
enum: [true]
|
|
@@ -19498,20 +20286,24 @@ components:
|
|
|
19498
20286
|
|
|
19499
20287
|
FleetHookNotice:
|
|
19500
20288
|
description: >
|
|
19501
|
-
Hook observability payload,
|
|
20289
|
+
Hook observability payload, FOUR kinds (server >= 7.133.0 added `hook_managed_unrun` and `hook_verdict_untrusted`; service fleet-bus.ts `HookNotice` minus the wire-stripped
|
|
19502
20290
|
ownerScope/ownerSessionId — the payload view of FleetFrame_hook_notice; a discriminated union on
|
|
19503
20291
|
`kind`, mirroring the SDK type verbatim). Both kinds are pure observe — never block, resume, or
|
|
19504
20292
|
inject. Visibility is fail-CLOSED: a ?session= subscriber only receives notices provably owned by
|
|
19505
|
-
that session. `kind` is a CLOSED
|
|
20293
|
+
that session. `kind` is a CLOSED four-member set on the server (exhaustive-switch discipline) but
|
|
19506
20294
|
OPEN ON READ: degrade an unknown future kind to a generic observability row, never crash.
|
|
19507
20295
|
oneOf:
|
|
19508
20296
|
- $ref: '#/components/schemas/FleetHookDecisionUnavailable'
|
|
19509
20297
|
- $ref: '#/components/schemas/FleetHookNonBlockingFailure'
|
|
20298
|
+
- $ref: '#/components/schemas/FleetHookManagedUnrun'
|
|
20299
|
+
- $ref: '#/components/schemas/FleetHookVerdictUntrusted'
|
|
19510
20300
|
discriminator:
|
|
19511
20301
|
propertyName: kind
|
|
19512
20302
|
mapping:
|
|
19513
20303
|
hook_decision_unavailable: '#/components/schemas/FleetHookDecisionUnavailable'
|
|
19514
20304
|
hook_non_blocking_failure: '#/components/schemas/FleetHookNonBlockingFailure'
|
|
20305
|
+
hook_managed_unrun: '#/components/schemas/FleetHookManagedUnrun'
|
|
20306
|
+
hook_verdict_untrusted: '#/components/schemas/FleetHookVerdictUntrusted'
|
|
19515
20307
|
|
|
19516
20308
|
FleetHookDecisionUnavailable:
|
|
19517
20309
|
type: object
|
|
@@ -19546,7 +20338,7 @@ components:
|
|
|
19546
20338
|
reason:
|
|
19547
20339
|
# 🔴 NO `enum` — same open-on-read ruling as kind 1 (SDK type is `... | (string & {})`).
|
|
19548
20340
|
type: string
|
|
19549
|
-
description: 'Machine-branchable failure shape. CLOSED server-side, OPEN ON READ — KNOWN WORDS TODAY: exit_nonzero | timeout | spawn_failed | bad_json.'
|
|
20341
|
+
description: 'Machine-branchable failure shape. CLOSED server-side, OPEN ON READ — KNOWN WORDS TODAY: exit_nonzero | timeout | spawn_failed | bad_json | matcher_over_budget (server >= 7.133.0: the group matcher / the entry `if` name part did not finish evaluating within its 1000 ms budget on this name — NOT a broken hook script but an unevaluable selection condition; the server treats it as selected, the entry still runs; ONE frame per group, `if` one per entry, no exitCode / stderr).'
|
|
19550
20342
|
hookName: { type: string, description: 'Hook identity (statusMessage, else command/URL/prompt; redacted + bounded, http entries stripped of query/fragment). Always sent.' }
|
|
19551
20343
|
entryType: { type: string, description: 'command | http | prompt | agent — without it, hookName''s nature is a guess. Closed server-side, open on read. Always sent.' }
|
|
19552
20344
|
exitCode: { type: integer, description: 'Absent for timeout/spawn_failed (no exit code exists — the server never mints a legit-looking 0).' }
|
|
@@ -19554,6 +20346,57 @@ components:
|
|
|
19554
20346
|
stderr: { type: string, description: 'Redacted + truncated stderr digest (512-char cap incl. marker). Empty stderr => absent.' }
|
|
19555
20347
|
detail: { type: string, description: 'Redacted supplement (e.g. where an exit-2 had no venue). Additive / tolerate-absent.' }
|
|
19556
20348
|
|
|
20349
|
+
FleetHookManagedUnrun:
|
|
20350
|
+
type: object
|
|
20351
|
+
description: >
|
|
20352
|
+
Kind 3 (server >= 7.133.0): a MANAGED hook did not complete — the group carries a `source`; managed groups (`managedPolicy` / `managedPlugin:<name>`) are the organization policy's guard and run in an independent lane
|
|
20353
|
+
after the unmanaged rewrites, on the final input. A synchronous managed entry that gave neither a legal verdict (exit 0 with no verdict / a closed-set verdict) nor a legal veto (exit 2 / `decision:"block"` /
|
|
20354
|
+
`continue:false`) is "unrun": on `PreToolUse` the conclusion folds to `ask` when nothing vetoed (a person in the loop; unmanaged allows are not trusted; any phase's veto is still the last vote), on other events the
|
|
20355
|
+
conclusion is unchanged — but this frame is ALWAYS sent. One frame per unrun managed entry. The frame does NOT assert how the call ended (read the tool / approval frames).
|
|
20356
|
+
required: [kind, event, reason, source, hookName, entryType]
|
|
20357
|
+
additionalProperties: true
|
|
20358
|
+
properties:
|
|
20359
|
+
kind: { type: string, enum: [hook_managed_unrun] }
|
|
20360
|
+
event: { type: string, description: 'Which hook event. On PreToolUse this entry sets the managed lane: with no veto the call folds to `ask`.' }
|
|
20361
|
+
reason:
|
|
20362
|
+
# NO `enum` — same open-on-read ruling as kinds 1 and 2.
|
|
20363
|
+
type: string
|
|
20364
|
+
description: >-
|
|
20365
|
+
Why it did not complete. CLOSED on the server (thirteen words), OPEN ON READ — KNOWN WORDS TODAY: matcher_invalid | llm_carrier_unavailable | llm_cap | powershell_unsupported | if_unevaluable | budget_exhausted |
|
|
20366
|
+
spawn_failed | timeout | exit_nonzero | bad_json | decision_out_of_set | evidence_unavailable | rewrite_unsettled. `input_truncated` / `matcher_over_budget` are NOT in this kind (they belong to kind 4).
|
|
20367
|
+
source: { type: string, description: 'The group''s source word (`managedPolicy` or `managedPlugin:<name>`; the name is trace only, never a criterion).' }
|
|
20368
|
+
hookName: { type: string, description: 'Hook identity (same rule as kind 2); redacted + bounded.' }
|
|
20369
|
+
entryType: { type: string, description: 'command | http | prompt | agent — closed server-side, open on read.' }
|
|
20370
|
+
toolName: { type: string, description: 'Present on tool events.' }
|
|
20371
|
+
detail: { type: string, description: 'Redacted supplement.' }
|
|
20372
|
+
|
|
20373
|
+
FleetHookVerdictUntrusted:
|
|
20374
|
+
type: object
|
|
20375
|
+
description: >
|
|
20376
|
+
Kind 4 (server >= 7.133.0): a hook's VERDICT IS UNTRUSTED — one rule: an entry that did not get the complete payload, or was pulled in BY SELECTION by an over-budget matcher, has its VETO count (deny / exit 2 /
|
|
20377
|
+
`decision:"block"` / `continue:false` / ask) and its ALLOW and `updatedInput` NOT count. The rule holds on both lanes, so there is one frame; reason, lane and identity are machine fields. Emission condition per lane:
|
|
20378
|
+
managed = the entry ran with an untrusted cause (sent whatever it judged; `PreToolUse` then folds to `ask` when nothing vetoed); unmanaged = it gave an allow or a real rewrite (an identity echo does not count) that was
|
|
20379
|
+
dropped. Today only on `PreToolUse` (the event with an allow word). THE FRAME DOES NOT ASSERT HOW THE CALL ENDED: a managed entry that itself vetoes ends in deny with the frame sent; another trusted allow in the group still
|
|
20380
|
+
lets the call through — read the call's own result. NEVER infer a call outcome from any hook_notice frame.
|
|
20381
|
+
required: [kind, event, reason, lane, hookName, entryType]
|
|
20382
|
+
additionalProperties: true
|
|
20383
|
+
properties:
|
|
20384
|
+
kind: { type: string, enum: [hook_verdict_untrusted] }
|
|
20385
|
+
event: { type: string, description: 'Which hook event (today always PreToolUse).' }
|
|
20386
|
+
reason:
|
|
20387
|
+
# NO `enum` — same open-on-read ruling as kinds 1–3.
|
|
20388
|
+
type: string
|
|
20389
|
+
description: >-
|
|
20390
|
+
Why the verdict is untrusted. CLOSED on the server (two words), OPEN ON READ — KNOWN WORDS TODAY: input_truncated (the entry did not get the full payload: `tool_input` over the cap was replaced by a truncation marker, or a prompt /
|
|
20391
|
+
agent entry''s whole payload text was cut at the same cap) | matcher_over_budget (the group matcher / entry `if` name part ran past its budget and the entry ran BY SELECTION; the same moment also sends a kind-2 frame
|
|
20392
|
+
`matcher_over_budget`).
|
|
20393
|
+
lane: { type: string, description: 'The lane the entry sits in, read off the source table: `managedPolicy` / `managedPlugin:*` => `managed`, everything else and absent => `unmanaged`. Closed (two words) server-side, open on read. Read THIS field, never re-derive from `source`.' }
|
|
20394
|
+
hookName: { type: string, description: 'Hook identity (same rule as kind 2); redacted + bounded.' }
|
|
20395
|
+
entryType: { type: string, description: 'command | http | prompt | agent — closed server-side, open on read.' }
|
|
20396
|
+
toolName: { type: string, description: 'Present on tool events.' }
|
|
20397
|
+
source: { type: string, description: 'The source word the group declared (both lanes give it; ABSENT = the group declared none, so only unmanaged). Trace only, never a criterion.' }
|
|
20398
|
+
detail: { type: string, description: 'Redacted supplement (human-facing; machines read `reason` / `lane`).' }
|
|
20399
|
+
|
|
19557
20400
|
BakeStatus:
|
|
19558
20401
|
# 新(census 批2 四段)——server `BakeStatus`(plugins/store-contracts.ts), the COARSE lifecycle
|
|
19559
20402
|
# bakeView/claimResponse/bakesCreate all key on.
|
|
@@ -19874,7 +20717,7 @@ components:
|
|
|
19874
20717
|
description: >
|
|
19875
20718
|
🔴 ONE RULE FOR EVERY "EFFECTIVE HALF ONLY" KEY (sdk 9.7.0, after a codex adversarial-review [high]):
|
|
19876
20719
|
this schema's only consumer today is `GET /v1/diagnostics/wiring`'s `static` half, and every key marked
|
|
19877
|
-
"effective half only" (`leg`, `ask.effective`, `configFingerprint`, `tools`, `
|
|
20720
|
+
"effective half only" (`leg`, `ask.effective`, `configFingerprint`, `tools`, `mods`, `lsp`,
|
|
19878
20721
|
`modelGate`, `autoMode`, `writeProtection`, `readDeny`, `autoConsolidation`, `fileHistory`, `instructions`) is ALWAYS ABSENT on that
|
|
19879
20722
|
wire ⇒ THEIR ABSENCE HERE CARRIES NO INFORMATION. The per-key absence readings ("absent = not armed",
|
|
19880
20723
|
"absent = a third state", …) hold for the LIVE FRAME (`Event_wiring_manifest`) and must not be carried
|
|
@@ -20020,14 +20863,12 @@ components:
|
|
|
20020
20863
|
properties:
|
|
20021
20864
|
armed: { type: boolean }
|
|
20022
20865
|
reason: { type: string }
|
|
20023
|
-
|
|
20866
|
+
mods:
|
|
20024
20867
|
type: array
|
|
20025
20868
|
description: >
|
|
20026
|
-
core 7.
|
|
20027
|
-
|
|
20028
|
-
|
|
20029
|
-
Full per-key contract: see Event_wiring_manifest.hooks.
|
|
20030
|
-
items: { $ref: '#/components/schemas/WiringManifestHookEntry' }
|
|
20869
|
+
core 7.52.0, server >= 7.132.0 (BREAKING — replaces `hooks[]`) — the leg's mods admission record, one row per registration. EFFECTIVE half only (the
|
|
20870
|
+
diagnostics endpoint's static half never carries it). Full per-key contract: see Event_wiring_manifest.mods.
|
|
20871
|
+
items: { $ref: '#/components/schemas/WiringManifestModEntry' }
|
|
20031
20872
|
lsp:
|
|
20032
20873
|
allOf: [{ $ref: '#/components/schemas/WiringManifestLspSeam' }]
|
|
20033
20874
|
description: >
|
|
@@ -20065,6 +20906,11 @@ components:
|
|
|
20065
20906
|
K-24 (server >= 7.104.0 / S-724) — does this leg capture file history (`on` / `disabled`, OPEN word). EFFECTIVE
|
|
20066
20907
|
HALF ONLY ⇒ ALWAYS ABSENT ON THIS ENDPOINT; the deployment-level reading is `capabilities.fileHistoryCapture`.
|
|
20067
20908
|
Full per-key contract: see Event_wiring_manifest.fileHistory.
|
|
20909
|
+
permissionMode:
|
|
20910
|
+
allOf: [{ $ref: '#/components/schemas/WiringManifestPermissionMode' }]
|
|
20911
|
+
description: >-
|
|
20912
|
+
core 7.53.0, server >= 7.133.0 — the leg's permission-mode receipt (section shape WiringManifestPermissionMode). EFFECTIVE HALF ONLY ⇒ this (static) face NEVER carries it, and absence here carries no
|
|
20913
|
+
information; the reading holds only on a live `wiring_manifest` frame.
|
|
20068
20914
|
instructions:
|
|
20069
20915
|
allOf: [{ $ref: '#/components/schemas/WiringManifestInstructions' }]
|
|
20070
20916
|
description: >
|
|
@@ -20136,33 +20982,70 @@ components:
|
|
|
20136
20982
|
type: array
|
|
20137
20983
|
description: 'The selected chain member(s), spelled as the chain spells them (relative to the cwd); `[]` = the chain was walked, nothing was selected.'
|
|
20138
20984
|
items: { type: string, enum: ['CLAUDE.md', '.claude/CLAUDE.md', 'AGENTS.md', '.claude/AGENTS.md'] }
|
|
20139
|
-
|
|
20140
|
-
#
|
|
20141
|
-
|
|
20985
|
+
WiringManifestPermissionMode:
|
|
20986
|
+
# server 7.133.0 / core 7.53.0:同一段形被 live 帧(两张脸)、静态诊断面、`POST /v1/tasks` 的 `wiringManifest` 回执与账本行引用 ⇒ 具名单源(`spec-field-drift-gate` 也按「导出的 interface 必有同名 schema」逼出它)。
|
|
20987
|
+
type: object
|
|
20988
|
+
additionalProperties: false
|
|
20989
|
+
description: >
|
|
20990
|
+
The `wiring_manifest.permissionMode` section (core 7.53.0 `PermissionModeReceipt`; server >= 7.133.0 projects it on BOTH faces — tenant and operator — and the same section rides the `wiringManifest`
|
|
20991
|
+
receipt of the `POST /v1/tasks` 200 body and the `/events` ledger row; the server judges SHAPE only: `effective` a non-empty string, `requested` / `foldedBy` absent or non-empty strings, else the whole section
|
|
20992
|
+
is dropped). The engine gives the same three-member receipt on EVERY mode question: `requested` = the mode word the caller declared (ABSENT = declared nothing — a root inherits `default`, a child inherits its
|
|
20993
|
+
parent); `effective` = the mode the leg actually runs under (the request clamped under a parent's ceiling, then folded to `default` where the deployment denies it or the classifier face is absent) — ALWAYS present,
|
|
20994
|
+
the shell renders its mode indicator from it; `foldedBy` = PRESENT IFF `requested` and `effective` differ — `operator_deny` (the deployment / organization ceiling denies the mode) / `face_absent` (`auto` needs
|
|
20995
|
+
a classifier face this leg lacks) / `inherited_ceiling` (a delegated child clamped under its parent's ceiling); read OPEN (a fourth word passes through as "folded, cause unknown"). ABSENT section = an older
|
|
20996
|
+
engine / server (<= 7.132.x), not an assertion of the default mode. This is ONE added key on a closed object: a consumer validating `wiring_manifest` strictly against sdk <= 24.0.0's spec fails the whole frame
|
|
20997
|
+
on 7.133.0+ — upgrade to sdk 25.0.0 or relax unknown keys on this section.
|
|
20998
|
+
required: [effective]
|
|
20999
|
+
properties:
|
|
21000
|
+
requested: { type: string, description: 'The mode word the caller declared (a PermissionMode word today; read open). ABSENT = declared nothing.' }
|
|
21001
|
+
effective: { type: string, description: 'The mode the leg actually runs under (a PermissionMode word today; read open). Always present.' }
|
|
21002
|
+
foldedBy: { type: string, description: 'Present iff `requested` and `effective` differ: `operator_deny` / `face_absent` / `inherited_ceiling` (engine words; read OPEN — an unknown word means "folded, cause unknown").' }
|
|
21003
|
+
WiringManifestModEntry:
|
|
21004
|
+
# server 7.132.0 / core 7.52.0:取代钩子席位行形(删,零别名)。同一份行形被 live 帧与静态诊断面两处引用 ⇒ 具名;两形各自具名(⑤bis 名单逐形对账)。
|
|
21005
|
+
description: >
|
|
21006
|
+
One row of a leg's MODS ADMISSION record (core 7.52.0 `ModAdmissionRecord`; server >= 7.132.0): a registration that was mounted, or one that was refused.
|
|
21007
|
+
Discriminate on presence — a mounted row carries `events`, a refused row carries `refusedBy` + `reason` (never both).
|
|
21008
|
+
oneOf:
|
|
21009
|
+
- $ref: '#/components/schemas/WiringManifestModMounted'
|
|
21010
|
+
- $ref: '#/components/schemas/WiringManifestModRefused'
|
|
21011
|
+
WiringManifestModMounted:
|
|
20142
21012
|
type: object
|
|
20143
21013
|
description: >
|
|
20144
|
-
|
|
20145
|
-
|
|
21014
|
+
A MOUNTED registration: the patterns it actually hung (`events`), the ones it declared observe-only (`observe`, present iff any), and the judges skipped while it
|
|
21015
|
+
was judged (`skipped`, present iff non-empty — absence and an empty list are both "every judge answered").
|
|
20146
21016
|
additionalProperties: false
|
|
20147
|
-
required: [
|
|
21017
|
+
required: [name, seat, tier, events]
|
|
20148
21018
|
properties:
|
|
20149
|
-
|
|
20150
|
-
|
|
20151
|
-
|
|
20152
|
-
|
|
20153
|
-
|
|
20154
|
-
|
|
20155
|
-
|
|
20156
|
-
|
|
20157
|
-
|
|
20158
|
-
|
|
20159
|
-
|
|
20160
|
-
|
|
20161
|
-
|
|
20162
|
-
|
|
20163
|
-
|
|
20164
|
-
|
|
20165
|
-
|
|
21019
|
+
name: { type: string, description: 'the registration name (registrant text, through the server''s wire-text exit; UNTRUSTED-for-display).' }
|
|
21020
|
+
seat: { type: string, description: 'which seat it came from — core `MOD_SEATS` (`deployment` / `task`). Engine word, passed through verbatim; read open.' }
|
|
21021
|
+
tier: { type: string, description: 'its tier — core `MOD_TIERS` (`prepend` / `user` / `append` / `builtin` / `core`). Engine word, passed through verbatim; read open.' }
|
|
21022
|
+
events: { type: array, items: { type: string }, description: 'the event patterns it actually hung (engine words, verbatim).' }
|
|
21023
|
+
observe: { type: array, items: { type: string }, description: 'the patterns it hung observe-only (engine words, verbatim); absent = none.' }
|
|
21024
|
+
skipped:
|
|
21025
|
+
type: array
|
|
21026
|
+
description: 'judges the dispatch skipped while this registration was judged (core `ModSkip`); present iff non-empty. An element missing a member is dropped individually.'
|
|
21027
|
+
items:
|
|
21028
|
+
type: object
|
|
21029
|
+
additionalProperties: false
|
|
21030
|
+
required: [registration, cause, reason]
|
|
21031
|
+
properties:
|
|
21032
|
+
registration: { type: string, description: 'the skipped judge''s registration name (registrant text).' }
|
|
21033
|
+
cause: { type: string, description: 'why it did not answer for itself — core `MOD_FAILURE_CAUSES` today (`threw` / `timeout` / `violation` / `reentry`); read open.' }
|
|
21034
|
+
reason: { type: string, description: 'the judge''s own words (registrant text, UNTRUSTED-for-display).' }
|
|
21035
|
+
WiringManifestModRefused:
|
|
21036
|
+
type: object
|
|
21037
|
+
description: >
|
|
21038
|
+
A REFUSED registration: another registration's `plugin.register` judge refused it at admission; the leg runs without it. The same refusal also reaches
|
|
21039
|
+
the stream as the `engine_notice` `mods.registration_refused` (its `detail` strings read byte-equal with this row's). This deployment wires no
|
|
21040
|
+
`plugin.register` judge, so it cannot happen here today.
|
|
21041
|
+
additionalProperties: false
|
|
21042
|
+
required: [name, seat, tier, refusedBy, reason]
|
|
21043
|
+
properties:
|
|
21044
|
+
name: { type: string, description: 'the refused registration (registrant text).' }
|
|
21045
|
+
seat: { type: string, description: 'core `MOD_SEATS` word, verbatim; read open.' }
|
|
21046
|
+
tier: { type: string, description: 'core `MOD_TIERS` word, verbatim; read open.' }
|
|
21047
|
+
refusedBy: { type: string, description: 'the registration whose judge refused it (registrant text).' }
|
|
21048
|
+
reason: { type: string, description: 'the refusing judge''s own words (registrant text, UNTRUSTED-for-display).' }
|
|
20166
21049
|
WiringManifestLspSeam:
|
|
20167
21050
|
# sdk 9.5.0:同上 —— live 帧与静态面共用一份段形。
|
|
20168
21051
|
type: object
|
|
@@ -20339,7 +21222,9 @@ components:
|
|
|
20339
21222
|
description: >
|
|
20340
21223
|
server >= 7.60 (S-131) — this deployment's SQL engine posture (engine / version / session isolation
|
|
20341
21224
|
level / TiDB transaction mode), READ BACK off a live connection rather than echoed from env.
|
|
20342
|
-
`null` = no SQL backend.
|
|
21225
|
+
`null` = no SQL backend. server >= 7.132.0 adds three keys (additive): `maxRowBytes` / `maxPacketBytes` (the database's single-row / packet
|
|
21226
|
+
wall; `null` = that wall does not exist) and `wallSources` (each wall's provenance, `reported` / `assumed` — what a 413 body's `wallSource` reads).
|
|
21227
|
+
NOT YET MIRRORED KEY-BY-KEY in this SDK generation — read as opaque.
|
|
20343
21228
|
configApply:
|
|
20344
21229
|
type: ["object", "null"]
|
|
20345
21230
|
additionalProperties: true
|
|
@@ -20644,10 +21529,218 @@ components:
|
|
|
20644
21529
|
remember for this session's category (fs-write tools share ONE category: approving Write covers
|
|
20645
21530
|
Edit/NotebookEdit; other tools are per-tool) — the CC "don't ask again this session" semantic.
|
|
20646
21531
|
|
|
21532
|
+
ConfigCatalog:
|
|
21533
|
+
type: object
|
|
21534
|
+
description: >
|
|
21535
|
+
The 200 body of GET /v1/config/catalog (server `ConfigCatalogWire`) — a PROJECTION, left open on read (the producer ships independently and adds keys additively between SDK releases; the request side has no body).
|
|
21536
|
+
required: [catalogVersion, envLaneTiming, restartSlices, centerDomains, summary, rows, retired]
|
|
21537
|
+
additionalProperties: true
|
|
21538
|
+
properties:
|
|
21539
|
+
catalogVersion: { type: integer, enum: [1] }
|
|
21540
|
+
envLaneTiming: { type: string, description: 'The env lane''s uniform timing (`deploy`: env is immutable at runtime, so changing env = changing the deployment). Open on read.' }
|
|
21541
|
+
restartSlices: { type: array, items: { type: string }, description: 'The restart-slice names a centre write can land in (open on read).' }
|
|
21542
|
+
centerDomains: { type: array, items: { type: string }, description: 'The contract package''s centre-configuration domains.' }
|
|
21543
|
+
summary:
|
|
21544
|
+
type: object
|
|
21545
|
+
required: [total, envHeld, secret, centerManaged]
|
|
21546
|
+
additionalProperties: true
|
|
21547
|
+
properties:
|
|
21548
|
+
total: { type: integer }
|
|
21549
|
+
envHeld: { type: integer }
|
|
21550
|
+
secret: { type: integer }
|
|
21551
|
+
centerManaged: { type: integer }
|
|
21552
|
+
rows: { type: array, items: { $ref: '#/components/schemas/ConfigCatalogRow' } }
|
|
21553
|
+
retired: { type: array, items: { $ref: '#/components/schemas/ConfigCatalogRetiredEnv' }, description: 'Tombstoned env names this process refuses to start on (always present, may be empty). A name is never in `rows` and here at once.' }
|
|
21554
|
+
ConfigCatalogRow:
|
|
21555
|
+
type: object
|
|
21556
|
+
description: >
|
|
21557
|
+
One catalog row (server `ConfigCatalogRow`): a deployment knob's static declaration plus this process's effective reading. OPEN on read (projection). The two VERDICT bits are the true-only family:
|
|
21558
|
+
`effectiveValueInvalid` (the effective value fell outside the row's echo set; `effectiveValue` is `null`) and `effectiveValueWithheld` (server >= 7.133.0) — see the property.
|
|
21559
|
+
required: [name, domain, type, semantics, writeLanes, effectiveLane, envHeld, envTiming, effectiveValue, valueClass, danger]
|
|
21560
|
+
additionalProperties: true
|
|
21561
|
+
properties:
|
|
21562
|
+
name: { type: string, description: 'The knob (env) name; the catalog is sorted by it.' }
|
|
21563
|
+
domain: { type: string, description: 'One of the nine configuration groups (store / modelPlane / approval / memory / auth / orchestration / limitsHttp / observability / integrations). Open on read.' }
|
|
21564
|
+
type: { type: string, description: 'Value type: boolean | number | string | enum | csv | json | path | url | secret | opaque. Open on read.' }
|
|
21565
|
+
semantics: { type: string, description: 'Human sentence (true to the read site).' }
|
|
21566
|
+
writeLanes: { type: array, items: { type: string, enum: [env, center] }, description: 'Which lanes can write this knob.' }
|
|
21567
|
+
effectiveLane: { type: string, description: 'The lane actually in force: env | center | default. Open on read.' }
|
|
21568
|
+
envHeld: { type: boolean, description: 'This machine''s env sets it explicitly.' }
|
|
21569
|
+
envTiming: { type: string, description: '`deploy` (changing env = changing the deployment) | `inert` (retired / zero-consumer key). Open on read.' }
|
|
21570
|
+
staticDefault: { type: string }
|
|
21571
|
+
derivedDefaultNote: { type: string }
|
|
21572
|
+
effectiveValue:
|
|
21573
|
+
description: 'This process''s effective DISPLAY value: a scalar / a word list / `null` (unset) / `{ present, length? }` (`secret` / `opaque` rows report presence and length only).'
|
|
21574
|
+
oneOf:
|
|
21575
|
+
- { type: [string, number, boolean, 'null'] }
|
|
21576
|
+
- { type: array, items: { type: string } }
|
|
21577
|
+
- { type: object, required: [present], additionalProperties: true, properties: { present: { type: boolean }, length: { type: integer } } }
|
|
21578
|
+
valueClass: { type: string, description: '`plain` (echoable) | `secret` | `opaque` (the value never goes on the wire). Open on read.' }
|
|
21579
|
+
danger: { type: array, items: { type: string }, description: 'The risk axes of a wrong setting: security | billing | data (open on read).' }
|
|
21580
|
+
center: { $ref: '#/components/schemas/ConfigCatalogRowCenter' }
|
|
21581
|
+
centerDomain: { type: string }
|
|
21582
|
+
centerPath: { type: string }
|
|
21583
|
+
scope: { type: string, description: '`bootstrap-only` = read only at start-up.' }
|
|
21584
|
+
enumValues: { type: array, items: { type: string }, description: 'An `enum` row''s writable word set.' }
|
|
21585
|
+
effectiveValueInvalid:
|
|
21586
|
+
type: boolean
|
|
21587
|
+
enum: [true]
|
|
21588
|
+
description: 'TRUE-ONLY verdict bit: the effective value fell OUTSIDE the row''s own echo set (or a boolean without a declared mapping) — `effectiveValue` is then `null` (echoing an out-of-set value would teach a consumer to write back an illegal word). Enum rows only. ABSENT = this cell has no such matter.'
|
|
21589
|
+
effectiveValueWithheld:
|
|
21590
|
+
type: boolean
|
|
21591
|
+
enum: [true]
|
|
21592
|
+
description: >-
|
|
21593
|
+
server >= 7.133.0, TRUE-ONLY verdict bit on `type: url` rows (present only when true, never `false`): the display mint judged this cell (single value) or any item of it (list) WITHHELD — a part the position rule
|
|
21594
|
+
would have shown (the whole query / a path segment) was NOT shown because it held a credential-shaped piece. The mint owns the verdict; the catalog does not judge again. So the shown value is not the whole value:
|
|
21595
|
+
a catalog page / `sema config show` marks the row ("part of this value is withheld"), and must not read the shown value as "the value is exactly that". ABSENT = nothing withheld (older servers never send it).
|
|
21596
|
+
The standard position rule (userinfo landed, query values become tokens) holds for every row and is NOT a withholding; a value that became a placeholder as a whole means the row's display rule cannot show it
|
|
21597
|
+
(not a hierarchical URL; the two outbound-proxy rows show only scheme://host[:port]) — also not this bit.
|
|
21598
|
+
ConfigCatalogRowCenter:
|
|
21599
|
+
type: object
|
|
21600
|
+
description: 'A catalog row''s centre seat: whether the knob is centre-publishable, who wins, when it takes effect. Present only on rows with a centre seat.'
|
|
21601
|
+
required: [domain, path, precedence, timing, managedNow, effectiveNow]
|
|
21602
|
+
additionalProperties: true
|
|
21603
|
+
properties:
|
|
21604
|
+
domain: { type: string }
|
|
21605
|
+
path: { type: string, description: 'Path in the domain (`a.b` into objects; `xs[].c` into array elements).' }
|
|
21606
|
+
precedence: { type: string, description: '`center-wins` | `env-wins` (open on read).' }
|
|
21607
|
+
timing: { type: string, description: '`hot` | `restart` | `inert` (open on read; not `deploy`).' }
|
|
21608
|
+
restartSlice: { type: string }
|
|
21609
|
+
restartReason: { type: string }
|
|
21610
|
+
managedNow: { type: boolean, description: 'The centre''s latest effective config currently MANAGES this key (no config pipeline => always false).' }
|
|
21611
|
+
effectiveNow: { type: boolean, description: 'The centre write is in force right now (managed AND not held down by an env placeholder).' }
|
|
21612
|
+
ConfigCatalogRetiredEnv:
|
|
21613
|
+
type: object
|
|
21614
|
+
description: 'A tombstoned env name (the contract package''s RETIRED_ENVS wire projection): a name this process refuses to start on. `renamed` carries only `replacement`; `replaced` carries `replacement` + `reason` (how the value semantics changed); `removed` carries only `reason`.'
|
|
21615
|
+
required: [name, kind]
|
|
21616
|
+
additionalProperties: true
|
|
21617
|
+
properties:
|
|
21618
|
+
name: { type: string }
|
|
21619
|
+
kind: { type: string, description: '`renamed` | `replaced` | `removed` (open on read).' }
|
|
21620
|
+
replacement: { type: string }
|
|
21621
|
+
reason: { type: string }
|
|
21622
|
+
EntryProblem:
|
|
21623
|
+
type: object
|
|
21624
|
+
description: >
|
|
21625
|
+
One ENTRY PROBLEM (server >= 7.133.0): a refusal body's `detail.problems[]` element and an accept-time `warnings[]` element share this shape. `code` = the refusal code the problem belongs to (in `warnings[]`: the engine's
|
|
21626
|
+
reading code for that entry); `field` = the coordinate of the list holding the entry in the request body (`settings.permissions.allow`, `skills[i].allowedTools` …); `entry` = the entry string (passed through the server''s
|
|
21627
|
+
redaction mouth — not a guarantee of your original bytes); `reason` = the machine reason — mostly the ENGINE''s word verbatim (why it read the entry as nothing); the server mints two of its own, `not_in_roster` (accept-time
|
|
21628
|
+
warnings only: the name in an allow-side selector list is not in the roster and is no protocol namespace name — the engine accepts it anyway) and `home_unresolvable` (settings-rule 422: a `~/` path rule on a deployment that cannot
|
|
21629
|
+
resolve the execution environment''s home); and `below_trust_floor` (the caller''s trust tier is below the member''s admission floor — see ErrorResponse.detail.callerTrust). Read OPEN.
|
|
21630
|
+
required: [code, field, entry, reason]
|
|
21631
|
+
additionalProperties: false
|
|
21632
|
+
properties:
|
|
21633
|
+
code: { type: string }
|
|
21634
|
+
field: { type: string }
|
|
21635
|
+
entry: { type: string }
|
|
21636
|
+
reason: { type: string }
|
|
21637
|
+
PrincipalInboxMessage:
|
|
21638
|
+
type: object
|
|
21639
|
+
description: 'The request body of POST /v1/principal-inbox/messages: a CLOSED three-key shape (`from` is minted by the server from the verified identity and cannot be sent).'
|
|
21640
|
+
required: [to, content]
|
|
21641
|
+
additionalProperties: false
|
|
21642
|
+
properties:
|
|
21643
|
+
to: { type: string, minLength: 1, description: 'The recipient principal string. Must belong to the sender''s organization (the membership judgement reads the organization directory); a failed judgement is 404 `org_delivery.not_member`, byte-identical to "no such person".' }
|
|
21644
|
+
content: { type: string, minLength: 1, maxLength: 32000, description: 'The letter body (characters; over 32000 => 400 `request.field_invalid`).' }
|
|
21645
|
+
urgent: { type: boolean, description: 'The urgent flag on the envelope (absent = ordinary).' }
|
|
21646
|
+
PrincipalInboxReceipt:
|
|
21647
|
+
type: object
|
|
21648
|
+
description: 'The 200 receipt: the letter was appended. `receiptId` = the gate-minted delivery receipt id (the envelope''s `gateReceiptId` carries the same value).'
|
|
21649
|
+
required: [receiptId]
|
|
21650
|
+
additionalProperties: false
|
|
21651
|
+
properties:
|
|
21652
|
+
receiptId: { type: string }
|
|
21653
|
+
OrgDeliveryRefusalCode:
|
|
21654
|
+
type: string
|
|
21655
|
+
enum: [org_delivery.not_member, org_delivery.rate_limited, org_delivery.inbox_full, org_delivery.recipient_tombstoned]
|
|
21656
|
+
description: >
|
|
21657
|
+
The four cross-principal delivery refusal codes (server >= 7.133.0; the engine's closed `ORG_DELIVERY_REFUSAL_CODES`, one frozen sentence each — machines read the CODE): `org_delivery.not_member` (404),
|
|
21658
|
+
`org_delivery.rate_limited` (429), `org_delivery.inbox_full` (409), `org_delivery.recipient_tombstoned` (410). See POST /v1/principal-inbox/messages.
|
|
21659
|
+
ToolApprovalReadState:
|
|
21660
|
+
type: string
|
|
21661
|
+
enum: [pending, decided, parked, void]
|
|
21662
|
+
description: >
|
|
21663
|
+
`state` of GET /v1/tool-approvals/{id} (server >= 7.133.0), a CLOSED four-word set — read it exhaustively: `pending` = a live registration on this replica is waiting (answer door open);
|
|
21664
|
+
`decided` = the row is DECIDED; `parked` = PARKING / PARKED (a late answer redeems the parked card); `void` = DENIED / VOID (nobody decided it, the answer has nowhere to land).
|
|
21665
|
+
ApprovalsStreamReadErrorCode:
|
|
21666
|
+
type: string
|
|
21667
|
+
enum: [approvals.read_unavailable, approvals.read_corrupt]
|
|
21668
|
+
description: >
|
|
21669
|
+
The `errorCode` of the two READ-FAILURE `error` frames on GET /v1/approvals/stream (server >= 7.133.0). `approvals.read_unavailable` = this tick's approval read failed (the store was momentarily
|
|
21670
|
+
unreadable) — the stream STAYS open and the next tick reads again; it is NOT a terminal frame and NOT a reconnect signal (do not reconnect on it, and do not read it as "nothing pending").
|
|
21671
|
+
`approvals.read_corrupt` = a corrupt row was read — the server closes the stream after the frame; deal with that row before reopening. Branch on the code, never match the message.
|
|
21672
|
+
Older servers (<= 7.132.x) answer a read failure with nothing but heartbeats.
|
|
21673
|
+
ToolApprovalReadProjection:
|
|
21674
|
+
type: object
|
|
21675
|
+
description: >
|
|
21676
|
+
The row projection shared by the three non-`pending` arms of GET /v1/tool-approvals/{id} (server >= 7.133.0): a SUBSET of the `livePending[]` row keys — one reader, one key set. `frame` = the disconnect-replay
|
|
21677
|
+
opening frame (an `approval_request` frame; ABSENT when the card cannot be read back — never invented).
|
|
21678
|
+
required: [approvalId, ts, expiresAtMs]
|
|
21679
|
+
additionalProperties: true
|
|
21680
|
+
properties:
|
|
21681
|
+
approvalId: { type: string }
|
|
21682
|
+
ts: { type: number, description: 'Registration time (ms epoch).' }
|
|
21683
|
+
expiresAtMs: { type: number, description: 'Absolute window deadline (cast once, never recomputed).' }
|
|
21684
|
+
sessionId: { type: string }
|
|
21685
|
+
toolName: { type: string }
|
|
21686
|
+
frame: { $ref: '#/components/schemas/ApprovalRequestFrame' }
|
|
21687
|
+
ToolApprovalReadBody:
|
|
21688
|
+
description: >
|
|
21689
|
+
The 200 body of GET /v1/tool-approvals/{id} (server >= 7.133.0) — a four-arm union discriminated by `state` (closed, read it exhaustively): `pending` = a live registration on this replica is waiting
|
|
21690
|
+
(the `livePending[]` row + `state`; answer door open); `decided` = the row is DECIDED (`decision` / `decidedAtMs` / `decisionNote?`, the same three keys as the late-replay body); `parked` = PARKING / PARKED
|
|
21691
|
+
(a late answer redeems the parked card; `decidePath?` points at the durable decision path); `void` = DENIED / VOID (nobody decided it, the answer has nowhere to land; `cause?` is the same cause word as the
|
|
21692
|
+
late-answer 404's, see ToolApprovalNotPendingCause).
|
|
21693
|
+
oneOf:
|
|
21694
|
+
- $ref: '#/components/schemas/ToolApprovalReadPending'
|
|
21695
|
+
- $ref: '#/components/schemas/ToolApprovalReadDecided'
|
|
21696
|
+
- $ref: '#/components/schemas/ToolApprovalReadParked'
|
|
21697
|
+
- $ref: '#/components/schemas/ToolApprovalReadVoid'
|
|
21698
|
+
discriminator:
|
|
21699
|
+
propertyName: state
|
|
21700
|
+
mapping:
|
|
21701
|
+
pending: '#/components/schemas/ToolApprovalReadPending'
|
|
21702
|
+
decided: '#/components/schemas/ToolApprovalReadDecided'
|
|
21703
|
+
parked: '#/components/schemas/ToolApprovalReadParked'
|
|
21704
|
+
void: '#/components/schemas/ToolApprovalReadVoid'
|
|
21705
|
+
ToolApprovalReadPending:
|
|
21706
|
+
allOf:
|
|
21707
|
+
- $ref: '#/components/schemas/LivePendingRow'
|
|
21708
|
+
- type: object
|
|
21709
|
+
required: [state]
|
|
21710
|
+
properties:
|
|
21711
|
+
state: { type: string, enum: [pending] }
|
|
21712
|
+
ToolApprovalReadDecided:
|
|
21713
|
+
allOf:
|
|
21714
|
+
- $ref: '#/components/schemas/ToolApprovalReadProjection'
|
|
21715
|
+
- type: object
|
|
21716
|
+
required: [state, decision, decidedAtMs]
|
|
21717
|
+
properties:
|
|
21718
|
+
state: { type: string, enum: [decided] }
|
|
21719
|
+
decision: { type: string, enum: [allow, deny] }
|
|
21720
|
+
decidedAtMs: { type: integer }
|
|
21721
|
+
decisionNote: { type: string }
|
|
21722
|
+
ToolApprovalReadParked:
|
|
21723
|
+
allOf:
|
|
21724
|
+
- $ref: '#/components/schemas/ToolApprovalReadProjection'
|
|
21725
|
+
- type: object
|
|
21726
|
+
required: [state]
|
|
21727
|
+
properties:
|
|
21728
|
+
state: { type: string, enum: [parked] }
|
|
21729
|
+
decidePath: { type: string, description: 'The durable decision path for this ask when it can be built.' }
|
|
21730
|
+
ToolApprovalReadVoid:
|
|
21731
|
+
allOf:
|
|
21732
|
+
- $ref: '#/components/schemas/ToolApprovalReadProjection'
|
|
21733
|
+
- type: object
|
|
21734
|
+
required: [state]
|
|
21735
|
+
properties:
|
|
21736
|
+
state: { type: string, enum: [void] }
|
|
21737
|
+
cause:
|
|
21738
|
+
allOf: [{ $ref: '#/components/schemas/AskRowEndingCause' }]
|
|
21739
|
+
description: 'The row''s recorded ending cause (absent for a legacy row with no cause written — never invented).'
|
|
20647
21740
|
ToolApprovalRespondApplied:
|
|
20648
21741
|
type: object
|
|
20649
21742
|
description: >
|
|
20650
|
-
The APPLIED arm of the 200 ack of POST /v1/tool-approvals/{
|
|
21743
|
+
The APPLIED arm of the 200 ack of POST /v1/tool-approvals/{id}/respond (server tool-approval.ts — exact
|
|
20651
21744
|
shape, `decision` echoed): the decision settled a live gate. Owner-gated with a 404 and NO existence oracle: non-owner and
|
|
20652
21745
|
unknown/settled/expired/wrong-replica ids are indistinguishable. See ToolApprovalRespondAck for the replayed arm.
|
|
20653
21746
|
# 封闭(census 批2 第三段,2026-07-30):铸造点 `tool-approval.ts` 三恒在键 + 两条件键
|
|
@@ -20663,6 +21756,13 @@ components:
|
|
|
20663
21756
|
approvalId: { type: string }
|
|
20664
21757
|
delivery: { type: string, enum: [applied] }
|
|
20665
21758
|
decision: { $ref: '#/components/schemas/ToolApprovalDecision' }
|
|
21759
|
+
consumerState:
|
|
21760
|
+
type: string
|
|
21761
|
+
enum: [absent]
|
|
21762
|
+
description: >-
|
|
21763
|
+
server >= 7.133.0, TRUE-ONLY: no engine leg on THIS replica was waiting for the ask this answer settled — the same bit, with the same meaning, as `LivePendingRow.consumerState` and the
|
|
21764
|
+
durable decision ack's. Present <=> the answered entry was ADOPTED from the ask ledger at start-up. The decision lands on the row as usual, but nothing running here resumes because of it — read the run
|
|
21765
|
+
surface; do not read the 200 as "the run continued". Absent = a local engine leg was waiting, or an older server.
|
|
20666
21766
|
rememberApplied:
|
|
20667
21767
|
type: boolean
|
|
20668
21768
|
description: >
|
|
@@ -20754,7 +21854,7 @@ components:
|
|
|
20754
21854
|
ToolApprovalRespondReplayed:
|
|
20755
21855
|
type: object
|
|
20756
21856
|
description: >
|
|
20757
|
-
The REPLAYED arm of the 200 ack of POST /v1/tool-approvals/{
|
|
21857
|
+
The REPLAYED arm of the 200 ack of POST /v1/tool-approvals/{id}/respond: the ask was already DECIDED
|
|
20758
21858
|
(by anyone) when this answer arrived, so the server replays the FIRST decision — `decision` is the row's two-word
|
|
20759
21859
|
value (`allow_session` was folded to `allow` when it landed), `decidedAtMs` the first decision's clock,
|
|
20760
21860
|
`decisionNote` only when the row has one, `rememberApplied: false` only when THIS request asked `allow_session`.
|
|
@@ -20770,14 +21870,57 @@ components:
|
|
|
20770
21870
|
decidedAtMs: { type: integer }
|
|
20771
21871
|
decisionNote: { type: string }
|
|
20772
21872
|
rememberApplied: { type: boolean, enum: [false] }
|
|
21873
|
+
noteRecorded: { type: boolean, description: 'server >= 7.133.0 (two doors, one shape): present ONLY when THIS request carried a `note`; `true` <=> the row''s text is verbatim what this request submitted, `false` = not confirmed (another reason is on the row / no store / read-back failed). A late answer''s note never overwrites the first decision''s reason — that is `decisionNote`.' }
|
|
21874
|
+
rulePersisted: { type: boolean, enum: [false], description: 'server >= 7.133.0: present (as `false`) only when this late answer carried `persistRule`: the rule is redeemed on the FIRST decision only, a late answer never saves one.' }
|
|
21875
|
+
ruleRefusal:
|
|
21876
|
+
type: string
|
|
21877
|
+
enum: [rule_lane_unavailable]
|
|
21878
|
+
description: 'with `rulePersisted: false`; on this arm always `rule_lane_unavailable` (the only word the published late-answer path mints).'
|
|
21879
|
+
ToolApprovalRespondParkedRedeemed:
|
|
21880
|
+
type: object
|
|
21881
|
+
description: >
|
|
21882
|
+
The PARKED-REDEEMED arm of the 200 ack of POST /v1/tool-approvals/{id}/respond (server >= 7.133.0; server tool-approval.ts `redeemParkedAsk` /
|
|
21883
|
+
`replayRedeemReceipt`): the card's window had run out and the ask moved to background waiting (PARKED); this late answer — on another replica or after a restart —
|
|
21884
|
+
goes through the EXISTING durable redemption leg (the same CAS as POST /v1/approvals/{sessionId}/decide) instead of the old 404 `tool_approval.not_pending`
|
|
21885
|
+
(`cause: unknown_or_other_replica`). Body = the redemption leg's receipt (ApprovalDecisionResult's keys — `status` / `taskId` / `sessionId` / ... as they come) plus the three keys
|
|
21886
|
+
this door adds: `approvalId` / `askId` (the same 64-hex value) and the discriminant `accepted`. `decision` is the two-word direction on the REPLAY form only (`allow` / `deny`,
|
|
21887
|
+
`allow_session` folded to `allow`); `rememberApplied: false` appears only when this request asked `allow_session` (a parked redemption cannot remember a session grant);
|
|
21888
|
+
`rulePersisted` / `ruleRefusal` / `persistedRule*` are the `persistRule` outcome on the redemption leg (a rule that fails to store NEVER flips the verdict).
|
|
21889
|
+
`idempotent: true` appears only on the REPLAY (the same already-redeemed card answered again returns the first redemption's receipt).
|
|
21890
|
+
CLOSED like its two sibling arms (the census keeps this op's 200 body closed): the key set is ApprovalDecisionResult's own keys (one source per shape, by `$ref`) plus the added ones.
|
|
21891
|
+
required: [approvalId, askId, accepted]
|
|
21892
|
+
additionalProperties: false
|
|
21893
|
+
properties:
|
|
21894
|
+
approvalId: { type: string }
|
|
21895
|
+
askId: { type: string }
|
|
21896
|
+
accepted: { type: string, enum: [parked_redeemed] }
|
|
21897
|
+
status: { $ref: '#/components/schemas/ApprovalDecisionResult/properties/status' }
|
|
21898
|
+
taskId: { $ref: '#/components/schemas/ApprovalDecisionResult/properties/taskId' }
|
|
21899
|
+
sessionId: { $ref: '#/components/schemas/ApprovalDecisionResult/properties/sessionId' }
|
|
21900
|
+
bindingEnforced: { $ref: '#/components/schemas/ApprovalDecisionResult/properties/bindingEnforced' }
|
|
21901
|
+
decision: { type: string, description: 'REPLAY form: `allow` / `deny` (`allow_session` folded to `allow`). FIRST redemption: whatever the redemption leg''s own receipt says (`approve` / `deny` today) — read it open.' }
|
|
21902
|
+
errorCode: { $ref: '#/components/schemas/ApprovalDecisionResult/properties/errorCode' }
|
|
21903
|
+
errorMessage: { $ref: '#/components/schemas/ApprovalDecisionResult/properties/errorMessage' }
|
|
21904
|
+
retriable: { $ref: '#/components/schemas/ApprovalDecisionResult/properties/retriable' }
|
|
21905
|
+
idempotent: { $ref: '#/components/schemas/ApprovalDecisionResult/properties/idempotent' }
|
|
21906
|
+
executionOutcome: { $ref: '#/components/schemas/ApprovalDecisionResult/properties/executionOutcome' }
|
|
21907
|
+
rememberApplied: { type: boolean, enum: [false] }
|
|
21908
|
+
rulePersisted: { $ref: '#/components/schemas/ToolApprovalRespondApplied/properties/rulePersisted' }
|
|
21909
|
+
ruleRefusal: { $ref: '#/components/schemas/ToolApprovalRespondApplied/properties/ruleRefusal' }
|
|
21910
|
+
persistedRule: { $ref: '#/components/schemas/ToolApprovalRespondApplied/properties/persistedRule' }
|
|
21911
|
+
persistedRules: { $ref: '#/components/schemas/ToolApprovalRespondApplied/properties/persistedRules' }
|
|
21912
|
+
persistedRuleAnchors: { $ref: '#/components/schemas/ToolApprovalRespondApplied/properties/persistedRuleAnchors' }
|
|
20773
21913
|
ToolApprovalRespondAck:
|
|
20774
21914
|
description: >
|
|
20775
|
-
The 200 ack of POST /v1/tool-approvals/{
|
|
21915
|
+
The 200 ack of POST /v1/tool-approvals/{id}/respond — a discriminated union: the decision was APPLIED to a live
|
|
20776
21916
|
gate (ToolApprovalRespondApplied, `delivery: "applied"`) or the ask was already decided and the first decision is
|
|
20777
|
-
REPLAYED (ToolApprovalRespondReplayed, `idempotent: true`).
|
|
21917
|
+
REPLAYED (ToolApprovalRespondReplayed, `idempotent: true`), or (server >= 7.133.0, sdk 25.0.0) the answer REDEEMED a PARKED card through the durable redemption
|
|
21918
|
+
leg (ToolApprovalRespondParkedRedeemed, `accepted: "parked_redeemed"`). The discriminants are `delivery` / `idempotent` / `accepted` (a replayed redemption carries
|
|
21919
|
+
BOTH `accepted: "parked_redeemed"` and `idempotent: true` — read `accepted` first).
|
|
20778
21920
|
oneOf:
|
|
20779
21921
|
- $ref: '#/components/schemas/ToolApprovalRespondApplied'
|
|
20780
21922
|
- $ref: '#/components/schemas/ToolApprovalRespondReplayed'
|
|
21923
|
+
- $ref: '#/components/schemas/ToolApprovalRespondParkedRedeemed'
|
|
20781
21924
|
UsageMetric:
|
|
20782
21925
|
type: string
|
|
20783
21926
|
enum: [tasks, tokensIn, tokensOut, costUsd]
|
|
@@ -21735,7 +22878,7 @@ components:
|
|
|
21735
22878
|
|
|
21736
22879
|
AdoptionNotMigratedFace:
|
|
21737
22880
|
type: string
|
|
21738
|
-
enum: [usage-window, cost-quota, rate-limit, approval-exemption-grantor, approval-ask-decision-actor, image-bake-requested-by]
|
|
22881
|
+
enum: [usage-window, cost-quota, rate-limit, approval-exemption-grantor, approval-ask-decision-actor, image-bake-requested-by, permission-rule-approval-history, permission-rule-import-ticket, org-delivery-quota]
|
|
21739
22882
|
description: >
|
|
21740
22883
|
FROZEN machine-readable vocabulary of the faces the server deliberately does not migrate. Renaming or
|
|
21741
22884
|
removing a member is a wire break; adding one is a new behaviour face. Consumers assert POSITIVELY on
|