@sema-agent/sdk 16.0.1 → 16.2.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 +125 -1
- package/dist/errors.d.ts +53 -11
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +32 -4
- package/dist/errors.js.map +1 -1
- package/dist/events.d.ts +4 -0
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/registry/admin.d.ts +3 -1
- package/dist/registry/admin.d.ts.map +1 -1
- package/dist/registry/admin.js +4 -2
- package/dist/registry/admin.js.map +1 -1
- package/dist/resources/adoption.d.ts +2 -1
- package/dist/resources/adoption.d.ts.map +1 -1
- package/dist/resources/adoption.js +2 -1
- package/dist/resources/adoption.js.map +1 -1
- package/dist/resources/approvals.d.ts +10 -3
- package/dist/resources/approvals.d.ts.map +1 -1
- package/dist/resources/approvals.js +11 -3
- package/dist/resources/approvals.js.map +1 -1
- package/dist/resources/assistant.d.ts +4 -2
- package/dist/resources/assistant.d.ts.map +1 -1
- package/dist/resources/assistant.js.map +1 -1
- package/dist/resources/leader.d.ts +5 -4
- package/dist/resources/leader.d.ts.map +1 -1
- package/dist/resources/leader.js +5 -4
- package/dist/resources/leader.js.map +1 -1
- package/dist/resources/memory.d.ts +6 -2
- package/dist/resources/memory.d.ts.map +1 -1
- package/dist/resources/memory.js +3 -1
- package/dist/resources/memory.js.map +1 -1
- package/dist/resources/ops.d.ts +3 -0
- package/dist/resources/ops.d.ts.map +1 -1
- package/dist/resources/ops.js +3 -0
- package/dist/resources/ops.js.map +1 -1
- package/dist/resources/rules.d.ts +4 -3
- package/dist/resources/rules.d.ts.map +1 -1
- package/dist/resources/rules.js +3 -3
- package/dist/resources/rules.js.map +1 -1
- package/dist/resources/runs.d.ts +20 -6
- package/dist/resources/runs.d.ts.map +1 -1
- package/dist/resources/runs.js +3 -2
- package/dist/resources/runs.js.map +1 -1
- package/dist/resources/session-sync.d.ts +11 -7
- package/dist/resources/session-sync.d.ts.map +1 -1
- package/dist/resources/session-sync.js +9 -6
- package/dist/resources/session-sync.js.map +1 -1
- package/dist/resources/sessions.d.ts +16 -5
- package/dist/resources/sessions.d.ts.map +1 -1
- package/dist/resources/sessions.js +15 -4
- package/dist/resources/sessions.js.map +1 -1
- package/dist/resources/tasks.d.ts +7 -1
- package/dist/resources/tasks.d.ts.map +1 -1
- package/dist/resources/tasks.js +7 -1
- package/dist/resources/tasks.js.map +1 -1
- package/dist/resources/tool-approvals.d.ts +24 -3
- package/dist/resources/tool-approvals.d.ts.map +1 -1
- package/dist/resources/tool-approvals.js +6 -0
- package/dist/resources/tool-approvals.js.map +1 -1
- package/dist/resources/workflows.d.ts +5 -2
- package/dist/resources/workflows.d.ts.map +1 -1
- package/dist/resources/workflows.js +5 -2
- package/dist/resources/workflows.js.map +1 -1
- package/dist/settings.d.ts +34 -8
- package/dist/settings.d.ts.map +1 -1
- package/dist/sync.d.ts +19 -2
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +88 -2
- package/dist/sync.js.map +1 -1
- package/dist/transport.d.ts +2 -0
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +2 -0
- package/dist/transport.js.map +1 -1
- package/dist/types.d.ts +213 -30
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/openapi.yaml +497 -74
- package/package.json +2 -2
package/openapi.yaml
CHANGED
|
@@ -414,9 +414,10 @@ paths:
|
|
|
414
414
|
Synchronous run-to-completion. Auto `Idempotency-Key` (→ retry-safe). Supports `verify`/`cascade`.
|
|
415
415
|
For anything that may take minutes or hit a HITL gate, use `/v1/runs` instead (this call blocks).
|
|
416
416
|
🔴 PREPARE-TIME REFUSALS ARE TRIAGED ON WORK DONE (server >= 7.104.0 / S-271, one rule for the whole table): a
|
|
417
|
-
prepare-time refusal code that HAS a status in the server's per-code triage table (`resume_at
|
|
417
|
+
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,
|
|
418
418
|
`rewind.store_unconfigured` / `rewind.capture_disabled` / `rewind.child_scope_unsupported` / `rewind_snapshot.unresolvable`, the
|
|
419
|
-
registered `config.*` codes incl. the three roster-bound ones
|
|
419
|
+
registered `config.*` codes incl. the three roster-bound ones and — server >= 7.116.0 — `config.invalid_checkpoint_store` (400) and
|
|
420
|
+
`config.user_invoked_skill_unknown` (400: top-level `userInvokedSkills` named a skill this run does not carry), `corrupt_session`; codes outside the table, e.g. `rewind.invalid_spec`, stay
|
|
420
421
|
200 with a failed body) answers its 4xx / 5xx ERROR BODY only when the whole submission did ZERO WORK (cumulative
|
|
421
422
|
`stats.turns === 0` AND `stats.tokens === 0` — the common case: nothing billed, not idempotency-cached). When a
|
|
422
423
|
`verify` / `cascade` run's earlier tier already ran turns and only the last tier is refused, the SAME code arrives
|
|
@@ -442,6 +443,16 @@ paths:
|
|
|
442
443
|
'400': { $ref: '#/components/responses/BadRequest' }
|
|
443
444
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
444
445
|
'403': { $ref: '#/components/responses/Forbidden' } # (declared 2026-08-01) 带 `sessionId` 复用他人会话:归属不匹配 ⇒ 403(自公开快照起点即有,spec 此前漏登记)。server 3.15.0 起多一个触发条件:多租部署上 session store 无归属判别能力时,复用**任何** caller 自报的 sessionId 都 403(含本 worker 自己刚铸的 —— 无 register seam 时归属从未被记下)。core 2.11.0 起默认内存店自带该能力 ⇒ 该触发条件在默认部署上不再出现。 ⚠️ (declared 2026-08-05,server >=7.0.0)`memory.admission_denied` 也走本状态 —— 本状态的 producer 全清单与分支判据写在 `Forbidden` 组件的 description 里(**那段是被解析的**,本行注释只是指路,不复述以免两处漂移)。
|
|
446
|
+
'404':
|
|
447
|
+
description: >-
|
|
448
|
+
Two codes. `resume.session_not_found` (server >= 7.115.0 / S-1038): the body carried `requireExistingSession: true` and its
|
|
449
|
+
`sessionId` does not exist in this deployment. `resume_at.not_found` (server `dist/runs.js` `resumeAtHttpStatus`): a `resumeAt`
|
|
450
|
+
anchor that is genuinely absent (compacted away) — the ONLY `resume_at.*` code that is a 404 (the rest are 422 below); like
|
|
451
|
+
every prepare-time refusal in that table it answers its error body only when the submission did ZERO WORK (turns 0, tokens 0),
|
|
452
|
+
otherwise 200 + a failed body carrying the code in `terminal.code`.
|
|
453
|
+
content:
|
|
454
|
+
application/json:
|
|
455
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
445
456
|
'409':
|
|
446
457
|
description: >-
|
|
447
458
|
Conflict (ConflictError). 409 — session already has an active run (`conflict.session_active_run`, `activeTaskId`,
|
|
@@ -460,7 +471,10 @@ paths:
|
|
|
460
471
|
Semantically unprocessable. K-24 (server >= 7.104.0 / S-724): `rewind.capture_disabled` — the run turned file
|
|
461
472
|
history off (`fileHistory: "disabled"`) and asks to restore in the same breath; this server's request face
|
|
462
473
|
refuses that combination earlier (400 `request.field_conflict`), so only a host building a TaskSpec directly can
|
|
463
|
-
reach this code. `rewind.child_scope_unsupported`
|
|
474
|
+
reach this code. `rewind.child_scope_unsupported` and every `resume_at.*` code EXCEPT `resume_at.not_found` (that one is
|
|
475
|
+
a 404 above) also land here — e.g. `resume_at.before_target_not_user` / `resume_at.before_root_unsupported` (`resumeAtMode:
|
|
476
|
+
"before"`). Also `request.field_conflict` (server >= 7.115.0 / S-1038): `requireExistingSession: true` without a `sessionId`
|
|
477
|
+
(the only 422 this code carries; the request contradicts itself).
|
|
464
478
|
`rewind_snapshot.unresolvable` (server 7.114.0 `dist/runs.js` `resumeAtHttpStatus`: a `resumeAt` file restore —
|
|
465
479
|
`restoreFiles` — that finds no file-history boundary at / above the branch point) is in the same per-code table and lands
|
|
466
480
|
here too, on the same ZERO WORK condition (turns 0, tokens 0: nothing ran, nothing billed); a submission that already ran
|
|
@@ -574,6 +588,20 @@ paths:
|
|
|
574
588
|
application/json:
|
|
575
589
|
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
576
590
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
591
|
+
'404':
|
|
592
|
+
description: >-
|
|
593
|
+
`resume.session_not_found` (server >= 7.115.0 / S-1038): the body carried `requireExistingSession: true` and its `sessionId` does not
|
|
594
|
+
exist in this deployment (the previous status-derived coarse code `not_found.resource` is gone). Dispatch on `errorCode`.
|
|
595
|
+
content:
|
|
596
|
+
application/json:
|
|
597
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
598
|
+
'422':
|
|
599
|
+
description: >-
|
|
600
|
+
`request.field_conflict` (server >= 7.115.0 / S-1038): the body carried `requireExistingSession: true` without a `sessionId` —
|
|
601
|
+
the request contradicts itself (the previous status-derived coarse code was `request.unprocessable`). The only 422 this code carries.
|
|
602
|
+
content:
|
|
603
|
+
application/json:
|
|
604
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
577
605
|
'429': { $ref: '#/components/responses/RateLimited' }
|
|
578
606
|
'503': { $ref: '#/components/responses/Unauthorized' } # (declared 2026-07-31) this path is in server.ts's isBillableSubmitPath set — same three 503 doors as POST /v1/tasks and /v1/runs (no service token / draining / model-roster-pending)
|
|
579
607
|
|
|
@@ -603,7 +631,21 @@ paths:
|
|
|
603
631
|
schema: { $ref: '#/components/schemas/RunReceipt' }
|
|
604
632
|
'400': { $ref: '#/components/responses/BadRequest' }
|
|
605
633
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
634
|
+
'404':
|
|
635
|
+
description: >-
|
|
636
|
+
`resume.session_not_found` (server >= 7.115.0 / S-1038): the body carried `requireExistingSession: true` and its `sessionId` does not
|
|
637
|
+
exist in this deployment (the previous status-derived coarse code `not_found.resource` is gone). Dispatch on `errorCode`.
|
|
638
|
+
content:
|
|
639
|
+
application/json:
|
|
640
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
606
641
|
'409': { $ref: '#/components/responses/Conflict' }
|
|
642
|
+
'422':
|
|
643
|
+
description: >-
|
|
644
|
+
`request.field_conflict` (server >= 7.115.0 / S-1038): the body carried `requireExistingSession: true` without a `sessionId` —
|
|
645
|
+
the request contradicts itself (the previous status-derived coarse code was `request.unprocessable`). The only 422 this code carries.
|
|
646
|
+
content:
|
|
647
|
+
application/json:
|
|
648
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
607
649
|
'429': { $ref: '#/components/responses/RateLimited' }
|
|
608
650
|
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
609
651
|
'503': { $ref: '#/components/responses/Unauthorized' }
|
|
@@ -919,7 +961,8 @@ paths:
|
|
|
919
961
|
un-started ones settle as interrupted pairs, in-flight tools are NOT collateral. TWO shapes,
|
|
920
962
|
discriminated by `text` presence.
|
|
921
963
|
WITH text = cut + steer: the in-flight turn is cut and the text goes to the FRONT of the queue — the
|
|
922
|
-
`"now"` tier is the VERB's semantics, not a body field (the steer op's `priority`
|
|
964
|
+
`"now"` tier is the VERB's semantics, not a body field (the steer op's own `priority` is a separate
|
|
965
|
+
input: it takes effect only on a server whose `Capabilities.fleet.steerPriority` reads `"engine"`) —
|
|
923
966
|
and the run CONTINUES. 202 `{taskId, status, delivery:"queued-immediate", messageId, note}`;
|
|
924
967
|
`messageId` ≡ the engine inputId, and a real cut is proven ONLY by a `task.turn_interrupted` event on
|
|
925
968
|
the run stream whose `detail.inputId` matches it (core: no false interrupt claims — every real cut
|
|
@@ -2048,7 +2091,11 @@ paths:
|
|
|
2048
2091
|
# 亲读真码:wake 的成功腿是 `driveResumeIntoRunLog` 的返回(`server.ts`,成功腿与取消臂两处铸造点),
|
|
2049
2092
|
# **恒为 200**(wake 是同步驱动到终局/再挂起,不是 accepted 回执),且 `taskId` 有条件
|
|
2050
2093
|
# (无活跃行即省略——ApprovalDecisionResult 同一铸造点的同一注)。旧 202+required taskId 双谎。
|
|
2051
|
-
description:
|
|
2094
|
+
description: >-
|
|
2095
|
+
Woken — the resumed leg ran to its next settle (terminal, re-suspended, or needs_review). 🔴 A message-carrying wake that is CANCELLED
|
|
2096
|
+
(`POST /v1/runs/{taskId}/cancel`) while the deployment's `userPromptSubmit` gate is still answering lands HERE, not as a 409 (server
|
|
2097
|
+
>= 7.115.0 / core 7.40.1): `{ status: "failed", errorCode: "cancelled", bindingEnforced: true }` — RETURNED, branch on `errorCode`; the
|
|
2098
|
+
park is closed with the cancel, so a second wake is 404 `not_found.parked_checkpoint` (continue the session with a new submit).
|
|
2052
2099
|
content:
|
|
2053
2100
|
application/json:
|
|
2054
2101
|
schema:
|
|
@@ -2070,12 +2117,17 @@ paths:
|
|
|
2070
2117
|
retriable: { type: boolean, description: 'true = the park is STILL pending (re-parked); refetch and retry. Synchronous form only.' }
|
|
2071
2118
|
'400': { $ref: '#/components/responses/BadRequest' }
|
|
2072
2119
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
2073
|
-
'404': { description: 'No parked checkpoint for this session (nothing to wake), or session not visible to the caller.' }
|
|
2120
|
+
'404': { description: 'No parked checkpoint for this session (nothing to wake; `not_found.parked_checkpoint`), or session not visible to the caller. Also what a SECOND wake gets after a message-carrying wake was cancelled (server >= 7.115.0: that park was closed with the cancel — continue the session with a new submit).' }
|
|
2074
2121
|
'409':
|
|
2075
2122
|
description: >
|
|
2076
2123
|
Pending gate (`wake.gate_pending` — decide it through its own entry) or resume context missing; also the resume-leg refusals core
|
|
2077
2124
|
raises before the claim (`steering.blocked_by_hook` when the wake carried a `message` and the deployment's `userPromptSubmit`
|
|
2078
|
-
hook crashed / timed out / refused — server >= 7.113.0 adds `retriable: true` there;
|
|
2125
|
+
hook crashed / timed out / refused — server >= 7.113.0 adds `retriable: true` there; since server >= 7.115.0 that is the ONLY thing it
|
|
2126
|
+
means on this door — a message-carrying wake CANCELLED while the gate was still answering (`POST /v1/runs/{taskId}/cancel`) is no longer a
|
|
2127
|
+
409 but a 200 `{ status: "failed", errorCode: "cancelled" }` (see 200; <= 7.114.x answered it 409 `steering.blocked_by_hook` and left the park
|
|
2128
|
+
pending — the wrong code's side effect); `checkpoint.unsupported_version` (server >= 7.115.0, `retriable: true` = the card is still pending,
|
|
2129
|
+
NOT "a verbatim retry will succeed": a task parked by <= 7.114.x whose submit body carried a non-empty `settings.permissions.allow` is not replayed
|
|
2130
|
+
under the new reading — resubmit it as a new task; no `taskId` in the body); `checkpoint.config_refused`). Value change on
|
|
2079
2131
|
the run row the wake minted for the refused attempt (server >= 7.113.0): it now ends `failed` with a structured terminal carrying
|
|
2080
2132
|
`terminal.code: "steering.blocked_by_hook"` and holds no session lock (before 7.113.0 it ended with a code-less terminal and
|
|
2081
2133
|
`result: null` — a zero-execution refusal recorded as an ordinary failure); the card itself stays pending.
|
|
@@ -2369,9 +2421,10 @@ paths:
|
|
|
2369
2421
|
written. DETERMINISTIC: a retry cannot change it (the SDK does not auto-retry this code; it arrives as a bare `APIError`
|
|
2370
2422
|
with `errorCode: "corrupt"`); the repair is the operator's — fix the file or delete it (deleting = an explicit "no
|
|
2371
2423
|
rules"). For a damaged rules row `error` names the session, the damage grade and both exits, with NO on-disk path.
|
|
2372
|
-
⚠️ The same code also comes from the write path's high-water-mark sidecar (`.hwm.json`) being unreadable
|
|
2373
|
-
|
|
2374
|
-
|
|
2424
|
+
⚠️ The same code also comes from the write path's high-water-mark sidecar (`.hwm.json`) being unreadable: the sentence names the
|
|
2425
|
+
object, the damage and both exits (fix the mark file, or delete it — deleting gives up the number it was holding). server >= 7.116.0
|
|
2426
|
+
does NOT name the on-disk path any more (the location goes to the operator log `file_store_corrupt_read` only); server <= 7.115.x
|
|
2427
|
+
still did. Also `internal.error` (unclassified).
|
|
2375
2428
|
content:
|
|
2376
2429
|
application/json:
|
|
2377
2430
|
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
@@ -2989,14 +3042,13 @@ paths:
|
|
|
2989
3042
|
2c session-sync PUSH Phase A — a SMALL metadata body (`entryIds, snapshots, policy, anchors, resolution?`); the
|
|
2990
3043
|
entries stream in Phase B. The cloud classifies (§7), pre-checks blob presence (a missing referenced hash →
|
|
2991
3044
|
422 `missing_blob` — PUT it first), guards the import lease + any active run (409), then mints a stagingId.
|
|
2992
|
-
⚠️ S-15 EPOCH
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
≤7.51 truth until that batch lands rather than half-changing.
|
|
3045
|
+
⚠️ S-15 EPOCH: server ≥7.52's Phase A consumes `{entryIds, fileHistory?, policy, anchors, resolution?,
|
|
3046
|
+
logDigest?}` (routes/session-sync.ts) — the `snapshots` key is SILENTLY IGNORED there (an unknown body key); the
|
|
3047
|
+
file history rides `fileHistory` (a `FileHistoryExport` envelope, `null` / absent = none) and every blob it references must have been
|
|
3048
|
+
`PUT …/sync/blobs/{hash}` first. ≤7.51 servers consume `snapshots` and do not know `fileHistory`. SDK 16.2.0 carries
|
|
3049
|
+
`fileHistory` in `pushSessionBundle` / `importSessionBundle` (and fills `snapshots: []` on the pull side when the manifest omits it); a hand-rolled
|
|
3050
|
+
push must send `fileHistory` itself, and only to a peer whose `capabilities.sessionSyncFileHistory` is not false (server >= 7.116.0 — else the
|
|
3051
|
+
commit 422s `missing_blob`).
|
|
3000
3052
|
`identical` → `{ relation:"identical", basis, payloadVerified }` with NO stagingId (skip Phase B);
|
|
3001
3053
|
`basis` is `"entry-ids+digest"` when the caller supplied a comparable digest and it matched, else
|
|
3002
3054
|
`"entry-ids"` (id-set equality only) — see the `ImportStaged` schema, which has carried these two
|
|
@@ -3013,6 +3065,11 @@ paths:
|
|
|
3013
3065
|
properties:
|
|
3014
3066
|
entryIds: { type: array, items: { type: string } }
|
|
3015
3067
|
snapshots: { type: array, items: { $ref: '#/components/schemas/SyncSnapshot' } }
|
|
3068
|
+
fileHistory:
|
|
3069
|
+
oneOf:
|
|
3070
|
+
- { $ref: '#/components/schemas/FileHistoryExport' }
|
|
3071
|
+
- { type: 'null' }
|
|
3072
|
+
description: 'server >= 7.52: the file-history envelope (replaces `snapshots`); `null` / absent = none. Every blob it references must already be PUT.'
|
|
3016
3073
|
policy: { type: array, items: { $ref: '#/components/schemas/SessionRulesRecord' } }
|
|
3017
3074
|
anchors: { type: array, items: { $ref: '#/components/schemas/SyncAnchor' } }
|
|
3018
3075
|
resolution: { type: string, enum: [overwrite-dst], description: Override a fork/stale loss-of-history conflict. }
|
|
@@ -4589,10 +4646,11 @@ paths:
|
|
|
4589
4646
|
`LEADER_ENABLED` (default OFF) + `REMOTE_EXEC=e2b`. Mode is a SERVER deploy flag, not a client choice:
|
|
4590
4647
|
`LEADER_FANOUT_ENABLED=true` (default) lets the router fan out to N isolated workers (= the value-HOLD
|
|
4591
4648
|
correctness bet); `=false` pins a single worker. Either way it runs the E2B+git pipeline. Door B's brain
|
|
4592
|
-
is the strong single agent via `/v1/tasks`+`/v1/runs`+`scenario`. When
|
|
4593
|
-
the
|
|
4594
|
-
|
|
4595
|
-
|
|
4649
|
+
is the strong single agent via `/v1/tasks`+`/v1/runs`+`scenario`. When there is no leader face on the deployment
|
|
4650
|
+
(`LEADER_ENABLED` off) the answer depends on the server: server >= 7.116.0 mounts the route unconditionally and answers
|
|
4651
|
+
**501 `capability.leader_endpoint_required`** (new code; under multi-tenant the identity gate's 401 still comes first);
|
|
4652
|
+
<= 7.115.x did not register the route at all → the generic **404** `not_found.route`. Detect "leader unavailable" by
|
|
4653
|
+
`errorCode` (or the `capabilities.leader` bit, which reads the same fact as the gate), not by the status alone.
|
|
4596
4654
|
|
|
4597
4655
|
|
|
4598
4656
|
🔴 IDEMPOTENCY (server >= 7.24.0): this POST now consumes the `Idempotency-Key` header — the header is
|
|
@@ -4733,7 +4791,8 @@ paths:
|
|
|
4733
4791
|
description: >-
|
|
4734
4792
|
(declared 2026-07-31) errorCode "auth.operator_only" — EXPLICIT operator gate (not the bare
|
|
4735
4793
|
isOperator, whose empty-OPERATOR_PRINCIPALS "true-for-all" would make this index-mutating door
|
|
4736
|
-
world-writable).
|
|
4794
|
+
world-writable). With an EMPTY `OPERATOR_PRINCIPALS` the answer is instead 501
|
|
4795
|
+
`capability.operator_principals_required` (server >= 7.116.0; any identity, ahead of authorization).
|
|
4737
4796
|
content:
|
|
4738
4797
|
application/json:
|
|
4739
4798
|
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
@@ -4787,7 +4846,7 @@ paths:
|
|
|
4787
4846
|
'400': { $ref: '#/components/responses/BadRequest' }
|
|
4788
4847
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
4789
4848
|
'403':
|
|
4790
|
-
description: (declared 2026-07-31) errorCode "auth.operator_only" — EXPLICIT operator gate (§P2.4a).
|
|
4849
|
+
description: (declared 2026-07-31) errorCode "auth.operator_only" — EXPLICIT operator gate (§P2.4a). With an EMPTY `OPERATOR_PRINCIPALS` the answer is instead 501 `capability.operator_principals_required` (server >= 7.116.0; any identity, ahead of authorization — branch on `errorCode`, not the status).
|
|
4791
4850
|
content:
|
|
4792
4851
|
application/json:
|
|
4793
4852
|
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
@@ -4841,7 +4900,7 @@ paths:
|
|
|
4841
4900
|
responses:
|
|
4842
4901
|
'200': { description: '{ bake }.', content: { application/json: { schema: { type: object, required: [bake], additionalProperties: false, properties: { bake: { $ref: '#/components/schemas/BakeRecordView' } } } } } }
|
|
4843
4902
|
'403':
|
|
4844
|
-
description: (declared 2026-07-31) errorCode "auth.operator_only" — EXPLICIT operator gate.
|
|
4903
|
+
description: (declared 2026-07-31) errorCode "auth.operator_only" — EXPLICIT operator gate. With an EMPTY `OPERATOR_PRINCIPALS` the answer is instead 501 `capability.operator_principals_required` (server >= 7.116.0; any identity, ahead of authorization — branch on `errorCode`, not the status).
|
|
4845
4904
|
content:
|
|
4846
4905
|
application/json:
|
|
4847
4906
|
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
@@ -4859,7 +4918,7 @@ paths:
|
|
|
4859
4918
|
responses:
|
|
4860
4919
|
'202': { description: '{ bakeId, cancelRequested, note }.', content: { application/json: { schema: { $ref: '#/components/schemas/BakeCancelAck' } } } }
|
|
4861
4920
|
'403':
|
|
4862
|
-
description: (declared 2026-07-31) errorCode "auth.operator_only" — EXPLICIT operator gate.
|
|
4921
|
+
description: (declared 2026-07-31) errorCode "auth.operator_only" — EXPLICIT operator gate. With an EMPTY `OPERATOR_PRINCIPALS` the answer is instead 501 `capability.operator_principals_required` (server >= 7.116.0; any identity, ahead of authorization — branch on `errorCode`, not the status).
|
|
4863
4922
|
content:
|
|
4864
4923
|
application/json:
|
|
4865
4924
|
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
@@ -4921,7 +4980,7 @@ paths:
|
|
|
4921
4980
|
responses:
|
|
4922
4981
|
'200': { description: 'SSE stream.', content: { text/event-stream: { schema: { type: string } } } }
|
|
4923
4982
|
'403':
|
|
4924
|
-
description: (declared 2026-07-31) errorCode "auth.operator_only" — EXPLICIT operator gate (this summary previously did not mention the restriction at all).
|
|
4983
|
+
description: (declared 2026-07-31) errorCode "auth.operator_only" — EXPLICIT operator gate (this summary previously did not mention the restriction at all). With an EMPTY `OPERATOR_PRINCIPALS` the answer is instead 501 `capability.operator_principals_required` (server >= 7.116.0; any identity, ahead of authorization — branch on `errorCode`, not the status).
|
|
4925
4984
|
content:
|
|
4926
4985
|
application/json:
|
|
4927
4986
|
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
@@ -5133,7 +5192,7 @@ paths:
|
|
|
5133
5192
|
schema: { $ref: '#/components/schemas/EntryProvenanceAccount' }
|
|
5134
5193
|
'400': { description: 'errorCode "request.id_invalid" — the entry id could not be decoded.' }
|
|
5135
5194
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
5136
|
-
'403': { description: 'errorCode "auth.operator_only" — provenance and erasure are operator-only deployment actions.' }
|
|
5195
|
+
'403': { description: 'errorCode "auth.operator_only" — provenance and erasure are operator-only deployment actions. With an EMPTY `OPERATOR_PRINCIPALS` the answer is instead 501 `capability.operator_principals_required` (server >= 7.116.0; any identity, ahead of authorization — branch on `errorCode`, not the status).' }
|
|
5137
5196
|
'500':
|
|
5138
5197
|
description: >
|
|
5139
5198
|
errorCode "internal.memory_control_plane_corrupt" — core's FAIL-CLOSED refusal: the control plane
|
|
@@ -5203,7 +5262,7 @@ paths:
|
|
|
5203
5262
|
application/json:
|
|
5204
5263
|
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
5205
5264
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
5206
|
-
'403': { description: 'errorCode "auth.operator_only" — provenance and erasure are operator-only deployment actions.' }
|
|
5265
|
+
'403': { description: 'errorCode "auth.operator_only" — provenance and erasure are operator-only deployment actions. With an EMPTY `OPERATOR_PRINCIPALS` the answer is instead 501 `capability.operator_principals_required` (server >= 7.116.0; any identity, ahead of authorization — branch on `errorCode`, not the status).' }
|
|
5207
5266
|
'409':
|
|
5208
5267
|
description: >
|
|
5209
5268
|
Three core-minted codes, passed through verbatim; branch on `errorCode` (the status cannot tell them
|
|
@@ -5282,7 +5341,7 @@ paths:
|
|
|
5282
5341
|
schema: { $ref: '#/components/schemas/MemoryOriginExternalResult' }
|
|
5283
5342
|
'400': { description: 'errorCode "request.query_invalid" — `scopes` is absent or normalizes to an empty list. The refusal text also names where scope keys come from and repeats that an empty answer is not a clean store.' }
|
|
5284
5343
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
5285
|
-
'403': { description: 'errorCode "auth.operator_only" — origin marking and clearance are operator-only deployment actions.' }
|
|
5344
|
+
'403': { description: 'errorCode "auth.operator_only" — origin marking and clearance are operator-only deployment actions. With an EMPTY `OPERATOR_PRINCIPALS` the answer is instead 501 `capability.operator_principals_required` (server >= 7.116.0; any identity, ahead of authorization — branch on `errorCode`, not the status).' }
|
|
5286
5345
|
'500':
|
|
5287
5346
|
description: 'errorCode "internal.memory_control_plane_corrupt" (meaning (1) only on this read face) or "internal.error" (unclassified, text not echoed).'
|
|
5288
5347
|
content:
|
|
@@ -5332,7 +5391,7 @@ paths:
|
|
|
5332
5391
|
application/json:
|
|
5333
5392
|
schema: { $ref: '#/components/schemas/MemoryOriginClearancesResult' }
|
|
5334
5393
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
5335
|
-
'403': { description: 'errorCode "auth.operator_only" — origin marking and clearance are operator-only deployment actions.' }
|
|
5394
|
+
'403': { description: 'errorCode "auth.operator_only" — origin marking and clearance are operator-only deployment actions. With an EMPTY `OPERATOR_PRINCIPALS` the answer is instead 501 `capability.operator_principals_required` (server >= 7.116.0; any identity, ahead of authorization — branch on `errorCode`, not the status).' }
|
|
5336
5395
|
'500':
|
|
5337
5396
|
description: 'errorCode "internal.memory_control_plane_corrupt" (the ledger cannot be read soundly) or "internal.error".'
|
|
5338
5397
|
content:
|
|
@@ -5396,7 +5455,7 @@ paths:
|
|
|
5396
5455
|
application/json:
|
|
5397
5456
|
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
5398
5457
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
5399
|
-
'403': { description: 'errorCode "auth.operator_only" — origin marking and clearance are operator-only deployment actions.' }
|
|
5458
|
+
'403': { description: 'errorCode "auth.operator_only" — origin marking and clearance are operator-only deployment actions. With an EMPTY `OPERATOR_PRINCIPALS` the answer is instead 501 `capability.operator_principals_required` (server >= 7.116.0; any identity, ahead of authorization — branch on `errorCode`, not the status).' }
|
|
5400
5459
|
'409':
|
|
5401
5460
|
description: >
|
|
5402
5461
|
Six core-minted codes, passed through verbatim; BRANCH ON `errorCode` — the six operator actions all
|
|
@@ -5519,7 +5578,7 @@ paths:
|
|
|
5519
5578
|
application/json:
|
|
5520
5579
|
schema: { $ref: '#/components/schemas/WiringDiagnostics' }
|
|
5521
5580
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
5522
|
-
'403': { description: 'Multi-tenant worker: wiring diagnostics are operator-only (`auth.operator_only`).' }
|
|
5581
|
+
'403': { description: 'Multi-tenant worker: wiring diagnostics are operator-only (`auth.operator_only`). With an EMPTY `OPERATOR_PRINCIPALS` the answer is instead 501 `capability.operator_principals_required` (server >= 7.116.0; any identity, ahead of authorization — branch on `errorCode`, not the status).' }
|
|
5523
5582
|
'404': { description: 'This worker serves no wiring diagnostics (older server, or a process not assembled by the composition root).' }
|
|
5524
5583
|
|
|
5525
5584
|
/v1/sendfile-links:
|
|
@@ -5849,7 +5908,9 @@ paths:
|
|
|
5849
5908
|
description: >
|
|
5850
5909
|
OPERATOR-ONLY cross-tenant read. Absent (or equal to the caller's own principal) = read your own
|
|
5851
5910
|
rules. Anything else requires explicit OPERATOR_PRINCIPALS membership ⇒ otherwise 403
|
|
5852
|
-
`auth.operator_only
|
|
5911
|
+
`auth.operator_only` (server >= 7.116.0: with an EMPTY list the answer is 501
|
|
5912
|
+
`capability.operator_principals_required` instead — any identity, ahead of authorization; your own rules never
|
|
5913
|
+
go through the operator gate). Rule text contains command shapes, so third-party reads are an information
|
|
5853
5914
|
disclosure and are deliberately not opened to non-operators.
|
|
5854
5915
|
- name: scope
|
|
5855
5916
|
in: query
|
|
@@ -6594,7 +6655,14 @@ components:
|
|
|
6594
6655
|
application/json:
|
|
6595
6656
|
schema: { $ref: '#/components/schemas/QuotaError' }
|
|
6596
6657
|
NotImplemented:
|
|
6597
|
-
description:
|
|
6658
|
+
description: >
|
|
6659
|
+
501 — "this deployment cannot answer this" (e.g. no TiDB run store; `wake` unsupported). server >= 7.116.0: HTTP has exactly ONE status for
|
|
6660
|
+
"unavailable on this deployment" — 501 — and the CAUSE is the code: `capability.*` = change the deployment shape / wire the facility
|
|
6661
|
+
(incl. the new `capability.leader_endpoint_required` for `/v1/leader*` and `capability.shared_memory_required` for `/v1/shared-memory/*`),
|
|
6662
|
+
`feature.*` = turn a knob on (incl. the new `feature.memory_consolidation_disabled` and `feature.config_catalog_disabled`), and
|
|
6663
|
+
`capability.operator_principals_required` = configure `OPERATOR_PRINCIPALS` (every operator-only endpoint answers it, for any identity,
|
|
6664
|
+
when the list is empty; a non-empty list the caller is not on is still 403 `auth.operator_only`). Branch on `errorCode`, not the status
|
|
6665
|
+
(these families answered 404 / 403 on <= 7.115.x). The one registered exception is `a2aServe`'s two routes (404, anti-fingerprint).
|
|
6598
6666
|
content:
|
|
6599
6667
|
application/json:
|
|
6600
6668
|
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
@@ -6774,7 +6842,18 @@ components:
|
|
|
6774
6842
|
name: { type: string }
|
|
6775
6843
|
description: { type: string }
|
|
6776
6844
|
content: { type: string }
|
|
6777
|
-
manifest:
|
|
6845
|
+
manifest:
|
|
6846
|
+
type: object
|
|
6847
|
+
additionalProperties: true
|
|
6848
|
+
deprecated: true
|
|
6849
|
+
description: >
|
|
6850
|
+
RETIRED — server >= 7.116.0 rejects the WHOLE skill when this key is present on a delegated agent's skill (unknown key:
|
|
6851
|
+
`agent.skills must be …`; a top-level skill answers 400 `request.field_invalid` "skill.manifest was retired in core 7.41.0 — …").
|
|
6852
|
+
core 7.41.0 retired the skill manifest (hard break, no alias). Rewrite `manifest.allowTools` to the skill's
|
|
6853
|
+
`allowedTools` (an allow-rule source, not a fence); `manifest.allowPaths` has no replacement (use the session rules'
|
|
6854
|
+
`allowDirs`). Older servers (<= 7.115.x) still accept it; the key stays declared here until the next major.
|
|
6855
|
+
allowedTools: { type: array, items: { type: string }, description: 'server >= 7.116.0 — the skill''s allow-rule source (see `SkillSpec.allowedTools`); <= 7.115.x rejects the key (unknown key).' }
|
|
6856
|
+
disallowedTools: { type: array, items: { type: string }, description: 'server >= 7.116.0 — the skill''s deny-rule source (see `SkillSpec.disallowedTools`); <= 7.115.x rejects the key (unknown key).' }
|
|
6778
6857
|
files:
|
|
6779
6858
|
type: array
|
|
6780
6859
|
items:
|
|
@@ -6837,6 +6916,13 @@ components:
|
|
|
6837
6916
|
instead of silently starting a fresh empty session ("looks warm, actually fresh"). Sending `true`
|
|
6838
6917
|
with NO sessionId also fails loud (nothing to resume). Absent/`false` ⇒ the historical create-on-miss.
|
|
6839
6918
|
Rides the persisted body onto resume legs.
|
|
6919
|
+
🔴 The two refusals carry machine codes (server >= 7.115.0 / S-1038; before that both answered the status-derived coarse
|
|
6920
|
+
codes `not_found.resource` / `request.unprocessable` and the real code lived only in the sentence's trailing
|
|
6921
|
+
parenthesis): `sessionId` not found in this deployment ⇒ **404 `resume.session_not_found`** (premise: the session store
|
|
6922
|
+
can answer ownership — SQL, local and the engine's default in-memory store all can); no `sessionId` at all ⇒ **422
|
|
6923
|
+
`request.field_conflict`** (the request contradicts itself — `sessionId` is its precondition; NOT "session not found",
|
|
6924
|
+
and the only 422 this code carries). Same body on `POST /v1/tasks`, `/v1/tasks/stream` and `/v1/runs`; authorization
|
|
6925
|
+
happens before the SSE head, so the stream door answers the real status too. Dispatch on `errorCode`.
|
|
6840
6926
|
projectId:
|
|
6841
6927
|
type: string
|
|
6842
6928
|
description: >
|
|
@@ -6876,6 +6962,18 @@ components:
|
|
|
6876
6962
|
LISTING RENDERER, not to this gate: turn it down with `settings.skillListingBudgetFraction` /
|
|
6877
6963
|
`settings.skillListingMaxDescChars`.
|
|
6878
6964
|
items: { $ref: '#/components/schemas/SkillSpec' }
|
|
6965
|
+
userInvokedSkills:
|
|
6966
|
+
type: array
|
|
6967
|
+
items: { type: string, minLength: 1 }
|
|
6968
|
+
description: >
|
|
6969
|
+
server >= 7.116.0 (core 7.41.0 #1303). Skills the HUMAN called by name (the shell parses the typed `/name`; by `SkillSpec.name`).
|
|
6970
|
+
Their `allowedTools` / `disallowedTools` take effect from the start of the run and NO `Skill` card is raised (the human naming
|
|
6971
|
+
it is the statement); it governs this one run only (a steer does not end it; the next submit does not carry it). Every name must be
|
|
6972
|
+
a skill the run carries (scenario factory ∪ this request's `skills`), else the engine refuses to start: 400
|
|
6973
|
+
`config.user_invoked_skill_unknown` (sync leg `POST /v1/tasks`; the async / live-stream legs answer 2xx and the same code lands on the
|
|
6974
|
+
terminal run row; `disableSkills: true` makes any name this code). A bad value shape (bare string / empty-string member / non-string /
|
|
6975
|
+
object / null) is a 400 `request.field_invalid`. Does not deliver the skill body. PROBE `capabilities.userInvokedSkills` (constant true);
|
|
6976
|
+
absent = an older server that answers 400 `request.body_shape` listing the key in `unknownKeys` — do not send it.
|
|
6879
6977
|
reasoningEffort:
|
|
6880
6978
|
type: string
|
|
6881
6979
|
enum: [off, minimal, low, medium, high, xhigh, max]
|
|
@@ -6936,7 +7034,8 @@ components:
|
|
|
6936
7034
|
type: string
|
|
6937
7035
|
description: >
|
|
6938
7036
|
CC Rewind parity (E18). Fork the conversation FROM this user-message SessionTreeEntry.id (non-destructive
|
|
6939
|
-
branch via setLeafId). With
|
|
7037
|
+
branch via setLeafId). With `restoreFiles: true` ⇒ "both" (also restore the working tree — the retired spelling
|
|
7038
|
+
`rewindFiles` still rides the wire but its restore sense is core's typed migration rejection naming `restoreFiles`). Alone ⇒
|
|
6940
7039
|
"conversation". HONORED only where the deployment wired a resume-anchor store + getLeafId (capabilities.resumeAt);
|
|
6941
7040
|
unknown anchor ⇒ 4xx, capability-off ⇒ 501. Cannot combine with a durable resume.
|
|
6942
7041
|
resumeAtMode:
|
|
@@ -6949,7 +7048,8 @@ components:
|
|
|
6949
7048
|
everything after it"). core enforces the edges and the service passes its rejection codes through
|
|
6950
7049
|
UNCHANGED for the shell to render: `resume_at.before_target_not_user` (plain user-message targets
|
|
6951
7050
|
only), `resume_at.before_root_unsupported` (cannot rewind past the session root — start a new
|
|
6952
|
-
session), `rewind_snapshot.unresolvable` (with
|
|
7051
|
+
session), `rewind_snapshot.unresolvable` (with a file restore, `restoreFiles`: the target has no file-history boundary of its
|
|
7052
|
+
own — a "before" restore only trusts the target's OWN boundary and never crosses into an earlier turn).
|
|
6953
7053
|
Only meaningful WITH `resumeAt` — sent alone it is a 400 (fail-loud, not a silent no-op).
|
|
6954
7054
|
rewindFiles:
|
|
6955
7055
|
type: boolean
|
|
@@ -7024,8 +7124,8 @@ components:
|
|
|
7024
7124
|
`acceptEdits` (in-workspace writes do not ask) or `bypassPermissions` (422 `request.host_posture_refused` on hosted
|
|
7025
7125
|
deployments) for the old no-ask posture. `auto` arms iff `permissionMode === "auto"` ∧ a classifier seat is mounted ∧
|
|
7026
7126
|
`caps.autoMode !== false` (one polarity); when the requested mode does not take effect the stream gets `engine_notice`
|
|
7027
|
-
`config.permission_mode_unavailable`. `bypassPermissions` RELEASES the
|
|
7028
|
-
(`tool_end.gate.disposition.released` + one `engine_notice` `permission.ask_released_by_mode` per (mode, class) per run);
|
|
7127
|
+
`config.permission_mode_unavailable`. `bypassPermissions` RELEASES the ten releasable ask classes (server >= 7.115.0: the tenth is `unstated`, a server-tool call nobody stated)
|
|
7128
|
+
and DISCLOSES each (`tool_end.gate.disposition.released` + one `engine_notice` `permission.ask_released_by_mode` per (mode, class) per run);
|
|
7029
7129
|
immune classes (deployment-authored, ask / org rules, hooks, ancestors, questions …) still ask; a write whose protection
|
|
7030
7130
|
cannot be judged is refused (`deniedBy: mode`). Request vocabulary: FIVE words — `dontAsk` on a fresh submit is 400
|
|
7031
7131
|
`request.field_invalid` (S-902). The three sentences below — "omitting both carriers means no mode-derived gate", "`auto`
|
|
@@ -7230,6 +7330,26 @@ components:
|
|
|
7230
7330
|
the delivery lane, so raising it only helps a model whose declared window is below 200 000 tokens.
|
|
7231
7331
|
The engine's own twin code `config.skill_listing_budget_invalid` (400) is NOT reachable through this
|
|
7232
7332
|
submit leg today — it belongs to callers that build a `TaskSpec` directly.
|
|
7333
|
+
🔴 `permissions.allow` IS A STATEMENT, NOT A WHITELIST (server >= 7.115.0 / S-654; probe
|
|
7334
|
+
`capabilities.settings.permissions.allowGrant === true` — an absent key is an older server that reads the bucket as a
|
|
7335
|
+
list, so put nothing in it there). The bucket is compiled by the SAME rule compiler as `deny` / `ask`: a hit is a
|
|
7336
|
+
reasoned allow = "somebody stated it" (it answers an MCP / A2A server-tool call nobody stated; without it an
|
|
7337
|
+
ask-class mode raises a card, and with no approval surface the call is refused); a miss states nothing and the call is
|
|
7338
|
+
judged as usual — a tool off the list is NOT refused any more (<= 7.114.x refused it). It does NOT skip the question
|
|
7339
|
+
on built-in tools: the engine's own write gate and shell checks still ask in `default` mode, and deny / ask win
|
|
7340
|
+
(unlike the reference implementation, where `allow: ["Edit"]` skips the edit confirmation; use `permissionMode`
|
|
7341
|
+
for that). For "only these tools" use the real knobs: the session rule `toolAllow`
|
|
7342
|
+
(`PUT /v1/sessions/{sessionId}/policy`), per-request `excludeTools` / `excludeAllTools`, or the deployment's scenario
|
|
7343
|
+
tool surface. Entry forms: a tool-name rule (exact name, `mcp__<server>__*`, `a2a__<peer>__*`; `Bash(*)` is accepted
|
|
7344
|
+
and compiled as a whole-tool rule; server >= 7.116.0 also accepts the two-segment covering form `mcp__<server>` / `a2a__<peer>`,
|
|
7345
|
+
read as the whole server — same meaning as `mcp__<server>__*`); a retired name, a short name with no protocol prefix, a missing-segment
|
|
7346
|
+
name (`mcp__` / `mcp__<server>__`), a protocol name whose server segment the engine cannot have minted (e.g. `mcp__github.com__*` —
|
|
7347
|
+
write `mcp__github_com__*`; server >= 7.116.0 refuses it with a 422 instead of accepting a rule that can never match), a backslash,
|
|
7348
|
+
more than 512 characters, or a CONTENT form
|
|
7349
|
+
(`Bash(npm:*)`, `Read(./x)`, `WebFetch(domain:...)`) is a whole-request 422 (permanent content-form allows live in the
|
|
7350
|
+
persistent rule store: `/v1/rules/cc-import`, or answer yes on a card). The same applies to a PreToolUse hook: an
|
|
7351
|
+
EXPLICIT `permissionDecision: "allow"` states it (and binds only the arguments the hook saw); a hook that only adds
|
|
7352
|
+
`additionalContext` / only rewrites `updatedInput` states nothing.
|
|
7233
7353
|
additionalProperties: true
|
|
7234
7354
|
cwd: { type: string, description: Working directory for the execution env. }
|
|
7235
7355
|
deviceId:
|
|
@@ -7452,6 +7572,12 @@ components:
|
|
|
7452
7572
|
to turn them off, or `{at: [r1, r2]}` with fractions in (0, 1], r1 <= r2 to tune thresholds
|
|
7453
7573
|
(bad shapes are a 400). Budget ceilings stay TOP-LEVEL body keys
|
|
7454
7574
|
(`maxCostUsd`/`maxTokens`) — the server folds them into the engine's limits internally.
|
|
7575
|
+
🔴 The key set is CLOSED (the same four keys as the server's published `TaskRequestBody.limits`):
|
|
7576
|
+
`limits.brainCallGuardrailMs` (the engine's wall on a SINGLE brain call, default one hour, `false` / `0` off) is NOT
|
|
7577
|
+
one of them — server >= 7.115.0 answers it with 400 `request.field_invalid` (a millisecond number, `false` and `0`
|
|
7578
|
+
alike; the sentence names the key; <= 7.114.x accepted it but it took no effect and the wall stayed at one hour).
|
|
7579
|
+
This server has no knob for a caller to set that wall. `budgetStreamCancel` and `degrade` are the same kind of
|
|
7580
|
+
"not caller-settable" keys.
|
|
7455
7581
|
properties:
|
|
7456
7582
|
maxWalltimeMs: { type: integer }
|
|
7457
7583
|
maxOutputTokens: { type: integer }
|
|
@@ -8136,6 +8262,16 @@ components:
|
|
|
8136
8262
|
is unchanged at 7.64.0 — only its source moved (projected from `result.terminal`, or read straight
|
|
8137
8263
|
off a legacy flat blob). ⚠️ K-24 / S-173 (server >= 7.104.0): on a `needs_review` PARK row it is core's canonical
|
|
8138
8264
|
`review.pending` (absent before) — never read "errorCode present" as "failed"; read `status` first.
|
|
8265
|
+
🔴 server >= 7.116.0 (S-1099) adds three values for the run store's own terminal verdicts, which used to live only in the `error`
|
|
8266
|
+
sentence: `run.stalled` (heartbeat-lost reap — and the read-time fold that precedes the reap; sentence `run stalled (instance lost?)`),
|
|
8267
|
+
`run.orphaned` (local-lane restart / session-occupancy takeover reclaim; sentence `run orphaned by engine restart`) and
|
|
8268
|
+
`approval.expired` (the expiry reap of a durably parked approval; the column already carried it, the read face did not project it;
|
|
8269
|
+
sentence `approval expired before decision`). None of the three means the request was wrong — resending the same request is
|
|
8270
|
+
pointless, only a new submission makes a new run. READ `status` FIRST (`failed`), then branch on the code. Open set (a string; always keep a
|
|
8271
|
+
default arm). ABSENCE: rows written by <= 7.115.x carry only the sentence; a one-time startup migration backfills the code
|
|
8272
|
+
(log `one_time_migrations_applied` `holderDeathCodeRowsBackfilled`) and a new replica reads such a row as the code during the upgrade window,
|
|
8273
|
+
but the migration has a window (30 days after the release, then the write-back and the read half are deleted) — so
|
|
8274
|
+
"no `errorCode`" never proves "not a holder death": rows migrated late or after the window stay sentence-only.
|
|
8139
8275
|
error: { type: string }
|
|
8140
8276
|
jobId:
|
|
8141
8277
|
type: string
|
|
@@ -8947,7 +9083,8 @@ components:
|
|
|
8947
9083
|
server >=7.12.0 — the `GET /v1/outcomes` mechanical-signal read aggregate (design/73 §7.2) is
|
|
8948
9084
|
available. Predicate mirrors the route's refusal arms exactly: a QUERYABLE ledger is wired (a
|
|
8949
9085
|
file-only sink writes JSONL and has no query face ⇒ 501), AND on a multi-tenant deployment the
|
|
8950
|
-
operator list is non-empty (single-user has no such gate — the only user IS the operator)
|
|
9086
|
+
operator list is non-empty (single-user has no such gate — the only user IS the operator); with an empty
|
|
9087
|
+
list the multi-tenant route answers 501 `capability.operator_principals_required` (server >= 7.116.0; 403 before).
|
|
8951
9088
|
Added because this face previously had a 501 but NO capability bit, leaving consumers to
|
|
8952
9089
|
trial-by-501 — the exact pattern this capability surface exists to remove.
|
|
8953
9090
|
images:
|
|
@@ -8971,7 +9108,17 @@ components:
|
|
|
8971
9108
|
principal→org membership fold present), so true ⟺ the face actually works — a deployment with
|
|
8972
9109
|
the store but no membership authority deliberately reports false (and does not mount the routes).
|
|
8973
9110
|
workflows: { type: boolean, description: "ENGINE-CAN: this worker's engine can orchestrate S8 self-orchestration workflows (server: `workflowsCapable ?? Boolean(workflowRunStore)`). The MOUNTING of the durable /v1/workflows read routes is the separate `workflowsList` bit below; the two coincide in today's wiring but are declared as orthogonal axes." }
|
|
8974
|
-
workflowsList: { type: boolean, description: "`GET /v1/workflows` list
|
|
9111
|
+
workflowsList: { type: boolean, description: "`GET /v1/workflows` list / detail / stream faces (the workflow run store is wired; separate from the per-run reads). server >= 7.116.0: the journal face `GET /v1/workflows/{id}/journal` is advertised by the new bit `workflowsJournal`, not by this one (value unchanged)." }
|
|
9112
|
+
workflowsJournal:
|
|
9113
|
+
type: boolean
|
|
9114
|
+
description: >
|
|
9115
|
+
server >= 7.116.0 (predicate class "facility": the workflow run store AND the journal store). Advertises
|
|
9116
|
+
`GET /v1/workflows/{id}/journal`. On a deployment with the run store but no journal store (`DB_BACKEND=memory`,
|
|
9117
|
+
multi-tenant bare boot, SQL coordinates not fully configured) with self-orchestration on, `workflowsList` is true
|
|
9118
|
+
and this is false; the journal face then answers 501 `capability.workflow_store_required` (any id, ahead of the
|
|
9119
|
+
per-row owner check; `capability.self_orchestration_required` when the run store is absent). A journal entry point reads THIS bit, not
|
|
9120
|
+
`workflowsList`. ABSENT = an older server (<= 7.115.x): fall back to `workflowsList` (the old behaviour — the
|
|
9121
|
+
bit could be true while the journal face always answers 501).
|
|
8975
9122
|
workflowModels:
|
|
8976
9123
|
type: array
|
|
8977
9124
|
items: { type: string }
|
|
@@ -9014,8 +9161,8 @@ components:
|
|
|
9014
9161
|
(DESIGN-278 §5 S2 — deployment config self-description) is mounted on this DEPLOYMENT. TWO-term
|
|
9015
9162
|
conjunction, written against the route's own refusal arms: ① the `CONFIG_CATALOG_ENABLED` knob is
|
|
9016
9163
|
on (default on; a compliance deployment that turns it off makes the path a 404 — the valve-family
|
|
9017
|
-
precedent) AND ② the operator principal list is NON-EMPTY (with an empty list the route
|
|
9018
|
-
identity). 🔴 DEPLOYMENT-LEVEL AVAILABILITY, NOT THE CALLER'S AUTHORIZATION: the caller's own
|
|
9164
|
+
precedent; server >= 7.116.0 answers 501 `feature.config_catalog_disabled` there, 404 before) AND ② the operator principal list is NON-EMPTY (with an empty list the route refuses every
|
|
9165
|
+
identity — 501 `capability.operator_principals_required` on server >= 7.116.0, 403 before). 🔴 DEPLOYMENT-LEVEL AVAILABILITY, NOT THE CALLER'S AUTHORIZATION: the caller's own
|
|
9019
9166
|
identity is NOT in the predicate — the route additionally requires the CURRENT principal to be an
|
|
9020
9167
|
explicit operator (`routes/config-catalog.ts` `explicitOperatorOk`, else 403 `auth.operator_only`),
|
|
9021
9168
|
so a non-operator reads `true` and still gets 403. Show/invoke the catalog only for an identity you
|
|
@@ -9035,8 +9182,15 @@ components:
|
|
|
9035
9182
|
`false`/absent otherwise (same predicate as the route's 501). `resume: "snapshot"` is a semantic
|
|
9036
9183
|
advertisement: the bus is latest-state (not an event log) and every connection opens with a full
|
|
9037
9184
|
snapshot frame, so reconnect = re-snapshot (deliberately no last-event-id cursor); transient
|
|
9038
|
-
bg_notification frames re-deliver via the durable completion inbox. `steerPriority
|
|
9039
|
-
|
|
9185
|
+
bg_notification frames re-deliver via the durable completion inbox. `steerPriority` (a string, open
|
|
9186
|
+
set) says whether the steer body's `priority` takes effect on THIS server: `steerPriority: "advisory"`
|
|
9187
|
+
(server <=7.115.x) = accepted + enum-validated + echoed but a no-op (nothing is handed to the engine);
|
|
9188
|
+
`steerPriority: "engine"` (server >=7.116.0) = `priority` (`now` / `next` / `later`) is handed to the
|
|
9189
|
+
engine as the injection tier, and the engine owns what each tier means — `now` cuts the in-flight turn
|
|
9190
|
+
IMMEDIATELY (the running tool receives an abort, an approval card pending on this replica is revoked; one `engine_notice`
|
|
9191
|
+
`task.turn_interrupted` frame is the evidence), `later` is delivered after the turn the run would have stopped on, no `priority` =
|
|
9192
|
+
`next`. Read this bit before offering a `priority` choice; an absent
|
|
9193
|
+
or unknown value means "do not assume it takes effect", never `"engine"`.
|
|
9040
9194
|
oneOf:
|
|
9041
9195
|
- type: boolean
|
|
9042
9196
|
enum: [false]
|
|
@@ -9257,6 +9411,25 @@ components:
|
|
|
9257
9411
|
outputStyle: { type: boolean }
|
|
9258
9412
|
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.' }
|
|
9259
9413
|
hooks: { type: boolean, description: 'Single-user deployments only (`requirePrincipal !== true`).' }
|
|
9414
|
+
settings:
|
|
9415
|
+
type: object
|
|
9416
|
+
description: >
|
|
9417
|
+
🔴 server >= 7.115.0 (S-654), ALWAYS present: `{ permissions: { allowGrant: true } }` — the VERSION bit for "which reading does this
|
|
9418
|
+
server give `settings.permissions.allow` on a task submit". `permissions.allowGrant === true` = the `allow` bucket is compiled into
|
|
9419
|
+
ALLOW RULES: a hit gives "somebody stated it" (so an MCP / A2A server-tool call nobody stated no longer raises a card) — it is NOT
|
|
9420
|
+
"skip the question" and NOT a whitelist (a tool off the list is no longer refused; the engine's own write gate / shell checks still ask
|
|
9421
|
+
on built-in tools, deny / ask still win; a bad-shape or content-form name is a whole-request 422).
|
|
9422
|
+
🔴 ABSENT KEY = an older server (<= 7.114.x), which read `allow` as a WHITELIST (everything off the list refused) — do not put anything
|
|
9423
|
+
in the allow bucket there. NOT the same bit as `taskSettings.permissions` (unchanged, still a boolean: "this server accepts the
|
|
9424
|
+
`settings.permissions` face"). A version bit: constant `true`, never varies with the deployment; the deployment-level "who stated what"
|
|
9425
|
+
(operator env `APPROVAL_GRANT`) is on the operator diagnostics face (`serverGates.approvalGrant`), not here.
|
|
9426
|
+
additionalProperties: true
|
|
9427
|
+
properties:
|
|
9428
|
+
permissions:
|
|
9429
|
+
type: object
|
|
9430
|
+
additionalProperties: true
|
|
9431
|
+
properties:
|
|
9432
|
+
allowGrant: { type: boolean, description: 'Constant `true` on server >= 7.115.0: `settings.permissions.allow` is read as allow RULES (a statement), not as a list. The whole `settings` key being absent = an older server.' }
|
|
9260
9433
|
memoryWrite:
|
|
9261
9434
|
type: boolean
|
|
9262
9435
|
description: >
|
|
@@ -9272,9 +9445,25 @@ components:
|
|
|
9272
9445
|
S-15 换店; ≤7.51 the last conjunct was the file-snapshot store). Gate the whole sync surface off
|
|
9273
9446
|
this. ⚠️ The two BLOB faces (PUT …/sync/blobs/{hash}, GET …/sync/history/blobs/{hash})
|
|
9274
9447
|
additionally need the store's blob faces (`syncBlobFaces` — the SQL/cloud backends; the local
|
|
9275
|
-
file backend has none): without them
|
|
9276
|
-
|
|
9277
|
-
surface keeps working.
|
|
9448
|
+
file backend has none): without them BOTH answer 501 `capability.snapshot_store_required`
|
|
9449
|
+
(server >= 7.116.0; the history PULL answered a no-oracle 404 `not_found.blob` there on <= 7.115.x),
|
|
9450
|
+
while the REST of the sync surface keeps working. Since server >= 7.116.0 the two blob faces are
|
|
9451
|
+
advertised by their own bit `sessionSyncFileHistory`; this bit speaks for the conversation half
|
|
9452
|
+
(its predicate additionally requires a session-policy store that can purge, `deleteBySession` —
|
|
9453
|
+
a deployment whose embedder-supplied store lacks it answers the whole family 501
|
|
9454
|
+
`capability.policy_purge_required` and this bit is false).
|
|
9455
|
+
sessionSyncFileHistory:
|
|
9456
|
+
type: boolean
|
|
9457
|
+
description: >
|
|
9458
|
+
server >= 7.116.0 (predicate class "facility": `sessionSync` AND the file-history store has blob transfer faces
|
|
9459
|
+
— SQL backends only; `DB_BACKEND=local` is always false). Advertises exactly the two file-history blob faces
|
|
9460
|
+
`PUT /v1/sessions/{sessionId}/sync/blobs/{hash}` and `GET /v1/sessions/{sessionId}/sync/history/blobs/{hash}`.
|
|
9461
|
+
READ IT ON BOTH ENDS of a sync: if either is false, sync the conversation only — do not push `fileHistory`, do
|
|
9462
|
+
not PUT blobs (a `fileHistory` pushed to a peer without the blob faces 422s `missing_blob` after commit). When
|
|
9463
|
+
false the two routes answer 501 `capability.snapshot_store_required` (any session id, ahead of the owner check).
|
|
9464
|
+
A blob that the session history graph does not reference / whose bytes are gone stays a 404 `not_found.blob`.
|
|
9465
|
+
ABSENT = an older server (<= 7.115.x): the bit cannot be read there (a `DB_BACKEND=local` deployment with
|
|
9466
|
+
`sessionSync: true` answered PUT blob 501 on every call), so try as before.
|
|
9278
9467
|
|
|
9279
9468
|
# ─── S-139(sdk 8.3.0):对 server 7.60.0 的整体重对账补齐的 19 位 ───────────────────────
|
|
9280
9469
|
# 行号 = server 7.60.0 树的 `src/http/routes/capabilities.ts`。语义与谓词的全文在
|
|
@@ -9367,7 +9556,8 @@ components:
|
|
|
9367
9556
|
description: >
|
|
9368
9557
|
Governance carry-out bundle pair `POST /v1/memory/{export,import}` (operator lane) —
|
|
9369
9558
|
capabilities.ts:261, two conjuncts: both engine seams wired AND `operatorPrincipals` NON-EMPTY
|
|
9370
|
-
(an empty roster makes those routes
|
|
9559
|
+
(an empty roster makes those routes refuse every identity — 501 `capability.operator_principals_required` on
|
|
9560
|
+
server >= 7.116.0, 403 before). True does not promise the backend
|
|
9371
9561
|
has the bundle composite face (core then refuses loudly with `memory.export_incomplete`).
|
|
9372
9562
|
memoryCompliance:
|
|
9373
9563
|
type: boolean
|
|
@@ -9469,10 +9659,13 @@ components:
|
|
|
9469
9659
|
a2aServe:
|
|
9470
9660
|
type: boolean
|
|
9471
9661
|
description: >
|
|
9472
|
-
Server-as-peer
|
|
9473
|
-
`
|
|
9474
|
-
|
|
9475
|
-
|
|
9662
|
+
Server-as-peer: true ⟺ `GET /.well-known/agent-card.json` and `POST /v1/a2a` exist; false ⟺ both 404
|
|
9663
|
+
(`not_found.route`, anti-fingerprint — the one registered exception to "unavailable = 501"). server >= 7.116.0
|
|
9664
|
+
predicate (class "facility + config"): the `A2A_SERVE_ENABLED` knob AND a durable run store; <= 7.115.x looked at the knob
|
|
9665
|
+
only (`config.a2aServe !== undefined`). 🔴 value change: with the knob on but NO durable run store
|
|
9666
|
+
(`DB_BACKEND=memory`, multi-tenant bare boot) this bit is now false and the card and the RPC both answer 404 (7.115.x:
|
|
9667
|
+
true, card 200, every `message/send` / `tasks/get` a JSON-RPC `-32004`); the startup log carries a warn
|
|
9668
|
+
`a2a_serve_not_served`. The old "the server deliberately does not fold the run store into this bit" note is retired.
|
|
9476
9669
|
agentRoster:
|
|
9477
9670
|
type: boolean
|
|
9478
9671
|
description: >
|
|
@@ -9667,6 +9860,23 @@ components:
|
|
|
9667
9860
|
answers the request key with a 400 `request.body_shape` naming it under `unknownKeys` — do not send the key
|
|
9668
9861
|
there and tell the user the factory skills stay installed. True only says "this server knows the key", not
|
|
9669
9862
|
whether the deployment has any factory skills.
|
|
9863
|
+
userInvokedSkills:
|
|
9864
|
+
type: boolean
|
|
9865
|
+
enum: [true]
|
|
9866
|
+
description: >
|
|
9867
|
+
server >= 7.116.0 (constant true; no predicate, no tenant gate) — the ADVANCE READING for the request key
|
|
9868
|
+
`TaskRequest.userInvokedSkills` (skills the human named; effective from the start of the run, no `Skill` card);
|
|
9869
|
+
the bit and the key are the SAME word. ABSENT = an older server (<= 7.115.x), which answers the key with a 400
|
|
9870
|
+
`request.body_shape` naming it under `unknownKeys` — do not send it there.
|
|
9871
|
+
skillToolLists:
|
|
9872
|
+
type: boolean
|
|
9873
|
+
enum: [true]
|
|
9874
|
+
description: >
|
|
9875
|
+
server >= 7.116.0 (constant true) — the skill tool lists `allowedTools` / `disallowedTools` TAKE EFFECT (allow-rule /
|
|
9876
|
+
deny-rule source; see `SkillSpec.allowedTools`). ABSENT = an older server (<= 7.115.x): on a top-level skill the two
|
|
9877
|
+
lists are accepted but the engine does not read them — they are silently inert and there is NO 400 to probe, so do not
|
|
9878
|
+
expect them to stop a tool (fence with deny rules instead); on a delegated agent's skill they are an unknown key that
|
|
9879
|
+
rejects the whole skill.
|
|
9670
9880
|
WriteProtectionCapability:
|
|
9671
9881
|
type: object
|
|
9672
9882
|
additionalProperties: false
|
|
@@ -9801,11 +10011,42 @@ components:
|
|
|
9801
10011
|
engine refuses the skill outright at load time, so the HTTP face answers first where the caller can read it).
|
|
9802
10012
|
The bound is 1 048 576 **UTF-16 code units** (`MAX_SKILL_CONTENT_CHARS`); see the STRING-LENGTH UNIT
|
|
9803
10013
|
convention in `info.description` for why this `maxLength` states that number verbatim.
|
|
10014
|
+
🔴 server >= 7.116.0 (core 7.41.0): a skill carries two TOOL LISTS, `allowedTools` / `disallowedTools` — the
|
|
10015
|
+
run-scoped ALLOW-RULE and DENY-RULE source of the skill once it is activated. NOT a fence (<= 7.115.x the engine read
|
|
10016
|
+
the skill's tool list as "only these"): unlisted tools are judged as usual, listed ones are not asked about for the rest
|
|
10017
|
+
of the run — which makes it WIDER than `settings.permissions.allow` (that one stays a statement and does not
|
|
10018
|
+
release the engine's own write gate / shell ordinary asks on built-in tools). Probe `capabilities.skillToolLists`
|
|
10019
|
+
(absent = an old server that accepts the keys on a top-level skill and silently ignores them). The skill's `manifest`
|
|
10020
|
+
key is RETIRED: any value on a top-level skill is a 400 `request.field_invalid` ("skill.manifest was retired in core
|
|
10021
|
+
7.41.0 — …"; rewrite `manifest.allowTools` to `allowedTools`; `allowPaths` has no replacement), and on a delegated
|
|
10022
|
+
agent's skill (`agents[].skills[]`) it is an unknown key that rejects the whole skill.
|
|
9804
10023
|
required: [name, description, content]
|
|
9805
10024
|
properties:
|
|
9806
10025
|
name: { type: string, minLength: 1 }
|
|
9807
10026
|
description: { type: string }
|
|
9808
10027
|
content: { type: string, minLength: 1, maxLength: 1048576 }
|
|
10028
|
+
allowedTools:
|
|
10029
|
+
type: array
|
|
10030
|
+
items: { type: string }
|
|
10031
|
+
description: >
|
|
10032
|
+
server >= 7.116.0. The skill's run-scoped ALLOW-RULE source (permission-rule spellings: a tool name,
|
|
10033
|
+
`mcp__<server>` / `mcp__<server>__*`; `*`, write paths and domain forms grant nothing). Once the skill is activated
|
|
10034
|
+
(named in top-level `userInvokedSkills` — no `Skill` card — or activated by the model and the card approved) the
|
|
10035
|
+
listed tools are not asked about for the rest of the run: it clears the engine's ordinary and "nobody stated it" asks,
|
|
10036
|
+
so it is WIDER than `settings.permissions.allow`; deny / ask rules, `APPROVAL_REQUIRE`, `APPROVAL_NEVER_AUTO`, the shell
|
|
10037
|
+
floor, write protection and plan-mode asks are not cleared. NOT a fence: unlisted tools are judged as usual. A non-string-array
|
|
10038
|
+
is a 400 `request.field_invalid`; a protocol name whose server segment cannot be minted / is missing / is a wildcard
|
|
10039
|
+
(`mcp__*`) is a 400 too (top-level `skills[]` and `agents[].skills[]` judge identically). Probe `capabilities.skillToolLists`.
|
|
10040
|
+
disallowedTools:
|
|
10041
|
+
type: array
|
|
10042
|
+
items: { type: string }
|
|
10043
|
+
description: >
|
|
10044
|
+
server >= 7.116.0. The skill's run-scoped DENY-RULE source (same grammar / gates / probe as `allowedTools`): once the skill
|
|
10045
|
+
is activated these tools are refused for the run (no execution, no card; `tool_end.gate.disposition` is
|
|
10046
|
+
`{ kind: "denied", deniedBy: "policy" }`). `*` and domain forms (`WebFetch(domain:…)`) read as "none" on this side too —
|
|
10047
|
+
accepted with 2xx and only an operator-audience notice `skills.allowed_tool_not_granted`; write-path forms and the rest compile
|
|
10048
|
+
into deny rows (as the server contract states it for the engine's `compileSkillGrant`; the SDK did not re-run the engine on the deny side's write-path forms —
|
|
10049
|
+
the engine's own notice text lists "a write-path or domain entry" among entries that "grant (or refuse) nothing").
|
|
9809
10050
|
|
|
9810
10051
|
McpServerSpec:
|
|
9811
10052
|
type: object
|
|
@@ -11740,6 +11981,11 @@ components:
|
|
|
11740
11981
|
expiresAtMs: { type: number, description: 'Absolute window deadline — the SAME number minted once for the tool_approval frame (never recomputed).' }
|
|
11741
11982
|
sessionId: { type: string }
|
|
11742
11983
|
requiresRealApproval: { type: boolean, enum: [true] }
|
|
11984
|
+
rememberRefused:
|
|
11985
|
+
type: boolean
|
|
11986
|
+
enum: [true]
|
|
11987
|
+
description: >-
|
|
11988
|
+
server >= 7.116.0, ADDITIVE, present ONLY when true (never `false`): the "remember for this session" answer (live `allow_session` / durable `/decide` `remember:"session"`) will NOT be remembered on this card — the decision is accepted and applies once, the receipt's `rememberApplied` is `false` (existing key, not a new one), later cards of the same kind still ask. A shell reads this to decide whether to render the "allow for the session" choice instead of inferring it from `requiresRealApproval` / `mandated` / `governanceForced`. One bit for four reasons: the operator-governance gate / a human must approve each time / a mandated card / the answer would also grant more than this one call (new in 7.116.0: approving an engine `Skill` card activates the skill and frees its listed tools for the run, which the card cannot show, so it is not remembered). ABSENT = remember works on this card, OR an older server (<= 7.115.x never carries the key). Same bit on the live frame, the `approval_request` card (= `card_json`, incl. the reconnect replay), the `livePending` row, and the `/v1/approvals` `pending[]` row (+ their `/stream` frames); NOT on inbox rows.
|
|
11743
11989
|
governanceForced: { type: boolean, enum: [true] }
|
|
11744
11990
|
mandated: { type: boolean, enum: [true], description: 'server >= 7.101.0 (T4①): the mandated bit, same layer and shape as the two flags above (present only when true); the SAME value as `frame.mandated` (read once when the entry is minted).' }
|
|
11745
11991
|
mandate:
|
|
@@ -11902,6 +12148,9 @@ components:
|
|
|
11902
12148
|
Present ⇔ the request carried `remember:"session"` and the worker has an exemption store. `true` = the
|
|
11903
12149
|
per-session per-tool exemption landed; `false` = the grant failed (logged) or the gate carried no
|
|
11904
12150
|
rememberable toolName — the decision itself still stands.
|
|
12151
|
+
🔴 server >= 7.116.0: ALWAYS `false` on a card that carries `rememberRefused: true` (an engine `Skill` card etc. — the
|
|
12152
|
+
answer would also grant more than this one call): the decision is accepted and applies once, the exemption store gets
|
|
12153
|
+
zero writes (existing key, not a new one). Ordinary cards keep `true` = landed.
|
|
11905
12154
|
|
|
11906
12155
|
ApprovalExemption:
|
|
11907
12156
|
type: object
|
|
@@ -12045,6 +12294,11 @@ components:
|
|
|
12045
12294
|
🔴 DISPLAY / TRIAGE ONLY, and ABSENT MEANS THERE REALLY IS NO SUPPLY (rule lane unarmed, the
|
|
12046
12295
|
command yields no rule, no rule could silence this ask, or an old row) — never "the projection
|
|
12047
12296
|
dropped it", which is precisely the bug this key exists to close. Never `null`, never `[]`.
|
|
12297
|
+
rememberRefused:
|
|
12298
|
+
type: boolean
|
|
12299
|
+
enum: [true]
|
|
12300
|
+
description: >-
|
|
12301
|
+
server >= 7.116.0, ADDITIVE, present ONLY when true (never `false`): the "remember for this session" answer (live `allow_session` / durable `/decide` `remember:"session"`) will NOT be remembered on this card — the decision is accepted and applies once, the receipt's `rememberApplied` is `false` (existing key, not a new one), later cards of the same kind still ask. A shell reads this to decide whether to render the "allow for the session" choice instead of inferring it from `requiresRealApproval` / `mandated` / `governanceForced`. One bit for four reasons: the operator-governance gate / a human must approve each time / a mandated card / the answer would also grant more than this one call (new in 7.116.0: approving an engine `Skill` card activates the skill and frees its listed tools for the run, which the card cannot show, so it is not remembered). ABSENT = remember works on this card, OR an older server (<= 7.115.x never carries the key). Same bit on the live frame, the `approval_request` card (= `card_json`, incl. the reconnect replay), the `livePending` row, and the `/v1/approvals` `pending[]` row (+ their `/stream` frames); NOT on inbox rows.
|
|
12048
12302
|
governanceForced:
|
|
12049
12303
|
type: boolean
|
|
12050
12304
|
enum: [true]
|
|
@@ -12997,31 +13251,97 @@ components:
|
|
|
12997
13251
|
type: object
|
|
12998
13252
|
description: >
|
|
12999
13253
|
2c session-sync `GET …/sync/manifest` payload (wrapped server-side as `{ manifest }`). The THIN cross-backend
|
|
13000
|
-
snapshot: entry IDS (oldest-first, NOT payloads) +
|
|
13001
|
-
|
|
13002
|
-
|
|
13254
|
+
snapshot: entry IDS (oldest-first, NOT payloads) + the file-history envelope + policy + anchors + leaf.
|
|
13255
|
+
🔴 server >= 7.52 (S-15, design/381; re-read byte for byte against 7.116.0): the key `snapshots` (per-snapshot
|
|
13256
|
+
relPath→blobHash, the retired E19 whole-tree snapshot epoch) is NO LONGER SENT — the server's `exportSessionManifest` mints
|
|
13257
|
+
`{ sessionId, entryIds, entryCount, leafId, fileHistory, policy, anchors }` and `fileHistory` (core's versioned
|
|
13258
|
+
`FileHistoryExport` envelope; `null` = no history / the source store cannot export) replaces it. <= 7.51 servers still send
|
|
13259
|
+
`snapshots` and no `fileHistory`. The blob BYTES never ride the manifest: content-addressed, via the history blob faces
|
|
13260
|
+
(`GET …/sync/history/blobs/{hash}` / `PUT …/sync/blobs/{hash}`; probe `capabilities.sessionSyncFileHistory` on BOTH ends).
|
|
13261
|
+
The SDK's `manifest()` fills `snapshots: []` when the wire omits it.
|
|
13262
|
+
# 封闭(census 批2 第三段,2026-07-30;16.2.0 按 7.116.0 发布字节重核):铸造点 `session-sync.ts`(exportSessionManifest 尾部
|
|
13263
|
+
# 字面量)恰是 `{ sessionId, entryIds, entryCount, leafId, fileHistory, policy, anchors }` 7 键(≥7.52),无 `snapshots`;
|
|
13264
|
+
# ≤7.51 老 server 发 `snapshots`、无 `fileHistory` ⇒ 两键都不进 required(支持底线 3.0.0)。
|
|
13003
13265
|
additionalProperties: false
|
|
13004
|
-
required: [sessionId, entryIds, entryCount, leafId,
|
|
13266
|
+
required: [sessionId, entryIds, entryCount, leafId, policy, anchors]
|
|
13005
13267
|
properties:
|
|
13006
13268
|
sessionId: { type: string }
|
|
13007
13269
|
entryIds: { type: array, items: { type: string }, description: Oldest-first, verbatim cross-backend. }
|
|
13008
13270
|
entryCount: { type: integer, description: '= entryIds.length (the `/sync/entries` trailer count).' }
|
|
13009
13271
|
leafId: { type: [string, 'null'] }
|
|
13010
|
-
snapshots: { type: array, items: { $ref: '#/components/schemas/SyncSnapshot' } }
|
|
13272
|
+
snapshots: { type: array, items: { $ref: '#/components/schemas/SyncSnapshot' }, description: 'server <= 7.51 ONLY (the retired E19 snapshot epoch); server >= 7.52 does not send it — see `fileHistory`.' }
|
|
13273
|
+
fileHistory:
|
|
13274
|
+
oneOf:
|
|
13275
|
+
- { $ref: '#/components/schemas/FileHistoryExport' }
|
|
13276
|
+
- { type: 'null' }
|
|
13277
|
+
description: 'server >= 7.52: the per-edited-file rewind history envelope; `null` = no history / the source store cannot export; key ABSENT = a <= 7.51 server (that generation sends `snapshots`).'
|
|
13011
13278
|
policy: { type: array, items: { $ref: '#/components/schemas/SessionRulesRecord' } }
|
|
13012
13279
|
anchors: { type: array, items: { $ref: '#/components/schemas/SyncAnchor' } }
|
|
13013
13280
|
|
|
13281
|
+
FileHistoryExport:
|
|
13282
|
+
type: object
|
|
13283
|
+
description: >
|
|
13284
|
+
Mirror of core's `FileHistoryExport` (`formatVersion: "file-history/1"`) — the session-sync envelope for the per-edited-file rewind history graph
|
|
13285
|
+
(server >= 7.52; replaces the retired E19 `SyncSnapshot`). Blob bytes are NOT inside: they are content-addressed and travel through the history blob faces.
|
|
13286
|
+
The SDK reads only `tracked[].versions[].blobHash` (which blobs to move) and passes everything else through verbatim — the server's import door judges
|
|
13287
|
+
`formatVersion` (refuse-not-coerce) and the closed `keyKind` / `keyFamily` sets, so they are plain strings here.
|
|
13288
|
+
required: [formatVersion, tracked, boundaries]
|
|
13289
|
+
properties:
|
|
13290
|
+
formatVersion: { type: string, description: 'today only `file-history/1`; the server refuses any other value.' }
|
|
13291
|
+
tracked:
|
|
13292
|
+
type: array
|
|
13293
|
+
items:
|
|
13294
|
+
type: object
|
|
13295
|
+
required: [relOrAbsPath, keyKind, keyFamily, baseAvailable, versions]
|
|
13296
|
+
properties:
|
|
13297
|
+
relOrAbsPath: { type: string }
|
|
13298
|
+
keyKind: { type: string }
|
|
13299
|
+
keyFamily: { type: string }
|
|
13300
|
+
baseAvailable: { type: boolean }
|
|
13301
|
+
versions:
|
|
13302
|
+
type: array
|
|
13303
|
+
items:
|
|
13304
|
+
type: object
|
|
13305
|
+
required: [version, blobHash, backupTime]
|
|
13306
|
+
properties:
|
|
13307
|
+
version: { type: integer }
|
|
13308
|
+
blobHash: { type: [string, 'null'], description: '`null` = the "did not exist" marker (no blob to move).' }
|
|
13309
|
+
mode: { type: integer }
|
|
13310
|
+
parentIdent: { type: string }
|
|
13311
|
+
backupTime: { type: string }
|
|
13312
|
+
boundaries:
|
|
13313
|
+
type: array
|
|
13314
|
+
items:
|
|
13315
|
+
type: object
|
|
13316
|
+
required: [entryId, files]
|
|
13317
|
+
properties:
|
|
13318
|
+
entryId: { type: string }
|
|
13319
|
+
files:
|
|
13320
|
+
type: array
|
|
13321
|
+
items:
|
|
13322
|
+
type: object
|
|
13323
|
+
required: [relOrAbsPath, version]
|
|
13324
|
+
properties:
|
|
13325
|
+
relOrAbsPath: { type: string }
|
|
13326
|
+
version: { type: integer }
|
|
13327
|
+
|
|
13014
13328
|
SessionBundle:
|
|
13015
13329
|
type: object
|
|
13016
13330
|
description: >
|
|
13017
13331
|
The portable state of ONE session, ready to replay into another backend. Blobs are NOT inlined (each
|
|
13018
13332
|
snapshot carries only its `manifest`; the bytes stream through the content-addressed blob routes). The SDK
|
|
13019
|
-
assembles this from a manifest + the streamed entries for a PUSH.
|
|
13333
|
+
assembles this from a manifest + the streamed entries for a PUSH. server >= 7.52: the file history rides `fileHistory`
|
|
13334
|
+
(the `FileHistoryExport` envelope) instead of `snapshots`.
|
|
13020
13335
|
required: [sessionId, entries, snapshots, policy, anchors]
|
|
13021
13336
|
properties:
|
|
13022
13337
|
sessionId: { type: string }
|
|
13023
13338
|
entries: { type: array, items: { $ref: '#/components/schemas/SyncEntry' } }
|
|
13024
13339
|
snapshots: { type: array, items: { $ref: '#/components/schemas/SyncSnapshot' } }
|
|
13340
|
+
fileHistory:
|
|
13341
|
+
oneOf:
|
|
13342
|
+
- { $ref: '#/components/schemas/FileHistoryExport' }
|
|
13343
|
+
- { type: 'null' }
|
|
13344
|
+
description: 'server >= 7.52 file-history envelope (same as `SessionManifest.fileHistory`); key absent = the source is a <= 7.51 server.'
|
|
13025
13345
|
policy: { type: array, items: { $ref: '#/components/schemas/SessionRulesRecord' } }
|
|
13026
13346
|
anchors: { type: array, items: { $ref: '#/components/schemas/SyncAnchor' } }
|
|
13027
13347
|
|
|
@@ -13270,7 +13590,27 @@ components:
|
|
|
13270
13590
|
carry their own `field`.) Resume legs carry the same group on 409 `resume_blocked_by_policy`
|
|
13271
13591
|
(`blockedBy: "request.field_invalid"`). Also on 409 `checkpoint.config_refused` (server >= 7.113.0): which part of the
|
|
13272
13592
|
row's configuration was refused — `taskConfig` (change the configuration, then decide the SAME card again) or
|
|
13273
|
-
`inheritedGate` (the row's recorded mode seed is bad — the run can only be cancelled).
|
|
13593
|
+
`inheritedGate` (the row's recorded mode seed is bad — the run can only be cancelled). Also on 400 `request.field_invalid` for a
|
|
13594
|
+
`settings.hooks` tool-event matcher that selects an engine alias but not its canonical name (server >= 7.115.0 / S-1025):
|
|
13595
|
+
`field` is always the literal `settings.hooks` (see `detail`). SDK: `err.extra.field`.
|
|
13596
|
+
detail:
|
|
13597
|
+
description: >
|
|
13598
|
+
🔴 TWO SHAPES under one code — branch on `field` (or the `errorCode`), never guess from the type of `detail`. On 400
|
|
13599
|
+
`request.field_invalid` for a `settings.hooks` tool-event matcher (server >= 7.115.0 / S-1025; additive, the sentence and the code
|
|
13600
|
+
are unchanged): an OBJECT `{ event, alias, canonical }` — `event` = the tool event of the refused group (the first refused one when
|
|
13601
|
+
several are), `alias` / `canonical` = the engine catalog's alias and canonical name (closed strings, never the caller's raw bytes),
|
|
13602
|
+
beside `field: "settings.hooks"`. On 400 `request.field_invalid` for the two `POST /v1/adoption` principal sentences (adoption):
|
|
13603
|
+
a human-readable STRING. Other codes (`rules.*` content refusals: `reason` + human `detail`; core `checkpoint.*` mirrors) carry their
|
|
13604
|
+
own `detail`; read it by `errorCode`. SDK: `err.extra.detail` (verbatim, unnamed).
|
|
13605
|
+
oneOf:
|
|
13606
|
+
- type: object
|
|
13607
|
+
required: [event, alias, canonical]
|
|
13608
|
+
additionalProperties: false
|
|
13609
|
+
properties:
|
|
13610
|
+
event: { type: string }
|
|
13611
|
+
alias: { type: string }
|
|
13612
|
+
canonical: { type: string }
|
|
13613
|
+
- type: string
|
|
13274
13614
|
count:
|
|
13275
13615
|
type: integer
|
|
13276
13616
|
description: 'S-904 `reason: over_cap` only — how many entries the bucket had (server >= 7.106.0). SDK: `err.extra.count`.'
|
|
@@ -13864,16 +14204,29 @@ components:
|
|
|
13864
14204
|
unattended leg run under `UNATTENDED_PERMISSION_MODE=dontAsk`).
|
|
13865
14205
|
AskClass:
|
|
13866
14206
|
type: string
|
|
13867
|
-
enum: [content_question, hook, ancestor, unverifiable_delete, transcript_write, org_rule, governance_unavailable, rule_unreadable, ask_rule, denial_limit_fallback, operator_forced, shell_floor, write_protection_unresolved, probe, write_protection, tool_marks_mcp, tool_marks_a2a, policy_rra, artifact_shared_read, mode, ordinary]
|
|
13868
|
-
description: >
|
|
13869
|
-
core `ASK_CLASSES` (twenty-
|
|
13870
|
-
server >= 7.113.0
|
|
14207
|
+
enum: [content_question, hook, ancestor, unverifiable_delete, transcript_write, org_rule, governance_unavailable, rule_unreadable, ask_rule, denial_limit_fallback, requires_user_interaction, operator_forced, shell_floor, write_protection_unresolved, probe, write_protection, tool_marks_mcp, tool_marks_a2a, policy_rra, artifact_shared_read, mode, unstated, ordinary]
|
|
14208
|
+
description: >
|
|
14209
|
+
core `ASK_CLASSES` (twenty-two words as of core 7.40.0, twenty-three as of core 7.41.0 — 7.34.0 minted twenty; `shell_floor` joined in 7.39.0 #1260 and rides
|
|
14210
|
+
server >= 7.113.0; `unstated` joined in 7.40.0 and rides server >= 7.115.0; `requires_user_interaction` joined in 7.41.0 and rides
|
|
14211
|
+
server >= 7.116.0) — which CLASS an ask falls in (the columns of the mode × class arbitration table).
|
|
14212
|
+
`requires_user_interaction` = the MCP server declared, in the tool's advertisement, `_meta["anthropic/requiresUserInteraction"] === true`
|
|
14213
|
+
(only the boolean `true`): EVERY call of that tool asks the human, in EVERY mode including `bypassPermissions` (it is not one of the ten
|
|
14214
|
+
RELEASABLE classes), and only the human's answer clears it — `settings.permissions.allow`, operator `APPROVAL_GRANT`, a skill's tool list +
|
|
14215
|
+
`userInvokedSkills` and a hook's explicit allow all fail to; with no approval seat the call is refused (the server sees nothing). The frame
|
|
14216
|
+
also carries `requiresRealApproval: true` / `mandated: true` (`origin: "safety_tighten"`). A client that renders cards by exhaustive `askClass`
|
|
14217
|
+
adds this one word.
|
|
14218
|
+
`unstated` = NOBODY STATED IT: in an ask-class mode (`default` / `acceptEdits` / `auto` / `plan`) a call to an MCP server tool or A2A skill
|
|
14219
|
+
(a seat that states no permission of its own) reached the end of the fold with no layer — rule / hook / approver / classifier / mode
|
|
14220
|
+
release — having said "this time is fine"; the engine raises a card with `askClass: "unstated"` (sentence `The agent requested permission to use <tool>,
|
|
14221
|
+
but it has not been granted yet.`), and with no approval surface the call is refused. It is clearable (one of the ten RELEASABLE
|
|
14222
|
+
classes: an allow rule — `settings.permissions.allow` / operator `APPROVAL_GRANT` — an explicit hook `permissionDecision: "allow"`, the auto-mode
|
|
14223
|
+
classifier or `bypassPermissions` clears it); under `plan` only READ-ONLY server tools raise it.
|
|
13871
14224
|
`shell_floor` = the operator's `shellGate: "always"` floor on a shell-running seat (the question the `operator_always` mandate
|
|
13872
14225
|
word discloses), a class of its own so a set that holds another forced question still holds it; like `operator_forced` it is
|
|
13873
14226
|
bypass-IMMUNE (not releasable).
|
|
13874
|
-
CLOSED on the gate record (screened with core `isAskClass`). `bypassPermissions` releases only the
|
|
14227
|
+
CLOSED on the gate record (screened with core `isAskClass`). `bypassPermissions` releases only the ten RELEASABLE classes
|
|
13875
14228
|
(`transcript_write` / `rule_unreadable` / `probe` / `write_protection` / `tool_marks_mcp` / `tool_marks_a2a` /
|
|
13876
|
-
`artifact_shared_read` / `mode` / `ordinary`); every other class (deployment-authored `operator_forced`, ask / org rules, hook,
|
|
14229
|
+
`artifact_shared_read` / `mode` / `unstated` / `ordinary`); every other class (deployment-authored `operator_forced`, ask / org rules, hook,
|
|
13877
14230
|
ancestor, content question, …) asks under every mode.
|
|
13878
14231
|
ModeRelease:
|
|
13879
14232
|
type: object
|
|
@@ -14514,6 +14867,15 @@ components:
|
|
|
14514
14867
|
properties:
|
|
14515
14868
|
backgroundAgentStore: { type: boolean }
|
|
14516
14869
|
hostChildEventSink: { type: boolean }
|
|
14870
|
+
subagentTranscripts:
|
|
14871
|
+
type: string
|
|
14872
|
+
description: >
|
|
14873
|
+
server >= 7.115.0 (S-744; core 7.32.0 tier now on the wire) — the deployment's SUBAGENT TRANSCRIPT TIER, so a shell can render the
|
|
14874
|
+
"durable record" wording truthfully: `none` (no agent-row store: subagent records are not kept) / `rows` (rows and terminal snapshots
|
|
14875
|
+
survive a restart but the CONVERSATION does not: continuable only in this process / within the session store's TTL) / `full` (an
|
|
14876
|
+
ended subagent can be resumed across a restart). 🔴 OPEN SET — read it open: the three words are core's today, do not enumerate (a
|
|
14877
|
+
fourth word would be swallowed into "absent"); an unknown word means "unknown tier", never treat it as `full`. ABSENT = unknown
|
|
14878
|
+
(older server / older engine) — never read it as `none`. Tenant and operator frames carry it alike.
|
|
14517
14879
|
permissionRules:
|
|
14518
14880
|
type: object
|
|
14519
14881
|
additionalProperties: false
|
|
@@ -14645,7 +15007,8 @@ components:
|
|
|
14645
15007
|
deliberately never reported (pattern TEXT is deployment material, not an enum).
|
|
14646
15008
|
🔴 AN EMPTY ARRAY IS NEVER EMITTED ("off" and "on to nothing" are one fact) ⇒ treat `[]` as a bad
|
|
14647
15009
|
producer. The tier vocabulary is owned by core — do not narrow it on the consumer side.
|
|
14648
|
-
⚠️ Deployment
|
|
15010
|
+
⚠️ Deployment default (server config catalog): an ABSENT `READ_DENY_BUILTIN_TIERS` ⇒ the factory pair `credentials,agent-config`
|
|
15011
|
+
is on (core 7.34.0 R-2 onward; it was OFF in 7.22.0–7.33.x); `none` = the explicit empty posture; an empty value refuses to boot.
|
|
14649
15012
|
autoConsolidation:
|
|
14650
15013
|
allOf: [{ $ref: '#/components/schemas/WiringManifestAutoConsolidation' }]
|
|
14651
15014
|
description: >
|
|
@@ -15452,6 +15815,11 @@ components:
|
|
|
15452
15815
|
args:
|
|
15453
15816
|
description: '"tool_approval" only: the call''s args, secret-redacted. UNTRUSTED for display. Absent (with argsOmitted) when over the byte cap or unserializable.'
|
|
15454
15817
|
argsOmitted: { type: boolean, enum: [true] }
|
|
15818
|
+
rememberRefused:
|
|
15819
|
+
type: boolean
|
|
15820
|
+
enum: [true]
|
|
15821
|
+
description: >-
|
|
15822
|
+
server >= 7.116.0, ADDITIVE, present ONLY when true (never `false`): the "remember for this session" answer (live `allow_session` / durable `/decide` `remember:"session"`) will NOT be remembered on this card — the decision is accepted and applies once, the receipt's `rememberApplied` is `false` (existing key, not a new one), later cards of the same kind still ask. A shell reads this to decide whether to render the "allow for the session" choice instead of inferring it from `requiresRealApproval` / `mandated` / `governanceForced`. One bit for four reasons: the operator-governance gate / a human must approve each time / a mandated card / the answer would also grant more than this one call (new in 7.116.0: approving an engine `Skill` card activates the skill and frees its listed tools for the run, which the card cannot show, so it is not remembered). ABSENT = remember works on this card, OR an older server (<= 7.115.x never carries the key). Same bit on the live frame, the `approval_request` card (= `card_json`, incl. the reconnect replay), the `livePending` row, and the `/v1/approvals` `pending[]` row (+ their `/stream` frames); NOT on inbox rows.
|
|
15455
15823
|
governanceForced:
|
|
15456
15824
|
type: boolean
|
|
15457
15825
|
enum: [true]
|
|
@@ -15584,6 +15952,18 @@ components:
|
|
|
15584
15952
|
properties:
|
|
15585
15953
|
shown: { type: array, items: { type: string } }
|
|
15586
15954
|
total: { type: integer }
|
|
15955
|
+
probeReason:
|
|
15956
|
+
type: string
|
|
15957
|
+
description: >
|
|
15958
|
+
server >= 7.115.0 (S-733), ADDITIVE, "tool_approval" only: the PROSE reason a reversibility probe gave for tightening this ask
|
|
15959
|
+
(core `AskRequest.probeReason`; the server's narrow read: a non-string / blank value ⇒ absent, more than 201 code points ⇒
|
|
15960
|
+
dropped WHOLE rather than truncated, content-family redaction — the same rule as the durable face's
|
|
15961
|
+
`gate.riskDescriptor.probeReason`, so the two faces carry the same bytes for the same sentence). It runs ALONGSIDE
|
|
15962
|
+
`probeCause` and does not replace it: engine-minted causes ride the structured seat, a deployment-written probe can only write this
|
|
15963
|
+
sentence. RENDER: prefer `probeCause`'s structure; fall back to this key when there is none; neither ⇒ no cause to render
|
|
15964
|
+
(absent != "no reason"). PRESENT ONLY WHEN IT HAS A VALUE (never an empty string) and ONLY ON THE LIVE card frame —
|
|
15965
|
+
the presented frame (`approval_request`) and the durable card (`card_json`) do NOT carry it (the durable twin is
|
|
15966
|
+
`gate.riskDescriptor.probeReason` on the parked row). Display / triage metadata, never an adjudication input; never in `message`.
|
|
15587
15967
|
ruleEvidence:
|
|
15588
15968
|
type: object
|
|
15589
15969
|
description: >
|
|
@@ -15904,6 +16284,11 @@ components:
|
|
|
15904
16284
|
argsOmitted: { type: boolean, enum: [true], description: 'Present (true) only when args exceeded the byte cap. Never false.' }
|
|
15905
16285
|
toolCallId: { type: string, description: 'The engine''s tool-call id (the `call_…` on the assistant message''s tool_use block) — same domain as ToolApprovalFrame.toolCallId.' }
|
|
15906
16286
|
risk: { $ref: '#/components/schemas/ApprovalRiskAxes' }
|
|
16287
|
+
rememberRefused:
|
|
16288
|
+
type: boolean
|
|
16289
|
+
enum: [true]
|
|
16290
|
+
description: >-
|
|
16291
|
+
server >= 7.116.0, ADDITIVE, present ONLY when true (never `false`): the "remember for this session" answer (live `allow_session` / durable `/decide` `remember:"session"`) will NOT be remembered on this card — the decision is accepted and applies once, the receipt's `rememberApplied` is `false` (existing key, not a new one), later cards of the same kind still ask. A shell reads this to decide whether to render the "allow for the session" choice instead of inferring it from `requiresRealApproval` / `mandated` / `governanceForced`. One bit for four reasons: the operator-governance gate / a human must approve each time / a mandated card / the answer would also grant more than this one call (new in 7.116.0: approving an engine `Skill` card activates the skill and frees its listed tools for the run, which the card cannot show, so it is not remembered). ABSENT = remember works on this card, OR an older server (<= 7.115.x never carries the key). Same bit on the live frame, the `approval_request` card (= `card_json`, incl. the reconnect replay), the `livePending` row, and the `/v1/approvals` `pending[]` row (+ their `/stream` frames); NOT on inbox rows.
|
|
15907
16292
|
governanceForced:
|
|
15908
16293
|
type: boolean
|
|
15909
16294
|
enum: [true]
|
|
@@ -16558,16 +16943,27 @@ components:
|
|
|
16558
16943
|
sessionId: { type: string, description: 'gone.ask_parked ONLY — gate reconciliation coordinate 1; drive the existing durable-gate flow with it.' }
|
|
16559
16944
|
gateBoundCallId: { type: string, description: 'gone.ask_parked ONLY — gate reconciliation coordinate 2.' }
|
|
16560
16945
|
gateBoundInputHash: { type: string, description: 'gone.ask_parked ONLY — gate reconciliation coordinate 3.' }
|
|
16561
|
-
state: { type: string, enum: [DENIED, VOID], description: 'gone.ask ONLY — the terminal state.' }
|
|
16946
|
+
state: { type: string, enum: [DENIED, VOID], description: 'gone.ask ONLY — the terminal state. server >= 7.116.0 also mints `VOID` for "the process that held the ask is gone" (local lane restart; see `deniedReason`).' }
|
|
16562
16947
|
deniedReason:
|
|
16563
16948
|
type: string
|
|
16564
16949
|
description: >
|
|
16565
16950
|
gone.ask ONLY — attribution, GROUPED BY `state`. `DENIED` carries the single-member deny
|
|
16566
16951
|
vocabulary `routing_failure_fail_closed`; `VOID` carries the separate (and growing) void
|
|
16567
|
-
vocabulary,
|
|
16952
|
+
vocabulary, seven words today: `run_cancelled`, `batch_aborted`, `batch_bound_elsewhere`,
|
|
16953
|
+
`adhoc_leg_no_durable_domain`, `orphan_ttl_exceeded` and — new in server 7.116.0 (local lane) —
|
|
16954
|
+
`crashed_before_park` (the process that held the ask crashed / was killed) and `shutdown_before_park`
|
|
16955
|
+
(an orderly shutdown could not settle the card inside its grace window; a fault shape, hard to build black-box).
|
|
16956
|
+
The last two are the SAME word as `GET /v1/approvals` `crashConverged[].cause`; the other six were already on the wire
|
|
16957
|
+
(7.3.0 / 7.55.0 / 7.108.0) and are only registered in the server's self-minted word table by 7.116.0.
|
|
16958
|
+
ABSENT = the row carries no attribution. The two vocabularies never mix; the VOID one is open (read an unknown word as "the ask ended without
|
|
16959
|
+
a human decision, reason unknown").
|
|
16568
16960
|
description: >
|
|
16569
16961
|
410 body. THE TWO LEGS ARE DISJOINT: `gone.ask_parked` carries exactly the three gate coordinates,
|
|
16570
|
-
`gone.ask` carries exactly `{state, deniedReason?}
|
|
16962
|
+
`gone.ask` carries exactly `{state, deniedReason?}` (no `consumerState`).
|
|
16963
|
+
🔴 server >= 7.116.0 (local lane, `DB_BACKEND=local`): after a crash / kill and a restart on the same data root, answering the PREVIOUS
|
|
16964
|
+
life's still-open card is now `410 gone.ask` with `state: "VOID"` and `deniedReason` `crashed_before_park` / `shutdown_before_park` —
|
|
16965
|
+
<= 7.115.x answered `200` + `consumerState: "absent"` (the run had long been reclaimed; nothing executed). An ask that was already decided
|
|
16966
|
+
(decided, then the process died mid-execution) is unchanged: `409 conflict.ask_decided`. SQL backends are unchanged in 7.116.0. Routing off field presence across the legs is how a
|
|
16571
16967
|
consumer ends up driving the wrong durable gate.
|
|
16572
16968
|
🔴 The checkpoint token is NEVER here: the resume credential is not externally disclosed. Use
|
|
16573
16969
|
`sessionId`.
|
|
@@ -17913,6 +18309,15 @@ components:
|
|
|
17913
18309
|
properties:
|
|
17914
18310
|
backgroundAgentStore: { type: boolean }
|
|
17915
18311
|
hostChildEventSink: { type: boolean }
|
|
18312
|
+
subagentTranscripts:
|
|
18313
|
+
type: string
|
|
18314
|
+
description: >
|
|
18315
|
+
server >= 7.115.0 (S-744; core 7.32.0 tier now on the wire) — the deployment's SUBAGENT TRANSCRIPT TIER, so a shell can render the
|
|
18316
|
+
"durable record" wording truthfully: `none` (no agent-row store: subagent records are not kept) / `rows` (rows and terminal snapshots
|
|
18317
|
+
survive a restart but the CONVERSATION does not: continuable only in this process / within the session store's TTL) / `full` (an
|
|
18318
|
+
ended subagent can be resumed across a restart). 🔴 OPEN SET — read it open: the three words are core's today, do not enumerate (a
|
|
18319
|
+
fourth word would be swallowed into "absent"); an unknown word means "unknown tier", never treat it as `full`. ABSENT = unknown
|
|
18320
|
+
(older server / older engine) — never read it as `none`. Tenant and operator frames carry it alike.
|
|
17916
18321
|
governance:
|
|
17917
18322
|
type: object
|
|
17918
18323
|
description: 'OPERATOR-AUDIENCE section (presence of the four deployment governance faces). Absent on every tenant-readable face.'
|
|
@@ -18242,6 +18647,16 @@ components:
|
|
|
18242
18647
|
`SESSION_AUTO_TITLE` AND who set it. Its default is the SAME on every deployment shape (true), so this
|
|
18243
18648
|
knob has NO posture arm — an unset one reads `source: "engine-default"` and says so in `note`.
|
|
18244
18649
|
checkpointStore: { type: boolean, description: 'A checkpoint store is wired (= the park facility exists).' }
|
|
18650
|
+
approvalGrant:
|
|
18651
|
+
type: array
|
|
18652
|
+
items: { type: string }
|
|
18653
|
+
description: >
|
|
18654
|
+
server >= 7.115.0 — the operator's allow rules `APPROVAL_GRANT` (env; off by default) VERBATIM (tool-name rules are not secrets;
|
|
18655
|
+
an EMPTY list = the knob is unset, count = length). It answers "who did the DEPLOYMENT state for": a matching MCP / A2A
|
|
18656
|
+
server-tool call no longer raises a card for want of a statement — it releases no layer's own question (deny / ask / session rules /
|
|
18657
|
+
the engine's write gate all still apply). OPERATOR face only (this endpoint is operator-only); deliberately NOT in `GET /v1/capabilities`
|
|
18658
|
+
(that face says what a caller can use — see `Capabilities.settings`). Not in `required`: the key is absent on a server < 7.115.0
|
|
18659
|
+
(no such knob there), which is a different fact from `[]` (knob present, unset).
|
|
18245
18660
|
|
|
18246
18661
|
WiringDiagnostics:
|
|
18247
18662
|
type: object
|
|
@@ -18327,9 +18742,15 @@ components:
|
|
|
18327
18742
|
description: >-
|
|
18328
18743
|
[2400] TR-4 — per-message queue priority on POST /v1/runs/{taskId}/steer. ACCEPTED + ENUM-VALIDATED
|
|
18329
18744
|
FAIL-LOUD (`routes/runs.ts`; anything else is 400 `request.field_invalid`) and echoed back on the
|
|
18330
|
-
receipt
|
|
18331
|
-
|
|
18332
|
-
on
|
|
18745
|
+
receipt. WHETHER IT TAKES EFFECT is the server's call — read `Capabilities.fleet.steerPriority` first:
|
|
18746
|
+
`"engine"` (server >=7.116.0) = the tier is handed to the engine on every delivery leg (`now` cuts the in-flight turn
|
|
18747
|
+
IMMEDIATELY — the running tool receives an abort, an approval card pending on this replica is revoked, one `engine_notice`
|
|
18748
|
+
`task.turn_interrupted` frame is the evidence; `next` ≡ no `priority`; `later` is delivered after the turn the run would have stopped on; parked
|
|
18749
|
+
legs store the tier and deliver on the resume's / wake's first turn; replaying the same `Idempotency-Key` + text with a different effective
|
|
18750
|
+
tier is 409 `steering.duplicate_input_id`); `"advisory"` (server <=7.115.x) = accepted and echoed but NOT applied —
|
|
18751
|
+
core's steer was a single-slot last-writer-wins with no per-message priority or addressable drop, so a
|
|
18752
|
+
faithful priority queue (and DELETE /v1/runs/{taskId}/queue/{messageId}) waited on a core seam. An absent
|
|
18753
|
+
or unknown capability value means "do not assume it is applied".
|
|
18333
18754
|
|
|
18334
18755
|
SteerReceipt:
|
|
18335
18756
|
type: object
|
|
@@ -18606,6 +19027,8 @@ components:
|
|
|
18606
19027
|
server 1.239 ([1392]②): on allow_session, an honest echo of whether the grant was REALLY
|
|
18607
19028
|
recorded (true = landed in the bridge store; false = no sessionId, could not record — do not
|
|
18608
19029
|
render "session-wide allowed"). Omitted on non-allow_session decisions and on older servers.
|
|
19030
|
+
🔴 server >= 7.116.0: ALWAYS `false` on a card that carries `rememberRefused: true` (an engine `Skill` card etc.) — the decision
|
|
19031
|
+
applies once and nothing is remembered (existing key, not a new one).
|
|
18609
19032
|
updatedInputForwarded:
|
|
18610
19033
|
type: boolean
|
|
18611
19034
|
description: >
|