@sema-agent/sdk 26.0.0 → 27.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +129 -1
- package/dist/abort.d.ts +25 -0
- package/dist/abort.d.ts.map +1 -0
- package/dist/abort.js +42 -0
- package/dist/abort.js.map +1 -0
- package/dist/client.d.ts +8 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +5 -4
- package/dist/client.js.map +1 -1
- package/dist/control-client.d.ts +4 -2
- package/dist/control-client.d.ts.map +1 -1
- package/dist/control-client.js +3 -3
- package/dist/control-client.js.map +1 -1
- package/dist/errors.d.ts +80 -8
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +32 -6
- package/dist/errors.js.map +1 -1
- package/dist/events.d.ts +31 -2
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +12 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/model-route-env/index.d.ts +11 -4
- package/dist/model-route-env/index.d.ts.map +1 -1
- package/dist/model-route-env/index.js +52 -3
- package/dist/model-route-env/index.js.map +1 -1
- package/dist/registry/auth.d.ts.map +1 -1
- package/dist/registry/auth.js +23 -13
- package/dist/registry/auth.js.map +1 -1
- package/dist/registry/client.d.ts +9 -1
- package/dist/registry/client.d.ts.map +1 -1
- package/dist/registry/client.js +17 -2
- package/dist/registry/client.js.map +1 -1
- package/dist/registry/read-body.d.ts +2 -0
- package/dist/registry/read-body.d.ts.map +1 -0
- package/dist/registry/read-body.js +24 -0
- package/dist/registry/read-body.js.map +1 -0
- package/dist/registry/scopes-effective.d.ts.map +1 -1
- package/dist/registry/scopes-effective.js +4 -2
- package/dist/registry/scopes-effective.js.map +1 -1
- package/dist/resources/approvals.d.ts +27 -10
- package/dist/resources/approvals.d.ts.map +1 -1
- package/dist/resources/approvals.js +5 -4
- package/dist/resources/approvals.js.map +1 -1
- package/dist/resources/attachments.d.ts +2 -1
- package/dist/resources/attachments.d.ts.map +1 -1
- package/dist/resources/attachments.js +3 -9
- package/dist/resources/attachments.js.map +1 -1
- package/dist/resources/fleet.d.ts +4 -36
- package/dist/resources/fleet.d.ts.map +1 -1
- package/dist/resources/fleet.js +40 -1
- package/dist/resources/fleet.js.map +1 -1
- package/dist/resources/ops.d.ts +2 -1
- package/dist/resources/ops.d.ts.map +1 -1
- package/dist/resources/ops.js +4 -6
- package/dist/resources/ops.js.map +1 -1
- package/dist/resources/rules.d.ts +1 -1
- package/dist/resources/runs.d.ts +4 -1
- package/dist/resources/runs.d.ts.map +1 -1
- package/dist/resources/runs.js +4 -1
- package/dist/resources/runs.js.map +1 -1
- package/dist/resources/session-sync.d.ts +20 -5
- package/dist/resources/session-sync.d.ts.map +1 -1
- package/dist/resources/session-sync.js +16 -10
- package/dist/resources/session-sync.js.map +1 -1
- package/dist/resources/sessions.d.ts +14 -6
- package/dist/resources/sessions.d.ts.map +1 -1
- package/dist/resources/sessions.js +15 -15
- package/dist/resources/sessions.js.map +1 -1
- package/dist/resources/side-query.d.ts +8 -0
- package/dist/resources/side-query.d.ts.map +1 -1
- package/dist/resources/side-query.js.map +1 -1
- package/dist/resources/tasks.d.ts +2 -0
- package/dist/resources/tasks.d.ts.map +1 -1
- package/dist/resources/tasks.js +2 -0
- package/dist/resources/tasks.js.map +1 -1
- package/dist/resources/tool-approvals.d.ts +61 -8
- package/dist/resources/tool-approvals.d.ts.map +1 -1
- package/dist/resources/tool-approvals.js +32 -9
- package/dist/resources/tool-approvals.js.map +1 -1
- package/dist/settings.d.ts +1 -1
- package/dist/sse.d.ts.map +1 -1
- package/dist/sse.js +4 -4
- package/dist/sse.js.map +1 -1
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +2 -0
- package/dist/sync.js.map +1 -1
- package/dist/transport.d.ts +66 -23
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +129 -27
- package/dist/transport.js.map +1 -1
- package/dist/types.d.ts +134 -27
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -1
- package/openapi.yaml +418 -54
- package/package.json +2 -3
package/openapi.yaml
CHANGED
|
@@ -2428,7 +2428,7 @@ paths:
|
|
|
2428
2428
|
summary: Write the per-session tool-permission rules (tighten-only).
|
|
2429
2429
|
description: >
|
|
2430
2430
|
E6 — write the per-session rules. 🔴 TIGHTEN-ONLY for a normal principal: a loosen (remove a deny / widen
|
|
2431
|
-
an allowlist or allowDirs) → 403 `loosen_forbidden` (operator-only). `expectedRev` = optimistic-concurrency
|
|
2431
|
+
an allowlist or allowDirs) → 403 `loosen_forbidden` (operator-only). 🔴 server >= 7.135.0 (engine 7.55.0): the tighten gate is a gate on the row's OPERATOR PART (`operatorRules`), not on the whole row — a non-operator (the session's owner) can take back what NON-operator writes added, but not what an operator wrote (moving anything inside the operator part, even an entry both sides wrote, answers 403 `loosen_forbidden`; the row stays). <= 7.134.x: a non-operator write was subtract-only against the whole row. Read the CODE (the sentence changed: `a non-operator session-rule write may not loosen what an operator wrote; refused: …` vs `… may only tighten …`) — never the sentence. `expectedRev` = optimistic-concurrency
|
|
2432
2432
|
CAS; a stale rev → 409 `conflict`. Each rule field must be `string[]` and the body carries only the three buckets (`toolAllow` / `toolDeny` / `allowDirs`; any other
|
|
2433
2433
|
key, including the retired `commandAllow` / `commandDeny`, → 400 `rules.invalid_shape` on server >= 7.129.0) → malformed body 400. ownerless
|
|
2434
2434
|
session → 409; non-owner → 404. 501 without a session-policy store.
|
|
@@ -2456,6 +2456,9 @@ paths:
|
|
|
2456
2456
|
# write judge stamps the current grammar). `grammar` newer than the engine's ⇒ `400 rules.invalid_shape`.
|
|
2457
2457
|
rev: { type: integer, minimum: 0 }
|
|
2458
2458
|
grammar: { type: integer, minimum: 0 }
|
|
2459
|
+
# server >= 7.135.0 (engine 7.55.0): a stored body echoed back (GET → edit → PUT) may also carry its `operatorRules`; on THIS door the echoed part is ALWAYS ignored — the route reads the value through the write reader
|
|
2460
|
+
# (its product carries no `rev`) and the store judges it again: over an existing row the STORED row's operator part is kept, over no row an empty stamped part is minted. Do not rely on an echo to move the operator line — send the new value without `operatorRules`.
|
|
2461
|
+
operatorRules: { $ref: '#/components/schemas/SessionRulesOperatorPart' }
|
|
2459
2462
|
expectedRev: { type: integer, minimum: 0, description: CAS — reject if the stored rev differs. }
|
|
2460
2463
|
responses:
|
|
2461
2464
|
'200':
|
|
@@ -2492,7 +2495,8 @@ paths:
|
|
|
2492
2495
|
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
2493
2496
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
2494
2497
|
'403':
|
|
2495
|
-
description:
|
|
2498
|
+
description: >-
|
|
2499
|
+
403 `loosen_forbidden` — a non-operator write tried to relax what an OPERATOR wrote (server >= 7.135.0; <= 7.134.x: relax the rules at all, tighten-only). Branch on the code, never the sentence (it changed with 7.135.0).
|
|
2496
2500
|
content:
|
|
2497
2501
|
application/json:
|
|
2498
2502
|
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
@@ -2581,7 +2585,7 @@ paths:
|
|
|
2581
2585
|
narrow it, switch with a default arm; `httpStatus` 401 is a re-authorize door); `reason` is HUMAN TEXT
|
|
2582
2586
|
(server-redacted, length-bounded) and must NOT be parsed.
|
|
2583
2587
|
Gates, the same family as steer / capture-optout: 501 `capability.run_store_required` (no durable run
|
|
2584
|
-
ledger) · 501 `capability.session_ownership_required` (no `sessionStorage.ownerOf`) · 400
|
|
2588
|
+
ledger) · 501 `capability.session_ownership_required` (no `sessionStorage.headOf`; <= 7.134.x: `ownerOf`) · 400
|
|
2585
2589
|
`request.path_malformed` (bad percent-encoding in the id) · 404 `not_found.session` — unknown session
|
|
2586
2590
|
AND someone else's session answer the SAME code and SAME message (deliberate: no existence oracle); an
|
|
2587
2591
|
EXPLICIT operator may re-dial any tenant's session · 422 `steering.invalid_content` · 409
|
|
@@ -2647,7 +2651,7 @@ paths:
|
|
|
2647
2651
|
the model's description, falling back to the launch command text (content family: redacted, cut at 500
|
|
2648
2652
|
chars). At most 500 rows (core `list()`'s own cap). 🔴 IN-PROCESS: only rows on THIS replica.
|
|
2649
2653
|
Zero model work: not billable, not refused by drain. Gates (same family as `mcp/reconnect`): 501
|
|
2650
|
-
`capability.session_ownership_required` (no `sessionStorage.ownerOf`) · 404 `not_found.session` — unknown
|
|
2654
|
+
`capability.session_ownership_required` (no `sessionStorage.headOf`; <= 7.134.x: `ownerOf`) · 404 `not_found.session` — unknown
|
|
2651
2655
|
session AND someone else's session answer the SAME code and SAME message (no existence oracle); an EXPLICIT
|
|
2652
2656
|
operator may read any session · 400 `request.path_malformed`. Probe with `capabilities.background.listFace`;
|
|
2653
2657
|
ABSENT key = an older server, where this path is 404 `not_found.route` (same status, different code).
|
|
@@ -2920,6 +2924,15 @@ paths:
|
|
|
2920
2924
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
2921
2925
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
2922
2926
|
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
2927
|
+
'503':
|
|
2928
|
+
description: >-
|
|
2929
|
+
server >= 7.135.0: `503 state.file_history_unreadable` — this session's file history cannot be read WHOLE (a boundary torn / unreadable, the tracked set unreadable); nothing is exported this time. 🔴 It is NOT "no history":
|
|
2930
|
+
with nothing to export the manifest still answers `200` with `fileHistory: null`. May carry `permanence` (`transient` / `terminal`; absent = the store did not judge — see `ErrorResponse.permanence`). Older servers read an
|
|
2931
|
+
unreadable history as "none" (manifest 200 / blob 404).
|
|
2932
|
+
Server >= 7.136.0: the SAME code with `permanence: "transient"` also answers a database / store connection failure on this leg (the entry-id set, policy, anchors, session row, the history read — the code's `file_history` is its origin; the action reads `permanence`); before 7.136.0 that fell to a generic `500 internal.error`. The SDK retries this 503 up to `maxRetries` times BEFORE the first byte (the same retrier on all three pull legs), except `permanence: "terminal"` (the store judged retrying useless until it is repaired).
|
|
2933
|
+
content:
|
|
2934
|
+
application/json:
|
|
2935
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
2923
2936
|
|
|
2924
2937
|
/v1/sessions/{sessionId}/sync/entries:
|
|
2925
2938
|
parameters:
|
|
@@ -2957,6 +2970,13 @@ paths:
|
|
|
2957
2970
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
2958
2971
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
2959
2972
|
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
2973
|
+
'503':
|
|
2974
|
+
description: >-
|
|
2975
|
+
server >= 7.136.0: `503 state.file_history_unreadable` + `permanence: "transient"` — a database / store connection failure BEFORE the response head is sent (nothing is streamed; before 7.136.0 a generic `500 internal.error`). The code's `file_history` is its origin; the action reads `permanence` (see `ErrorResponse.permanence`).
|
|
2976
|
+
A disconnect AFTER the 200 head can only truncate the stream — no `{"__sync":"end"}` trailer — and is never a 5xx. The SDK retries the 503 up to `maxRetries` times BEFORE the first byte (the same retrier on all three pull legs), except `permanence: "terminal"` (the store judged retrying useless until it is repaired); a truncated body is not retried (resume with `afterSeq`).
|
|
2977
|
+
content:
|
|
2978
|
+
application/json:
|
|
2979
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
2960
2980
|
|
|
2961
2981
|
/v1/sessions/{sessionId}/sync/history/blobs/{hash}:
|
|
2962
2982
|
parameters:
|
|
@@ -2994,6 +3014,15 @@ paths:
|
|
|
2994
3014
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
2995
3015
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
2996
3016
|
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
3017
|
+
'503':
|
|
3018
|
+
description: >-
|
|
3019
|
+
server >= 7.135.0: `503 state.file_history_unreadable` — the history cannot be read WHOLE, so the server cannot tell whether this hash is one the session references — it does NOT answer "no such blob" (that is `404 not_found.blob`) and gives no bytes. 🔴 It is NOT "no history":
|
|
3020
|
+
with nothing to export the manifest still answers `200` with `fileHistory: null`. May carry `permanence` (`transient` / `terminal`; absent = the store did not judge — see `ErrorResponse.permanence`). Older servers read an
|
|
3021
|
+
unreadable history as "none" (manifest 200 / blob 404).
|
|
3022
|
+
Server >= 7.136.0: the SAME code with `permanence: "transient"` also answers a database / store connection failure on this leg (the history read or the blob bytes read — the code's `file_history` is its origin; the action reads `permanence`); before 7.136.0 that fell to a generic `500 internal.error`. The SDK retries this 503 up to `maxRetries` times BEFORE the first byte (the same retrier on all three pull legs), except `permanence: "terminal"` (the store judged retrying useless until it is repaired).
|
|
3023
|
+
content:
|
|
3024
|
+
application/json:
|
|
3025
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
2997
3026
|
|
|
2998
3027
|
/v1/sessions/{sessionId}/sync/blobs/{hash}:
|
|
2999
3028
|
parameters:
|
|
@@ -3091,12 +3120,15 @@ paths:
|
|
|
3091
3120
|
description: >
|
|
3092
3121
|
2c session-sync PUSH Phase A — a SMALL metadata body (`entryIds, fileHistory?, policy, anchors, resolution?, logDigest?, title?, pinned?`); the
|
|
3093
3122
|
entries stream in Phase B. The cloud classifies (§7), pre-checks blob presence (a missing referenced hash →
|
|
3094
|
-
422 `missing_blob` — PUT it first
|
|
3123
|
+
422 `missing_blob` — PUT it first; server >= 7.135.0 answers it in this FIRST phase — zero staging, zero commit, ahead of the `identical` replay arm — and
|
|
3124
|
+
a deployment whose `capabilities.sessionSyncFileHistory` is false, e.g. `DB_BACKEND=local`, takes a `fileHistory` that references blobs as a first-phase 422 too: the conversation does not land either; <= 7.134.x answered it after the conversation
|
|
3125
|
+
had committed), guards the import lease + any active run (409), then mints a stagingId. 🔴 server >= 7.135.0: a file-history replay fault (the replay arms of `identical` re-push and of the commit) answers `422 adopt_failed`
|
|
3126
|
+
(+ optional `permanence`, see `ErrorResponse.permanence`; <= 7.134.x: `unsupported_format`) — distinct from `missing_blob`.
|
|
3095
3127
|
The file history rides `fileHistory` (a `FileHistoryExport` envelope, `null` / absent = none) and every blob it references must have been
|
|
3096
3128
|
`PUT …/sync/blobs/{hash}` first (the `snapshots` key of servers <= 7.51 is outside the support range; a supported server ignores it and sdk 26.0.0
|
|
3097
3129
|
no longer declares it). The SDK carries `fileHistory` in `pushSessionBundle` / `importSessionBundle`; a hand-rolled
|
|
3098
|
-
push must send `fileHistory` itself, and only to a peer whose `capabilities.sessionSyncFileHistory` is not false (server >= 7.116.0 — else
|
|
3099
|
-
commit
|
|
3130
|
+
push must send `fileHistory` itself, and only to a peer whose `capabilities.sessionSyncFileHistory` is not false (server >= 7.116.0 — else
|
|
3131
|
+
`422 missing_blob` in the first phase from server >= 7.135.0; after the commit on <= 7.134.x).
|
|
3100
3132
|
`identical` → `{ relation:"identical", basis, payloadVerified }` with NO stagingId (skip Phase B);
|
|
3101
3133
|
`basis` is `"entry-ids+digest"` when the caller supplied a comparable digest and it matched, else
|
|
3102
3134
|
`"entry-ids"` (id-set equality only) — see the `ImportStaged` schema, which has carried these two
|
|
@@ -3169,7 +3201,12 @@ paths:
|
|
|
3169
3201
|
content:
|
|
3170
3202
|
application/json:
|
|
3171
3203
|
schema: { $ref: '#/components/schemas/SyncConflict' }
|
|
3172
|
-
'422':
|
|
3204
|
+
'422':
|
|
3205
|
+
description: >-
|
|
3206
|
+
422 — `missing_blob` (first phase from server >= 7.135.0), `restore_failed`, and (server >= 7.135.0) `adopt_failed` (+ optional `permanence`) for the file-history replay; `invalid_entries` etc. as before. Branch on `errorCode`.
|
|
3207
|
+
content:
|
|
3208
|
+
application/json:
|
|
3209
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
3173
3210
|
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
3174
3211
|
'503': { $ref: '#/components/responses/Unauthorized' } # (declared 2026-08-01) E6 兄弟守卫:无 service token + 未开 ALLOW_UNAUTHED_WRITES 时,这条 import 提交腿与 `PUT …/policy` 写的是同一个 policy store ⇒ 同门同码 `auth.service_token_required`(server 3.15.0 起)
|
|
3175
3212
|
|
|
@@ -3211,7 +3248,8 @@ paths:
|
|
|
3211
3248
|
'400': { $ref: '#/components/responses/BadRequest' }
|
|
3212
3249
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
3213
3250
|
'403':
|
|
3214
|
-
description:
|
|
3251
|
+
description: >-
|
|
3252
|
+
403 `loosen_forbidden` — a post-commit policy replay tried to relax what an operator wrote (server >= 7.135.0; <= 7.134.x: tighten-only against the whole row). A non-operator replay keeps each record's own operator part; an operator replay makes the imported row the operator's.
|
|
3215
3253
|
content:
|
|
3216
3254
|
application/json:
|
|
3217
3255
|
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
@@ -3259,7 +3297,14 @@ paths:
|
|
|
3259
3297
|
server >= 7.134.0: a queue row whose stored body cannot be read (the store's refusal contract — a retry fails the same way; an operator has to repair
|
|
3260
3298
|
or delete that row) answers `500` + `errorCode: "approvals.read_corrupt"` (body `{ error, errorCode }`; the bad row's coordinates stay off the wire) —
|
|
3261
3299
|
the same judge and the same code as `GET /v1/approvals/stream`. Do NOT retry it as-is (the SDK's GET retry arm exempts the code). Every other read
|
|
3262
|
-
failure (connection / timeout / store hiccup) is
|
|
3300
|
+
failure (connection / timeout / store hiccup) is `503 approvals.read_unavailable` from server >= 7.135.0 (below); servers <= 7.134.x answered it `500 internal.error`. Older servers answered the corrupt row with `internal.error`.
|
|
3301
|
+
content:
|
|
3302
|
+
application/json:
|
|
3303
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
3304
|
+
'503':
|
|
3305
|
+
description: >-
|
|
3306
|
+
server >= 7.135.0: `503 approvals.read_unavailable` — the approvals queue could not be read RIGHT NOW (the store hiccuped; transient — the SDK retries it by status). Until a read succeeds, an answer here does NOT mean nothing is pending.
|
|
3307
|
+
Body `{ error, errorCode }`. Older servers answered a read that could not complete with the global fallback `500 internal.error`.
|
|
3263
3308
|
content:
|
|
3264
3309
|
application/json:
|
|
3265
3310
|
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
@@ -3339,7 +3384,10 @@ paths:
|
|
|
3339
3384
|
schema: { $ref: '#/components/schemas/ApprovalDecision' }
|
|
3340
3385
|
responses:
|
|
3341
3386
|
'200':
|
|
3342
|
-
description:
|
|
3387
|
+
description: >-
|
|
3388
|
+
Decision accepted. Usually the run (or the parked background agent) resumes; on the two parked-agent forms that can never revive,
|
|
3389
|
+
a DENY (server >= 7.136.0) is answered `{ taskId, status: "failed", decision: "deny" }` instead — the card is voided and nothing resumes
|
|
3390
|
+
(see `ParkedDecideAccepted`, `ApprovalDecisionResult`).
|
|
3343
3391
|
content:
|
|
3344
3392
|
application/json:
|
|
3345
3393
|
schema: { $ref: '#/components/schemas/ApprovalDecisionResult' }
|
|
@@ -3514,6 +3562,10 @@ paths:
|
|
|
3514
3562
|
the claim and rolls back when it is gone or different) — a 7.104.0 session delete retires such cards, so this form
|
|
3515
3563
|
mostly meets cards left by a pre-7.104.0 delete; `decide.row_unrevivable` (DecideError) now also answers when the
|
|
3516
3564
|
parked row carries no root-session anchor (refused before the claim, nothing consumed).
|
|
3565
|
+
server >= 7.136.0 — those two never-revive forms (a parked child whose row carries no agent name; a row with no root-session anchor) keep answering APPROVE with this 409 (the sentence now ends
|
|
3566
|
+
by pointing at deny), but DENY answers `200 { taskId, status: "failed", decision: "deny" }`: the card is voided under its own scope CAS and leaves the pending queue and the
|
|
3567
|
+
`/v1/approvals/stream` snapshot, the child ends `failed`, the gated tool never runs, no `remember` is granted; a lost void CAS is the existing 409 `decide.gate_moved`. Branch on
|
|
3568
|
+
`status` / `errorCode`, not on the sentence.
|
|
3517
3569
|
content:
|
|
3518
3570
|
application/json:
|
|
3519
3571
|
schema: { $ref: '#/components/schemas/ResumeLegConflictError' }
|
|
@@ -3707,6 +3759,20 @@ paths:
|
|
|
3707
3759
|
application/json:
|
|
3708
3760
|
schema: { $ref: '#/components/schemas/InboxList' }
|
|
3709
3761
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
3762
|
+
'500':
|
|
3763
|
+
description: >-
|
|
3764
|
+
server >= 7.135.0: `500 approvals.read_corrupt` — a queue row's stored body cannot be read (the store's refusal contract: a retry fails the same way; an operator has to repair or delete that row) — the SAME judge and the same code as `GET /v1/approvals`
|
|
3765
|
+
and `GET /v1/approvals/stream`. Do NOT retry it as-is (the SDK's retry arm exempts the code). Every other read failure is `503 approvals.read_unavailable` (below). Older servers: `500 internal.error`.
|
|
3766
|
+
content:
|
|
3767
|
+
application/json:
|
|
3768
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
3769
|
+
'503':
|
|
3770
|
+
description: >-
|
|
3771
|
+
server >= 7.135.0: `503 approvals.read_unavailable` — the approvals queue could not be read RIGHT NOW (the store hiccuped; transient — the SDK retries it by status). Until a read succeeds, an answer here does NOT mean nothing is pending.
|
|
3772
|
+
Body `{ error, errorCode }`. Older servers answered a read that could not complete with the global fallback `500 internal.error`.
|
|
3773
|
+
content:
|
|
3774
|
+
application/json:
|
|
3775
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
3710
3776
|
|
|
3711
3777
|
/v1/assistant/tasks:
|
|
3712
3778
|
parameters:
|
|
@@ -3728,6 +3794,20 @@ paths:
|
|
|
3728
3794
|
application/json:
|
|
3729
3795
|
schema: { $ref: '#/components/schemas/AssistantTaskList' }
|
|
3730
3796
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
3797
|
+
'500':
|
|
3798
|
+
description: >-
|
|
3799
|
+
server >= 7.135.0: `500 approvals.read_corrupt` — a queue row's stored body cannot be read (the store's refusal contract: a retry fails the same way; an operator has to repair or delete that row) — the SAME judge and the same code as `GET /v1/approvals`
|
|
3800
|
+
and `GET /v1/approvals/stream`. Do NOT retry it as-is (the SDK's retry arm exempts the code). Every other read failure is `503 approvals.read_unavailable` (below). Older servers: `500 internal.error`.
|
|
3801
|
+
content:
|
|
3802
|
+
application/json:
|
|
3803
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
3804
|
+
'503':
|
|
3805
|
+
description: >-
|
|
3806
|
+
server >= 7.135.0: `503 approvals.read_unavailable` — the approvals queue could not be read RIGHT NOW (the store hiccuped; transient — the SDK retries it by status). Until a read succeeds, an answer here does NOT mean nothing is pending.
|
|
3807
|
+
Body `{ error, errorCode }`. Older servers answered a read that could not complete with the global fallback `500 internal.error`.
|
|
3808
|
+
content:
|
|
3809
|
+
application/json:
|
|
3810
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
3731
3811
|
|
|
3732
3812
|
/v1/assistant/tasks/{taskId}/resume:
|
|
3733
3813
|
parameters:
|
|
@@ -5921,6 +6001,14 @@ paths:
|
|
|
5921
6001
|
schema: { $ref: '#/components/schemas/WorkflowJournalPage' }
|
|
5922
6002
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
5923
6003
|
'404': { $ref: '#/components/responses/NotFound' }
|
|
6004
|
+
'500':
|
|
6005
|
+
description: >-
|
|
6006
|
+
server >= 7.135.0 (core 7.55.0): `500 workflow.journal_incompatible` — a journal row the engine's judge rejects (a parked row with no checkpoint token, a parked row whose terminal is not paused, a row that does not read as an object — hand-edited / another writer /
|
|
6007
|
+
a newer format). The judgment covers the WHOLE journal, on every backend, on every page (a bad row on another page, or one over 64 KiB, answers the same); the body carries `ordinal` (the first bad row, ascending; `-1` = the refusal names no entry). The run's resume is refused by the engine
|
|
6008
|
+
with the same code. Repair that row from the retained copy — NEVER by deleting it (a missing entry re-runs that step live). A retry changes nothing (the SDK's retry arm exempts the code). <= 7.134.x read such rows back as `200`.
|
|
6009
|
+
content:
|
|
6010
|
+
application/json:
|
|
6011
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
5924
6012
|
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
5925
6013
|
|
|
5926
6014
|
/v1/workflows/{workflowRunId}/agents/{label}/steer:
|
|
@@ -7006,8 +7094,32 @@ components:
|
|
|
7006
7094
|
enabled: { type: boolean }
|
|
7007
7095
|
available: { type: boolean, description: 'whether this deployment can actually RUN the scenario right now — same predicate as the 501 rejection arm on submit; false ⟺ submitting is guaranteed to 501. Independent axis from `enabled` (declared vs runnable).' }
|
|
7008
7096
|
attachmentSupplies: { type: array, items: { type: string, enum: [path, content_text, content_image] }, description: 'server >= 7.133.0, always present there: the attachment SUPPLY words this scenario actually carries — a subset of `capabilities.userAttachments.supplies` (`path` only on hands scenarios, where a workspace lives somewhere; a no-hands scenario drops `path`, and a `path` entry is refused by the engine with `config.user_attachment_invalid`). ABSENT = server <= 7.132.x: fall back to `userAttachments.supplies` plus the existing 400 handling.' }
|
|
7097
|
+
skills:
|
|
7098
|
+
type: array
|
|
7099
|
+
items: { $ref: '#/components/schemas/ScenarioSkill' }
|
|
7100
|
+
description: >-
|
|
7101
|
+
server >= 7.135.0, always present there (`[]` when none): the deployment SKILLS this scenario's run mounts (the deployment skills directory UNION what the config source hands over, filtered by scenario; a request's own `skills` are not
|
|
7102
|
+
included) — the same single filter that feeds `TaskSpec`, same group, same order. A client's `/skill-name` completion reads it; naming one goes through `userInvokedSkills`. Entries carry no body and none of a skill's tool lists. On the card
|
|
7103
|
+
but not in the run: `disableSkills: true` (nothing mounted) and a skill whose body exceeds the engine's load cap (naming it answers `config.user_invoked_skill_unknown`). ABSENT = an older server: the list cannot be read —
|
|
7104
|
+
NOT "no skills" (that is `[]`). Bit: `capabilities.scenarioSkills`.
|
|
7009
7105
|
unavailableReason: { type: string, description: 'machine-readable reason, present ONLY when available:false (absent = no reason). Closed set, currently the single member `git_client_unconfigured`; branch on the key, never match the English prose. Additive-open: treat an unknown word as "unavailable, reason unknown".' }
|
|
7010
7106
|
|
|
7107
|
+
ScenarioSkill:
|
|
7108
|
+
type: object
|
|
7109
|
+
description: One row of `ScenarioDetail.skills` (server >= 7.135.0). No body, no tool lists.
|
|
7110
|
+
additionalProperties: false
|
|
7111
|
+
required: [name, description, source]
|
|
7112
|
+
properties:
|
|
7113
|
+
name: { type: string }
|
|
7114
|
+
description: { type: string }
|
|
7115
|
+
source: { $ref: '#/components/schemas/ScenarioSkillSource' }
|
|
7116
|
+
ScenarioSkillSource:
|
|
7117
|
+
type: string
|
|
7118
|
+
description: >
|
|
7119
|
+
Where a scenario skill came from (server >= 7.135.0; the server's self-minted word table `scenarioSkillSource`, closed two words): `factory` = the deployment's skills directory (`SKILLS_DIR`);
|
|
7120
|
+
`center` = the config source (the center / the local `config.d` skills list, or a config-declared plugin) — a skill that overrides a same-named factory one by name is also `center`.
|
|
7121
|
+
enum: [factory, center]
|
|
7122
|
+
|
|
7011
7123
|
RunStatus:
|
|
7012
7124
|
type: string
|
|
7013
7125
|
enum: [running, completed, failed, suspended, needs_review, blocked]
|
|
@@ -7279,10 +7391,16 @@ components:
|
|
|
7279
7391
|
`egress:true` + `effect:"write"` (core's ruling); `toolAxes` is the caller's explicit override face.
|
|
7280
7392
|
🔴 A malformed entry drops the WHOLE peer (named in a warn), never "drop the bad key and keep the
|
|
7281
7393
|
peer": `allowSkills` is a NARROWING field whose absence means "no restriction", so a half-applied
|
|
7282
|
-
entry would turn a narrowing intent into a widening.
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7394
|
+
entry would turn a narrowing intent into a widening.
|
|
7395
|
+
🔴 server >= 7.136.0 — on a FRESH submit (the three submit doors) a badly written declaration is REFUSED, not dropped, and no longer answers a 200
|
|
7396
|
+
that reads as "in effect": a list that is not an array / an entry that is not an object / a key value the judge cannot read as usable
|
|
7397
|
+
(`url` not an http(s) string, `headers` values that are not strings, `allowSkills` not a string array …) ⇒ `400 request.field_invalid` with the sentence only
|
|
7398
|
+
(no `field` / `reason`); a key outside the peer vocabulary (a mis-spelled `allowSkill` …) ⇒ `400 request.body_shape` + `unknownKeys` (full coordinates, e.g.
|
|
7399
|
+
`a2aPeers[0].allowSkill`); a `url` / `cardUrl` that carries a credential ⇒ `400 request.field_invalid` WITH `field` / `reason` (`url_userinfo` / `url_credential_param`);
|
|
7400
|
+
more than 32 entries ⇒ `400 request.field_invalid` WITH `field: "a2aPeers"` / `reason: "over_cap"` / `count` / `cap`. Branch on `errorCode` / `unknownKeys` / `field`, never on the sentence.
|
|
7401
|
+
The durable-resume REPLAY leg (a stored body re-read on resume) does NOT refuse: it keeps the reader's degradation — a bad entry is not mounted and is named in an operator warn, the request is not 400.
|
|
7402
|
+
Servers <= 7.135.x: a malformed entry drops the whole peer (warn), the request is not rejected, and over the cap the surplus is dropped (7.135.0 already answers 400 `over_cap`).
|
|
7403
|
+
The center/config baseline wins on a name clash (the peer name IS the tool namespace segment).
|
|
7286
7404
|
items: { $ref: '#/components/schemas/A2aServerSpec' }
|
|
7287
7405
|
resumeAt:
|
|
7288
7406
|
type: string
|
|
@@ -7290,7 +7408,7 @@ components:
|
|
|
7290
7408
|
CC Rewind parity (E18). Fork the conversation FROM this user-message SessionTreeEntry.id (non-destructive
|
|
7291
7409
|
branch via setLeafId). With `restoreFiles: true` ⇒ "both" (also restore the working tree — the retired spelling
|
|
7292
7410
|
`rewindFiles` still rides the wire but its restore sense is core's typed migration rejection naming `restoreFiles`). Alone ⇒
|
|
7293
|
-
"conversation". HONORED only where the deployment wired a resume-anchor store + getLeafId (capabilities.resumeAt);
|
|
7411
|
+
"conversation". HONORED only where the deployment wired a resume-anchor store + the session head read `headOf` (<= 7.134.x: `getLeafId`) (capabilities.resumeAt);
|
|
7294
7412
|
unknown anchor ⇒ 4xx, capability-off ⇒ 501. Cannot combine with a durable resume.
|
|
7295
7413
|
resumeAtMode:
|
|
7296
7414
|
type: string
|
|
@@ -7324,7 +7442,7 @@ components:
|
|
|
7324
7442
|
kind of handle as `resumeAt`, resolved through the SAME anchor store — typically the `taskId` from that turn's
|
|
7325
7443
|
202 receipt (the server keys the user-message anchor by the run's taskId). Server `src/boot/resolve-spec.ts:686-697`:
|
|
7326
7444
|
`resumeAnchorStore.resolve(sessionId, handle, principal)` → entry id; unknown handle ⇒ 404
|
|
7327
|
-
`rewind_files_to.unknown_event`; no session ⇒ 422 `rewind_files_to.no_session`; no anchor store / no getLeafId ⇒
|
|
7445
|
+
`rewind_files_to.unknown_event`; no session ⇒ 422 `rewind_files_to.no_session`; no anchor store / no session head read (`headOf`; <= 7.134.x: `getLeafId`) ⇒
|
|
7328
7446
|
501. ⚠️ The 501 is NOT the capability's whole predicate: `capabilities.rewindFilesTo` also requires the
|
|
7329
7447
|
file-history store; without it the server does not 501 — core refuses at prepare with
|
|
7330
7448
|
`rewind.store_unconfigured` (server >= 7.104.0 / S-724: a 409 error body on the synchronous `POST /v1/tasks` when
|
|
@@ -7501,7 +7619,7 @@ components:
|
|
|
7501
7619
|
not exceed 5 MiB — otherwise the engine refuses BEFORE the first model call (after the UserPromptSubmit hook; not one model token spent) with 400 `config.image_invalid`, whose
|
|
7502
7620
|
`error` starts with `TaskSpec.images: `. Before 7.117.0 such an image was sent as-is to the model provider and the whole first request failed there (no code to branch on).
|
|
7503
7621
|
A base64 string longer than 5 242 880 characters (the model API's 5 MB image cap; the server reads the engine's exported constant) is NOT this code: the submit gate refuses it first
|
|
7504
|
-
with 413 `request.payload_too_large` (zero model calls, no submit hook, no run row). The `{ url }` arm is unchanged. The model must accept image input (`ModelInfo.vision`; absent = unknown, send anyway).
|
|
7622
|
+
with 413 `request.payload_too_large` (zero model calls, no submit hook, no run row). The `{ url }` arm: from server >= 7.136.0 a URL that carries a credential (`user:pass@host`, or a credential-named query / fragment parameter) is refused on a FRESH submit with 400 `request.field_invalid` + `field: "images[i].url"` + `reason` `url_userinfo` / `url_credential_param` (the sixth seat of the URL-credential judge; send the bytes inline as `{ data, mimeType }` instead — an inline image never lands in a URL); the durable-resume replay of a stored body is not judged. Otherwise unchanged (the server has long recognised the type by signature). The model must accept image input (`ModelInfo.vision`; absent = unknown, send anyway).
|
|
7505
7623
|
items:
|
|
7506
7624
|
oneOf:
|
|
7507
7625
|
- type: object
|
|
@@ -7920,6 +8038,15 @@ components:
|
|
|
7920
8038
|
combination); `taskWriteFaceOpen` is NOT its reading. Residual (server S-908): the binding is keyed by SESSION and written
|
|
7921
8039
|
after the run is claimed (a refused request writes nothing); on deployments without a run store two concurrently accepted
|
|
7922
8040
|
runs on one session are last-writer-wins. Delegated children's shells keep the default scrub.
|
|
8041
|
+
projectMemory:
|
|
8042
|
+
type: string
|
|
8043
|
+
enum: [disabled]
|
|
8044
|
+
description: >
|
|
8045
|
+
server >= 7.135.0 (engine 7.55.0 `TaskSpec.projectMemory`, passed through verbatim): this ONE run does not read the deployment's project context — the engine does not call the deployment's project-context seat, so the project layer,
|
|
8046
|
+
the declared instruction files and the few things they feed are all absent (the engine's own git-status lane, the memory engine, skills / hooks / MCP are unaffected; delegated / background / fork / workflow children inherit it from
|
|
8047
|
+
the parent). The only word is `disabled`; the key ABSENT = call the seat. The leg's `wiring_manifest.projectMemory` reads `disabled` and the server-minted `instructions` section is absent. A deployment without the seat still accepts it
|
|
8048
|
+
(the manifest answers `absent`). Anything else (`off`, a boolean, `null`) ⇒ a fresh submit answers 400 `request.field_invalid`; a resume replay judges the same and folds into 409 `resume_blocked_by_policy`
|
|
8049
|
+
(`blockedBy: request.field_invalid`). Read `capabilities.projectMemory` beforehand: older servers answer 400 `request.body_shape` (`unknownKeys: ["projectMemory"]`).
|
|
7923
8050
|
attachments:
|
|
7924
8051
|
type: object
|
|
7925
8052
|
description: >
|
|
@@ -9596,8 +9723,8 @@ components:
|
|
|
9596
9723
|
(`decision: "approve"`, `decidedBy` absent or `person`): on a deny or a `decidedBy: "policy"` decision ⇒ 400 `request.field_conflict` with
|
|
9597
9724
|
`detail.kind: "approval_feedback"` and `detail.fields` `["feedback", "decision"]` / `["feedback", "decidedBy"]` (a denial's words go in `reason`);
|
|
9598
9725
|
a non-string ⇒ 400 `request.field_invalid`; any value on a direct-door worker ⇒ 400 `feedback_not_in_proof` (not inside the signed proof); words
|
|
9599
|
-
carrying `<system-reminder>` ⇒ 409 `
|
|
9600
|
-
do not auto-refetch and re-decide on the code). The same door serves parked background-agent cards and workflow child cards; the live
|
|
9726
|
+
carrying `<system-reminder>` ⇒ server >= 7.135.0 (engine 7.55.0): 409 `resume_outcome_invalid` + `field: "feedback"` + `retriable: true` (the engine's sentence naming `feedback`; refused before the CAS, the card stays pending — ask the person to change
|
|
9727
|
+
or drop the words, do not auto-refetch and re-decide on the code); server 7.134.x: 409 `approval_binding_mismatch` (no `field`). The same door serves parked background-agent cards and workflow child cards; the live
|
|
9601
9728
|
`POST /v1/tool-approvals/{id}/respond` does NOT take it. Servers <= 7.133.x refuse the key (400 `request.body_shape`, `unknownKeys: ["feedback"]`).
|
|
9602
9729
|
|
|
9603
9730
|
Capabilities:
|
|
@@ -9807,7 +9934,7 @@ components:
|
|
|
9807
9934
|
type: boolean
|
|
9808
9935
|
description: >-
|
|
9809
9936
|
Code-only rewind (`TaskRequest.rewindFilesTo`) is wired — mint `routes/capabilities.ts:839` =
|
|
9810
|
-
`Boolean(deps.fileHistoryStore && deps.resumeAnchorStore && deps.sessionStorage?.getLeafId)
|
|
9937
|
+
`Boolean(deps.fileHistoryStore && deps.resumeAnchorStore && headReadOf(deps.sessionStorage))` (<= 7.134.x last conjunct: `deps.sessionStorage?.getLeafId`): it needs the
|
|
9811
9938
|
file-history store (to restore) AND the anchor map (to resolve the target HANDLE). Corrected in sdk 11.4.0
|
|
9812
9939
|
(board [8437] U3): the store is the FILE-HISTORY store (not the pre-S-15 whole-tree snapshot store).
|
|
9813
9940
|
🔴 K-24: on server 7.97.0–7.103.x that seat was the CAPTURE face (backend AND the `FILE_HISTORY_CAPTURE` knob), so a
|
|
@@ -9889,8 +10016,9 @@ components:
|
|
|
9889
10016
|
description: >
|
|
9890
10017
|
🔴 契约调和车1 H② (2026-08-02): server HAS been emitting this key (the `sessionEvents` bit in `src/http/routes/capabilities.ts`)
|
|
9891
10018
|
while both this spec and the SDK type were missing it. Gates `GET /v1/sessions/{sessionId}/events`
|
|
9892
|
-
(the session-level SSE head subscription). Predicate is a
|
|
9893
|
-
plus a session store exposing BOTH `getLeafId` and `ownerOf
|
|
10019
|
+
(the session-level SSE head subscription). Predicate (server >= 7.135.0) is a TWO-way AND: a durable session-watch seam
|
|
10020
|
+
plus a session store exposing the session head read `headOf` (<= 7.134.x it was a THREE-way AND with BOTH `getLeafId` and `ownerOf`; those two
|
|
10021
|
+
methods left the store contract in 7.135.0, so `DB_BACKEND=memory` now answers `true`, was `false`) — the route's 501 uses the same
|
|
9894
10022
|
predicate, so "says yes <=> route works" holds here. False/absent => fall back to polling
|
|
9895
10023
|
`GET /v1/sessions/{sessionId}/head`. NOTE (server [2373]A-5): no consumer is wired to it yet — it is
|
|
9896
10024
|
a prepared slot, correct to gate on, wrong to read as "widely consumed".
|
|
@@ -10222,11 +10350,29 @@ components:
|
|
|
10222
10350
|
— SQL backends only; `DB_BACKEND=local` is always false). Advertises exactly the two file-history blob faces
|
|
10223
10351
|
`PUT /v1/sessions/{sessionId}/sync/blobs/{hash}` and `GET /v1/sessions/{sessionId}/sync/history/blobs/{hash}`.
|
|
10224
10352
|
READ IT ON BOTH ENDS of a sync: if either is false, sync the conversation only — do not push `fileHistory`, do
|
|
10225
|
-
not PUT blobs (a `fileHistory` pushed to a peer without the blob faces 422s `missing_blob` after
|
|
10353
|
+
not PUT blobs (a `fileHistory` pushed to a peer without the blob faces 422s `missing_blob` in the FIRST phase — zero staging, zero commit, the conversation does not land either — from server >= 7.135.0; <= 7.134.x answered it in the second phase, after the conversation committed). When
|
|
10226
10354
|
false the two routes answer 501 `capability.snapshot_store_required` (any session id, ahead of the owner check).
|
|
10227
10355
|
A blob that the session history graph does not reference / whose bytes are gone stays a 404 `not_found.blob`.
|
|
10228
10356
|
ABSENT = an older server (<= 7.115.x): the bit cannot be read there (a `DB_BACKEND=local` deployment with
|
|
10229
10357
|
`sessionSync: true` answered PUT blob 501 on every call), so try as before.
|
|
10358
|
+
sessionRulesNamespaceForms:
|
|
10359
|
+
type: boolean
|
|
10360
|
+
description: >
|
|
10361
|
+
server >= 7.135.0 (predicate class "always true", read per request from the engine's protocol table): the session-rule write faces (`PUT /v1/sessions/{id}/policy`, the `policy` face of `POST /v1/sessions/{id}/sync/import`)
|
|
10362
|
+
accept — in `toolAllow` / `toolDeny` — the three COVERING FORMS of every protocol namespace the engine knows (today `mcp__` and `a2a__`): the whole peer (`mcp__srv`), a tool-segment wildcard (`mcp__srv__*`)
|
|
10363
|
+
and a tool-segment glob (`mcp__srv__get_*`); the engine's matcher reads each as ONE GROUP of tools. A client may stop refusing those three forms losslessly on this bit alone (never on a version guess).
|
|
10364
|
+
The bit says NOTHING about other wildcards: `*`, partial peer-segment wildcards (`mcp__git*`) and a trailing-separator `mcp__srv__` are still refused by the write face (`400 rules.inert_entry`); the whole-protocol
|
|
10365
|
+
name `mcp__*` is accepted only in `toolDeny`. Orthogonal to `sessionPolicy` (does the deployment have a session-rules write face at all): read `sessionPolicy` AND this bit. ABSENT (older server) and `false` ⇒ read as "do not widen".
|
|
10366
|
+
projectMemory:
|
|
10367
|
+
type: boolean
|
|
10368
|
+
description: >
|
|
10369
|
+
server >= 7.135.0 (always true): the top-level request key `projectMemory: "disabled"` is accepted. The read face hangs on no facility — a deployment without a project-context seat still accepts it
|
|
10370
|
+
(the manifest answers `"absent"`). ABSENT = an older server, whose key-closure gate answers `400 request.body_shape` (`unknownKeys` names it): send the key on sight of the bit only.
|
|
10371
|
+
scenarioSkills:
|
|
10372
|
+
type: boolean
|
|
10373
|
+
description: >
|
|
10374
|
+
server >= 7.135.0 (always true): `GET /v1/capabilities/scenarios/{name}` carries `skills[]` (`ScenarioDetail.skills`). ABSENT = an older server: the card has no list — do NOT read that as "this scenario has no skills"
|
|
10375
|
+
(that is `skills: []`).
|
|
10230
10376
|
|
|
10231
10377
|
# ─── S-139(sdk 8.3.0):对 server 7.60.0 的整体重对账补齐的 19 位 ───────────────────────
|
|
10232
10378
|
# 行号 = server 7.60.0 树的 `src/http/routes/capabilities.ts`。语义与谓词的全文在
|
|
@@ -10513,7 +10659,7 @@ components:
|
|
|
10513
10659
|
type: boolean
|
|
10514
10660
|
description: >
|
|
10515
10661
|
server >= 7.85.0 (S-381 / core 7.22.0 #857; mint `routes/capabilities.ts:264` =
|
|
10516
|
-
`Boolean(deps.runStore) && Boolean(deps.sessionStorage?.ownerOf)`) — presence of
|
|
10662
|
+
`Boolean(deps.runStore) && Boolean(deps.sessionStorage?.ownerOf)`; server >= 7.135.0 the last conjunct is `headReadOf(deps.sessionStorage) !== undefined`) — presence of
|
|
10517
10663
|
`POST /v1/sessions/{sessionId}/mcp/reconnect`. FACILITY DEPENDENCY, two conjuncts: a durable run
|
|
10518
10664
|
ledger (the verb reaches the live stream through the run row) AND the session-ownership face (the
|
|
10519
10665
|
inbound owner gate is fail-closed; without it the whole door is 501). Both 501s derive from the SAME
|
|
@@ -10634,7 +10780,7 @@ components:
|
|
|
10634
10780
|
sessionBackgroundFacesAvailable(deps), exitFaces: sessionBackgroundFacesAvailable(deps) }`) — presence of the
|
|
10635
10781
|
session background-task doors: `listFace` = `GET /v1/sessions/{sessionId}/background`, `exitFaces` =
|
|
10636
10782
|
`POST /v1/sessions/{sessionId}/background/stop` (contract §16). Both bits use the SAME predicate as the two
|
|
10637
|
-
doors' 501 (the session-ownership face `sessionStorage.ownerOf`), so "says yes but 501s" is structurally
|
|
10783
|
+
doors' 501 (the session-ownership face: `sessionStorage.headOf` on server >= 7.135.0, `ownerOf` on <= 7.134.x), so "says yes but 501s" is structurally
|
|
10638
10784
|
impossible; without it both bits are explicitly `false` and both doors answer 501
|
|
10639
10785
|
`capability.session_ownership_required`. ENDPOINT-GATE FORM: `false` ⇒ do not call. True only promises the
|
|
10640
10786
|
endpoint — not that this replica holds any background row of that session (the registry is in-process).
|
|
@@ -11685,7 +11831,7 @@ components:
|
|
|
11685
11831
|
modelPlane:
|
|
11686
11832
|
allOf: [{ $ref: '#/components/schemas/ModelPlane' }]
|
|
11687
11833
|
description: >-
|
|
11688
|
-
server >= 7.133.0, ALWAYS present there (appended last): which model table this engine SERVES, whether the catalog was adopted, and what the start-up route judge says — read this instead of predicting
|
|
11834
|
+
server >= 7.133.0, ALWAYS present there (appended last on 7.133.0–7.134.x; from server >= 7.135.0 the last key is `aliases` and this one precedes it — key order is not a contract, read by name): which model table this engine SERVES, whether the catalog was adopted, and what the start-up route judge says — read this instead of predicting
|
|
11689
11835
|
(the judge's inputs are the serving process's facts; mirroring two of its judgements drifts). ABSENT = an earlier server (<= 7.132.x). Field reading: ModelPlane.
|
|
11690
11836
|
candidateRejected:
|
|
11691
11837
|
allOf: [{ $ref: '#/components/schemas/CandidateRejected' }]
|
|
@@ -11697,6 +11843,25 @@ components:
|
|
|
11697
11843
|
configuration is clean" (it is also an earlier server): render the real cause only when the key is present; keep the old behaviour when absent.
|
|
11698
11844
|
Same read as `models`: key present => this `models` is the fallback generation (none of the candidate's models are in it). No capability bit
|
|
11699
11845
|
(the endpoint is always there; the presence of the key is the presence rule).
|
|
11846
|
+
aliases:
|
|
11847
|
+
type: array
|
|
11848
|
+
items: { $ref: '#/components/schemas/ModelAlias' }
|
|
11849
|
+
description: >
|
|
11850
|
+
server >= 7.135.0, ALWAYS present there (appended LAST; `[]` when none): the model WORDS besides `models[].name` that the server's acceptance gate takes (tier words / `default` / a catalog entry's id spelling, ...).
|
|
11851
|
+
ACCEPTANCE RULE (one rule; a model-word judge reads this key, never infers from a row's id): a model word is submittable IFF its name is in `models[].name` UNION `aliases[].name` AND its row's `atMentionable !== false`
|
|
11852
|
+
(`atMentionable` absent = no allowlist verdict, not "not mentionable"). `aliases` deliberately does not say which row a word lands on. ABSENT = an earlier server (<= 7.134.x): tier words / `default` stay "cannot tell" —
|
|
11853
|
+
do not read the absence as "no aliases". Known boundary (not introduced by this version): a catalog entry literally named `default` does not appear in `models[]`.
|
|
11854
|
+
|
|
11855
|
+
ModelAlias:
|
|
11856
|
+
type: object
|
|
11857
|
+
additionalProperties: false
|
|
11858
|
+
required: [name]
|
|
11859
|
+
description: >
|
|
11860
|
+
One row of `ModelsResponse.aliases` (server >= 7.135.0): a submittable model word that is not a `models[]` row. `name` = the word (never equal to a `models[].name`); `atMentionable` = the SAME projection as on a `models[]`
|
|
11861
|
+
row, present ONLY when the deployment configured an at-mention allowlist (the allowlist verdict for the catalog entry the word resolves to); absent = no allowlist verdict, NOT "not mentionable".
|
|
11862
|
+
properties:
|
|
11863
|
+
name: { type: string }
|
|
11864
|
+
atMentionable: { type: boolean }
|
|
11700
11865
|
|
|
11701
11866
|
CandidateRejected:
|
|
11702
11867
|
type: object
|
|
@@ -12077,6 +12242,8 @@ components:
|
|
|
12077
12242
|
name: { type: string, description: "The workflow script's declared `meta.name`." }
|
|
12078
12243
|
description: { type: string, description: "The workflow script's declared `meta.description` (one-liner)." }
|
|
12079
12244
|
agentFailures: { type: integer, description: 'Count of agent-runs that ended failed — present only when > 0 (a "completed, with failures" flag without an N+1 get).' }
|
|
12245
|
+
parked: { type: boolean, enum: [true], description: 'server >= 7.135.0 (core 7.55.0 `runParkedOf`) — present, always the literal `true`, ONLY while the run is `running` AND at least one of its agents is parked at an approval gate; otherwise the key is ABSENT (never `false`). Read it as "the run is waiting on a person", not "failed". Older servers never send it.' }
|
|
12246
|
+
errorCode: { type: string, description: 'The run row''s machine code (open set; e.g. `workflow.agent_parked` for a drained parked terminal) — present only when the row has one. (Declared here in 26.1.0: the engine summary has emitted it since before 7.134.0.)' }
|
|
12080
12247
|
currentPhase: { type: string, description: 'Title of the phase currently executing (absent once terminal).' }
|
|
12081
12248
|
status: { $ref: '#/components/schemas/WorkflowRunStatus' }
|
|
12082
12249
|
phaseCount: { type: integer, description: 'Phases recorded.' }
|
|
@@ -12255,6 +12422,8 @@ components:
|
|
|
12255
12422
|
description: { type: string, description: "The workflow script's declared `meta.description` (redacted, one-liner)." }
|
|
12256
12423
|
status: { $ref: '#/components/schemas/WorkflowRunStatus' }
|
|
12257
12424
|
agentFailures: { type: integer, description: 'run-level count of agents whose status ended failed — stamped at run end, only when > 0.' }
|
|
12425
|
+
parked: { type: boolean, enum: [true], description: 'server >= 7.135.0 (core 7.55.0 `runParkedOf`) — present, always the literal `true`, ONLY while the run is `running` AND at least one of its agents is parked at an approval gate; otherwise the key is ABSENT (never `false`). Read it as "the run is waiting on a person", not "failed". Older servers never send it.' }
|
|
12426
|
+
errorCode: { type: string, description: 'The run row''s machine code (open set; the same words as the same-named slot on the fleet row, e.g. `workflow.agent_parked` for a drained parked terminal) — present only when the row has one. (Declared here in 26.1.0: the detail projection has forwarded it since before 7.134.0.)' }
|
|
12258
12427
|
stats: { $ref: '#/components/schemas/WorkflowRunStats' }
|
|
12259
12428
|
startedAt: { type: integer }
|
|
12260
12429
|
endedAt: { type: integer }
|
|
@@ -12727,6 +12896,11 @@ components:
|
|
|
12727
12896
|
run row has one, the key ABSENT otherwise (never an empty string). A parked workflow run reads `status: "failed"` + `errorCode: "workflow.agent_parked"`
|
|
12728
12897
|
(parked, not failed; the `status` vocabulary gains no word). Snapshot rows, `workflow` upsert frames and rows merged from the terminal window share one mint
|
|
12729
12898
|
point; a `?session=` subscriber's demoted rows carry it too. ABSENT = an older server, or no code on this row — fall back to `status`.
|
|
12899
|
+
parked:
|
|
12900
|
+
type: boolean
|
|
12901
|
+
enum: [true]
|
|
12902
|
+
description: >-
|
|
12903
|
+
server >= 7.135.0 (core 7.55.0 `runParkedOf`) — present, always the literal `true`, ONLY while the run is `running` AND at least one of its agents is parked at an approval gate; otherwise the key is ABSENT (never `false`). Read it as "the run is waiting on a person", not "failed". Older servers never send it. On a fleet row the workflow-bus row is now replaced WHOLE on every `workflow` upsert (server >= 7.135.0; no longer merged by `id` into the old row), so a key that left is gone from the row.
|
|
12730
12904
|
FleetFrame:
|
|
12731
12905
|
description: >
|
|
12732
12906
|
One decoded frame off GET /v1/fleet/stream (service streamFleet emit set, src/http/routes/fleet.ts). On the
|
|
@@ -13147,7 +13321,9 @@ components:
|
|
|
13147
13321
|
errorCode?, errorMessage?, retriable?}`, plus `rememberApplied` when the request carried
|
|
13148
13322
|
`remember:"session"` AND the worker has an exemption store;
|
|
13149
13323
|
· the PARKED-BACKGROUND-AGENT shape (`parked-decide.ts`, server >=1.267) — `{taskId, status:"resuming",
|
|
13150
|
-
decision}`, an ACCEPTED (not completed) receipt; the revive drives asynchronously.
|
|
13324
|
+
decision}`, an ACCEPTED (not completed) receipt; the revive drives asynchronously. Since server >= 7.136.0 this
|
|
13325
|
+
shape has a SECOND ARM, the VOIDED receipt `{taskId, status:"failed", decision:"deny"}` — a DENY on a parked row that can
|
|
13326
|
+
never revive (no agent name / no root-session anchor) voids the card; nothing resumes (see `ParkedDecideAccepted`).
|
|
13151
13327
|
A FOURTH shape, the #368 IDEMPOTENT REPLAY (server >= 7.4x; declared 2026-09-08 — it shipped without
|
|
13152
13328
|
ever reaching this schema): `{sessionId, idempotent:true, decision, bindingEnforced:true,
|
|
13153
13329
|
executionOutcome?}` — it carries NO `status` and NO `taskId` (nothing was accepted this time). So no key
|
|
@@ -13208,7 +13384,7 @@ components:
|
|
|
13208
13384
|
description: >
|
|
13209
13385
|
OPEN string — do NOT narrow. Task-level acceptance (server >= 7.37): the literal `resuming` (= accepted,
|
|
13210
13386
|
resume in flight — follow the run stream). Terminal leg: the run's resulting status (`completed`/`failed`/
|
|
13211
|
-
`suspended`/`needs_review`). Parked leg: the literal `resuming` (= accepted, revive in flight).
|
|
13387
|
+
`suspended`/`needs_review`). Parked leg: the literal `resuming` (= accepted, revive in flight) — or, server >= 7.136.0, the literal `failed` on the VOIDED receipt (a deny that closed a card which could never revive; nothing resumes).
|
|
13212
13388
|
decision:
|
|
13213
13389
|
type: string
|
|
13214
13390
|
enum: [approve, deny]
|
|
@@ -13429,7 +13605,14 @@ components:
|
|
|
13429
13605
|
description: 'server >= 7.100.0 (S-700): WHY the park row offers no rule — the same narrow read and closed set (four words from server >= 7.129.0) as the live card frame and `card_json`.'
|
|
13430
13606
|
boundGrantAbsence:
|
|
13431
13607
|
allOf: [{ $ref: '#/components/schemas/BoundGrantAbsence' }]
|
|
13432
|
-
description: 'server >= 7.129.0 (core 7.51.0 #1688; park-row fact eight): why this parked card has no grant-binding digest — the park-row twin seat `PendingAction.tool_approval.boundGrantAbsence`, the same narrow read and the same name / value as the live frame and the inbox row. ABSENT on this face = a skill card (it carries the digest
|
|
13608
|
+
description: 'server >= 7.129.0 (core 7.51.0 #1688; park-row fact eight): why this parked card has no grant-binding digest — the park-row twin seat `PendingAction.tool_approval.boundGrantAbsence`, the same narrow read and the same name / value as the live frame and the inbox row. ABSENT on this face = a skill card (it carries the digest) / a row parked before engine 7.51.0 (says neither — the inbox face projects `unreadable` for the same row) / a word outside the set / an old server — NOT `not_bindable`.'
|
|
13609
|
+
boundGrantDigest: { type: string, description: 'server >= 7.136.0 — a parked `Skill` card''s grant-binding digest; the same value as the inbox row''s and the live frame''s `boundGrantDigest` (one projection feeds this operator queue row, the `/v1/approvals/stream` `pending` frame and the inbox row — byte-equal for the same parked row). Present only on a skill card; absent on an ordinary card. `card_json` does not carry it. Server <= 7.135.x: not on this face.' }
|
|
13610
|
+
boundGrants:
|
|
13611
|
+
allOf: [{ $ref: '#/components/schemas/BoundSkillGrants' }]
|
|
13612
|
+
description: 'server >= 7.136.0 — the value `boundGrantDigest` hashes, published ONLY when it hashes to it (digest only when they disagree; no digest, no list). DEPLOYMENT TEXT (skill names and list entries are written by the deployer; the server neither redacts nor escapes them): render with contextual escaping.'
|
|
13613
|
+
classifierNoRuling:
|
|
13614
|
+
allOf: [{ $ref: '#/components/schemas/AutoModeFallbackCause' }]
|
|
13615
|
+
description: 'server >= 7.136.0 — only on a parked `classifier_no_ruling` card: why the auto-mode classifier did not rule (closed set, echoed only when a member). Same value as the inbox row''s and the live frame''s.'
|
|
13433
13616
|
askClass:
|
|
13434
13617
|
allOf: [{ $ref: '#/components/schemas/AskClass' }]
|
|
13435
13618
|
description: 'server >= 7.109.0 (S-934 ② / core 7.37.0 #1214): the park-row twin seat `PendingAction.tool_approval.askClass`, read through `readAskClassPair` — the SAME narrow read as the live frame and the card. Present together with `classes` (`classes[0] === askClass`); the basis a durable approver answers by. Absent = an old row (parked before core 7.37.0; resume does not backfill) or an unreadable pair — NOT "no class". The inbox row (InboxRow) does not carry it.'
|
|
@@ -13583,7 +13766,7 @@ components:
|
|
|
13583
13766
|
classifierNoRuling:
|
|
13584
13767
|
allOf: [{ $ref: '#/components/schemas/AutoModeFallbackCause' }]
|
|
13585
13768
|
description: 'server >= 7.118.0 — only on a parked `classifier_no_ruling` card: why the auto-mode classifier did not rule.'
|
|
13586
|
-
objective: { type: ['string', 'null'], description: 'task objective, null if unavailable.' }
|
|
13769
|
+
objective: { type: ['string', 'null'], description: 'task objective, null if unavailable. server >= 7.136.0: the run row''s `objectivePreview` (redacted when written, about 120 characters — the same column as `GET /v1/assistant/tasks`; looked up through the gate''s session: its active run, else its latest run; a delegated child''s gate — whose session has no run of its own — falls back to the run that spawned it, via the parked agent row''s `parentTaskId`, hop by hop, at most 8 hops) — null when no preview could be read (a deployment without a run ledger is one cause; a failed read of the row, a delegation chain that breaks or exceeds 8 hops, or a run row without a preview also answer null — the key does not say which). Before 7.136.0 this was the objective ORIGINAL stored in the parked context (not truncated, not redacted); a consumer that used it as the full objective should know that server 7.136.0 has no full-objective read face (`GET /v1/runs/:id` carries neither `objective` nor `objectivePreview`) — this key IS the preview; a full read face comes with a later server version and this package locksteps then (no substitute path is declared here).' }
|
|
13587
13770
|
input:
|
|
13588
13771
|
description: >
|
|
13589
13772
|
REDACTED tool-args preview for display (null on gates without one, e.g. plan_review). Untyped by
|
|
@@ -14001,7 +14184,9 @@ components:
|
|
|
14001
14184
|
non-object is `400 request.body_shape`. `title`: a string renames (1..120 CHARACTERS counted as Unicode characters = the storage column width, no leading /
|
|
14002
14185
|
trailing whitespace, stored verbatim — not rewritten, not redacted); `null` CLEARS it back to the automatic title (the next submit lets the auto-titler fill
|
|
14003
14186
|
it again). `""` is NOT a clear — it is `400 request.body_shape`. A string of the wrong form / a non-string-non-null `title` / a non-boolean `pinned` is
|
|
14004
|
-
`400 request.field_invalid
|
|
14187
|
+
`400 request.field_invalid`; from server >= 7.136.0 a title made only of invisible characters (zero-width, bidi controls, soft hyphen, C1 controls — empty after the cross-session peer directory's own
|
|
14188
|
+
usable-name normalization) is `400 request.field_invalid` too (`title must contain at least one visible character`; the session-sync 2c import's `title` reads the same rule). Such titles written before
|
|
14189
|
+
7.136.0 are not migrated.
|
|
14005
14190
|
additionalProperties: false
|
|
14006
14191
|
minProperties: 1
|
|
14007
14192
|
properties:
|
|
@@ -14148,12 +14333,20 @@ components:
|
|
|
14148
14333
|
server >= 7.92.0 (engine 7.25.0): the session's rule LINEAGE generation. An erase
|
|
14149
14334
|
(`deleteBySession`) ends the lineage — the next write carries gen+1 — so a reader treats a
|
|
14150
14335
|
different gen as a new lineage, never a continuation, regardless of rev. Absent on older servers.
|
|
14336
|
+
operatorRules:
|
|
14337
|
+
allOf: [{ $ref: '#/components/schemas/SessionRulesOperatorPart' }]
|
|
14338
|
+
description: >
|
|
14339
|
+
server >= 7.135.0 (engine 7.55.0): the row's OPERATOR PART — the buckets (and their own `grammar` stamp) the last OPERATOR write set; the line a non-operator write may not loosen (`403 loosen_forbidden` on a move inside it).
|
|
14340
|
+
ABSENT = the whole row is the operator's (an operator write; every row stored before 7.135.0, read as before the upgrade: the owner can take nothing back). Minted by the engine's write judge alone, stored whole and read back verbatim; also on the 2c export `policy[].rules`.
|
|
14341
|
+
A non-operator write over an EMPTY row stamps an empty part (stamp only) — the owner can then take back what the owner added. A part ECHOED back is read per door: on `PUT /v1/sessions/{sessionId}/policy` it is ALWAYS ignored (the stored row's part is kept over an existing row; an empty stamped part is minted over none).
|
|
14342
|
+
On the sync-import replay (`POST …/sync/import`, `policy[]` records, which carry `rev`): over an existing row the judge keeps the STORED row's part and ignores the echo; over NO row, a non-operator record that looks like a stored row (carries `rev` >= 1)
|
|
14343
|
+
has its own part adopted (from then on that part IS the row's operator line: taking it back answers 403 `loosen_forbidden`), otherwise an empty stamped part is minted; an operator write never carries a part.
|
|
14151
14344
|
grammar:
|
|
14152
14345
|
type: integer
|
|
14153
14346
|
minimum: 0
|
|
14154
14347
|
description: >
|
|
14155
14348
|
server >= 7.129.0 (engine 7.51.2): the rule GRAMMAR the row's entries are read in, stamped by the
|
|
14156
|
-
engine's write judge on every row written through it (
|
|
14349
|
+
engine's write judge on every row written through it (server >= 7.135.0 writes `4` — the engine's `SESSION_RULES_GRAMMAR`; 7.129.0 wrote `1`).
|
|
14157
14350
|
Absent = a row stored before the stamp (grammar 0: an allow entry spelled as a rule, `Bash(rm:*)`,
|
|
14158
14351
|
named no tool and admitted nothing — the engine keeps reading such a row that way and announces it
|
|
14159
14352
|
once; the one-time migration rewrites stored rows and stamps them). Echoing a stored body back into
|
|
@@ -14174,6 +14367,18 @@ components:
|
|
|
14174
14367
|
rev: { type: integer }
|
|
14175
14368
|
gen: { type: integer }
|
|
14176
14369
|
grammar: { type: integer }
|
|
14370
|
+
operatorRules: { $ref: '#/components/schemas/SessionRulesOperatorPart' }
|
|
14371
|
+
|
|
14372
|
+
SessionRulesOperatorPart:
|
|
14373
|
+
type: object
|
|
14374
|
+
description: '`StoredSessionRules.operatorRules` (server >= 7.135.0): the three buckets plus their own grammar stamp. The `grammar` is always present (the write judge stamps it).'
|
|
14375
|
+
additionalProperties: false
|
|
14376
|
+
required: [grammar]
|
|
14377
|
+
properties:
|
|
14378
|
+
toolAllow: { type: array, items: { type: string } }
|
|
14379
|
+
toolDeny: { type: array, items: { type: string } }
|
|
14380
|
+
allowDirs: { type: array, items: { type: string } }
|
|
14381
|
+
grammar: { type: integer, minimum: 0 }
|
|
14177
14382
|
|
|
14178
14383
|
McpServerStatus:
|
|
14179
14384
|
type: object
|
|
@@ -14816,7 +15021,18 @@ components:
|
|
|
14816
15021
|
fail-closed) and `state.scenario_assignment_unknown` (503, server >= 7.119.0 — the center's scenario assignment for the
|
|
14817
15022
|
principal is dangling; only re-pointing the assignment, or adding the scenario back to the deployment, helps) and
|
|
14818
15023
|
`approvals.read_corrupt` (500, server >= 7.134.0 on `GET /v1/approvals` — a queue row's stored body cannot be read; an operator has to repair or
|
|
14819
|
-
delete the row
|
|
15024
|
+
delete the row; server >= 7.135.0 the same judge answers `GET /v1/assistant/inbox` and `GET /v1/assistant/tasks` too) and `workflow.journal_incompatible`
|
|
15025
|
+
(500, server >= 7.135.0 on `GET /v1/workflows/{id}/journal` — a journal row the engine's judge rejects; the body carries `ordinal`; repair the row from the retained copy, never by deleting it).
|
|
15026
|
+
Every other 5xx code keeps the status-based retry.
|
|
15027
|
+
🔴 server >= 7.135.0 read-failure and store-fault codes (all additive; branch on the code, never the sentence): `503 approvals.read_unavailable` on `GET /v1/approvals`, `/v1/assistant/inbox` and
|
|
15028
|
+
`/v1/assistant/tasks` (the queue cannot be read RIGHT NOW — transient, retried by status; until a read succeeds an answer does NOT mean nothing is pending; it moved from the SSE-only table into the status-bearing catalog, status `-` → 503) and, on
|
|
15029
|
+
the same three faces, `500 approvals.read_corrupt` (above); `503 state.file_history_unreadable` on the session-sync pull faces (`GET /v1/sessions/{id}/sync/manifest`, `GET /v1/sessions/{id}/sync/history/blobs/{hash}` — the file history
|
|
15030
|
+
cannot be read WHOLE; it is NOT "no history", which stays `200` with `fileHistory: null`); `422 adopt_failed` on `POST /v1/sessions/{id}/sync/import` (the file-history replay hit a store fault; 7.134.x answered `unsupported_format`;
|
|
15031
|
+
NOT a missing blob — that is `422 missing_blob`, now answered in the FIRST phase). The two store-fault codes may carry `permanence` (`transient` = nothing changed, retry the same shape later / `terminal` = repair the store first; absent = the store did not judge).
|
|
15032
|
+
`422 request.unprocessable` now also answers a deny / ask rule whose PARAMETER does not belong to the tool (the sentence carries the engine code `unsupported.param_unknown`, the same word in `detail.problems[].reason`; a stored body that
|
|
15033
|
+
resumes ⇒ `409 resume_blocked_by_policy` with `blockedBy: request.unprocessable`; 7.134.x accepted such a rule, and it never matched). `400 request.body_shape` also names an unread key inside a `settings.hooks` group / entry in
|
|
15034
|
+
`unknownKeys` as a FULL coordinate (`settings.hooks.PreToolUse.0.hooks.0.onFailure`) on a fresh submit.
|
|
15035
|
+
`409 resume_outcome_invalid` + `field: "feedback"` (`retriable: true`) now answers a release `feedback` that carries an engine `<system-reminder>` tag (refused before the CAS, the card stays pending; fix or drop the words and decide again — it was `409 approval_binding_mismatch` without `field` on 7.134.x). A `feedback` on a deny / policy decision stays `400 request.field_conflict` (`detail.kind: approval_feedback`).
|
|
14820
15036
|
🔴 `request.host_posture_refused` (422) has TWO triggers (same code, same status — "you wrote it right, this
|
|
14821
15037
|
deployment will not grant that host posture"): (1) the write-containment face (`permissionMode: bypassPermissions` ⇒
|
|
14822
15038
|
`writeFace: open`; read `capabilities.taskWriteFaceOpen` first); (2) server >= 7.106.0 / S-895: `inheritEnv: "all"` on a
|
|
@@ -14880,10 +15096,23 @@ components:
|
|
|
14880
15096
|
the ids of the background children rooted at this session that are still alive (count = length) — the SAME
|
|
14881
15097
|
strings as the `handle` on `GET /v1/agents/roster` rows. Nothing was deleted; wait for them to finish (or stop
|
|
14882
15098
|
them where they run) and retry the delete verbatim. SDK: `err.extra.remaining` on the ConflictError.
|
|
15099
|
+
permanence:
|
|
15100
|
+
type: string
|
|
15101
|
+
enum: [transient, terminal]
|
|
15102
|
+
description: >-
|
|
15103
|
+
server >= 7.135.0, on `503 state.file_history_unreadable` and the file-history store's fault answers (`422 adopt_failed`; server >= 7.136.0 also `restore_failed` and the like, and the session-sync pull legs' database-disconnect `503`, where `transient` is judged for connection-class faults): the file-history store's own judgment of the fault (the engine's `GovernanceRetryClass`) —
|
|
15104
|
+
`transient` = nothing was changed, retrying the same shape later may succeed; `terminal` = repair the store first. ABSENT = the store did not judge; not terminal — retried by status like any retryable 5xx (the SDK does so automatically on the pull legs, up to `maxRetries`); still red ⇒ look at the store. SDK: `err.extra.permanence`.
|
|
15105
|
+
ordinal:
|
|
15106
|
+
type: integer
|
|
15107
|
+
description: >-
|
|
15108
|
+
server >= 7.135.0, on `500 workflow.journal_incompatible`: the journal ordinal of the FIRST bad row (ascending); `-1` = the refusal names no entry. SDK: `err.extra.ordinal`.
|
|
14883
15109
|
reason:
|
|
14884
15110
|
type: string
|
|
14885
15111
|
description: >-
|
|
14886
|
-
A per-code closed word — read it by `errorCode`, never across codes. On
|
|
15112
|
+
A per-code closed word — read it by `errorCode`, never across codes. On 400 `request.field_invalid` for a URL that carries a credential (server >= 7.135.0): `url_userinfo` (`user:pass@host`) / `url_credential_param` (a credential-named
|
|
15113
|
+
query / fragment parameter — the names the service's log redactor treats as credentials), beside `field` = the body coordinate (`mcpServers[i].transport.url`, `a2aPeers[i].url`, `a2aPeers[i].cardUrl`,
|
|
15114
|
+
`settings.hooks.<event>[g].hooks[h].url` — the FULL coordinate, not `field: "settings.hooks"` + `detail` — and `settings.webSearch.endpoint`; a `settings.webSearch.endpoint` with userinfo keeps its sentence and gains `field` / `reason`);
|
|
15115
|
+
`a2aPeers` over 32 entries answers `over_cap` + `count` + `cap` on `field: "a2aPeers"`. Server >= 7.136.0: the same URL-credential words on a SIXTH seat, `images[i].url` (`field` = `images[i].url`, an `images` `{ url }` arm — fresh submits only); `mcpServers` over 32 entries answers `over_cap` + `count` + `cap` on `field: "mcpServers"` (the same body as `a2aPeers`; the probe door `POST /v1/capabilities/mcp/probe` answers the same sentence and keys — before 7.136.0 a sentence without machine keys); a malformed `a2aPeers` list / entry / key value carries NO `reason` (sentence only), a key outside the peer vocabulary is `request.body_shape` + `unknownKeys`. On 503 `fleet.lease_unavailable` (server >=
|
|
14887
15116
|
7.106.0 / S-866 ③): `auth-rejected` (the center refused this engine's credential, or the credential file is
|
|
14888
15117
|
unreadable) / `unreachable` (unreachable / 5xx / timeout / bad body / any status other than 200 / 409 / 400 / 401 / 403 —
|
|
14889
15118
|
center 404 / 429 / 3xx included). On 400 `request.field_invalid` for a `settings.permissions` bucket (server >= 7.106.0 /
|
|
@@ -14921,6 +15150,10 @@ components:
|
|
|
14921
15150
|
`[i]`, record members `.key`: `mcpServers[0].transport.headers.Authorization`, `settings.hooks.PreToolUse[0].hooks[0].headers.Authorization`; the key
|
|
14922
15151
|
name is not a secret, the value never enters the refusal); on 400 `request.field_invalid` for the request key `settings.approvalFrameFamilies` it is
|
|
14923
15152
|
that literal (with `reason: "bad_entry"` and the bad `index`; no `index` for a non-array).
|
|
15153
|
+
server >= 7.135.0: on 409 `conflict.checkpoint_ctx_unsealable` with `reason: "unrecognized_seal"` the arm of the stored credential-slot GENERATION newer than this server's (or not a positive integer) reads `field: "credentialSlotGeneration"` — not an in-body coordinate.
|
|
15154
|
+
server >= 7.136.0: the credential-slot set gains four seats (generation 3) — `mcpServers[i].transport.command` / `mcpServers[i].transport.args` (stdio transport) and `settings.hooks.<event>[g].hooks[h].command` / `.args` (command hook); `args` is sealed as ONE value (the whole array); on 409 `conflict.checkpoint_ctx_unsealable` `field` names that coordinate (which doors can answer which `reason`, and how the refusal arrives, is written once — in the SDK documentation of `CHECKPOINT_CTX_UNSEALABLE_REASONS` — not repeated here).
|
|
15155
|
+
server >= 7.136.0: on 400 `request.field_invalid` for a URL that carries a credential, `field` also names `images[i].url` (the sixth seat); on `mcpServers` over 32 entries `field` is `mcpServers` (beside `reason: "over_cap"` / `count` / `cap`); a key outside the `a2aPeers` entry vocabulary is `400 request.body_shape` whose `unknownKeys` carry the full coordinates (`a2aPeers[0].allowSkill`).
|
|
15156
|
+
server >= 7.135.0: on `a2aPeers` over 32 entries `field` is `a2aPeers` (beside `reason: "over_cap"` / `count` / `cap`).
|
|
14924
15157
|
detail:
|
|
14925
15158
|
description: >
|
|
14926
15159
|
🔴 SHAPES differ by code — branch on `field` (or the `errorCode`), never guess from the type of `detail`. On 503
|
|
@@ -15699,6 +15932,12 @@ components:
|
|
|
15699
15932
|
K-32 (server >= 7.106.0 / core 7.34.0 design/1111) — `bypassPermissions` RELEASED an ask nobody answered (see
|
|
15700
15933
|
`ModeRelease`). Absent = this allow was not a mode release (a plain allow / a person's yes / a rule), or an older
|
|
15701
15934
|
server (<= 7.105.0 stripped it).
|
|
15935
|
+
clearedBy:
|
|
15936
|
+
allOf: [{ $ref: '#/components/schemas/AllowRuleClearance' }]
|
|
15937
|
+
description: >
|
|
15938
|
+
server >= 7.135.0 (core 7.55.0) — the allow layer's account of a call it let run WITHOUT asking: which member's allow rule cleared a standing ask that nobody answered
|
|
15939
|
+
(`AllowRuleClearance`). Present exactly when an allow member cleared the ask; absent on a call nothing asked about, a mode's release or acceptance, the read-only arm's,
|
|
15940
|
+
the classifier's or the sandbox's allow, and a person's yes. Never present together with `released`. Older servers stripped it.
|
|
15702
15941
|
- type: object
|
|
15703
15942
|
additionalProperties: false
|
|
15704
15943
|
required: [kind, deniedBy]
|
|
@@ -16156,6 +16395,10 @@ components:
|
|
|
16156
16395
|
`MCP_FAILURE_CODES` spellings — including `network` and the `http_<status>` encoding — are gone,
|
|
16157
16396
|
and an HTTP status now rides the structured `httpStatus` seat on `wiring_manifest.mcp[]` instead of
|
|
16158
16397
|
being baked into the code. The set as a WHOLE stays open (a tool owns its own codes).
|
|
16398
|
+
🔴 core 7.55.0 / server >= 7.135.0 — two MCP words minted BEFORE the call is sent (`delivered: "no"`; the server has no mint point, they pass through verbatim): after the engine redials a Streamable HTTP
|
|
16399
|
+
server that LOST its session, `mcp.tool_declaration_changed` (the server now declares the tool differently — safety axis / read-only reading / the "a person must answer" mark / task support — or no longer lists it) and
|
|
16400
|
+
`mcp.tool_listing_unreached` (the post-redial listing walk stopped before reaching the tool, so its new declaration cannot be proved). Every later call to that tool is refused the same way until a listing of the connection
|
|
16401
|
+
reaches it — the way out is `POST /v1/sessions/{id}/mcp/reconnect` (or the engine's refresh); do not resend as-is. The lost-session failure itself stays `http_status` + `httpStatus: 404` + `delivered: "unknown"`.
|
|
16159
16402
|
Consumers MUST branch with a `default` arm and MUST NOT exhaustively switch on known values.
|
|
16160
16403
|
The service enforces only a length bound (>128 chars = malformed, the whole key is DROPPED rather
|
|
16161
16404
|
than truncated — truncating would mint a code core never sent). NOTE: this is a DIFFERENT
|
|
@@ -16505,6 +16748,21 @@ components:
|
|
|
16505
16748
|
type: object
|
|
16506
16749
|
additionalProperties: false
|
|
16507
16750
|
properties: { kind: { type: string, description: 'root | child | resume. Open on read.' } }
|
|
16751
|
+
sessionRules:
|
|
16752
|
+
type: object
|
|
16753
|
+
additionalProperties: false
|
|
16754
|
+
required: [childrenReadLive]
|
|
16755
|
+
description: >
|
|
16756
|
+
server >= 7.135.0 (engine 7.55.0; effective half only, both faces): whether the session-rules layer is handed to the delegated legs. `childrenReadLive: true` = this leg wired the session-rules layer (the deployment has a session-rules
|
|
16757
|
+
store and the task carries a session id) and handed the session's key to every leg it delegates (sync / background / fork / workflow / resume / observer side-car, any depth) — a rule written into the session NOW governs an
|
|
16758
|
+
already-running child's NEXT call; `false` = no rules layer, nothing handed out. The section ABSENT = an older engine (say nothing; do not read it as `false`). An unreadable section (not `{ childrenReadLive: <boolean> }`) is dropped.
|
|
16759
|
+
properties:
|
|
16760
|
+
childrenReadLive: { type: boolean }
|
|
16761
|
+
projectMemory:
|
|
16762
|
+
type: string
|
|
16763
|
+
description: >
|
|
16764
|
+
server >= 7.135.0 (engine 7.55.0; effective half only, both faces): did this leg call the deployment's project-context seat — `on` = it did; `disabled` = the seat is wired but the request's `projectMemory: "disabled"` turned it off;
|
|
16765
|
+
`absent` = the deployment wired no seat (whatever the request said). On `disabled` / `absent` legs the server-minted `instructions` section is ABSENT. Open on read (a new engine word passes through); ABSENT = an older engine.
|
|
16508
16766
|
ask:
|
|
16509
16767
|
type: object
|
|
16510
16768
|
additionalProperties: false
|
|
@@ -17096,6 +17354,10 @@ components:
|
|
|
17096
17354
|
own failure carries the same code. `{ modelId, boundOrigin, requestOrigin, sessionId, runId }` — both origins in display spelling (scheme + host +
|
|
17097
17355
|
port, no userinfo / path), never a credential or a digest of one. Once per run per (modelId, boundOrigin, requestOrigin). It replaces the retired
|
|
17098
17356
|
operator code `route.base_url_changed_key_unchanged` (never on this whitelist). `config.credential_not_withheld` is operator-audience — ops log only.
|
|
17357
|
+
`advisor.not_attached` (server >= 7.135.0 / core 7.55.0; D.3 is now 42 codes) — the request's advisor model did NOT attach (the engine's pairing judge refuses the (advisor, main) pair).
|
|
17358
|
+
`{ advisorModel, mainModel, reason, sessionId, runId? }` — the two model names are the catalog id / the reference the request wrote (display spelling); `reason` is an engine word (`unknown_model` / `advisor_unranked` /
|
|
17359
|
+
`weakest_tier` / `main_unranked` / `pairing` / `hold_unknown`; the server echoes it — read OPEN). Unreachable on this server today: it does not accept `advisorModel` (the request body does not take it, and the
|
|
17360
|
+
`advisor` section is not projected on either `wiring_manifest` face).
|
|
17099
17361
|
Value change: `permission.rule_row_dropped`'s `detail.rows[].rule` is, since core 7.53.0, the rule's original text (the same reading as
|
|
17100
17362
|
`allowed_tool_not_granted`'s `entries[].entry`: at most 1 024 code points, longer cut to 1 024 + a truncation mark, CONTROL CHARACTERS RIDE AS DATA —
|
|
17101
17363
|
neutralize at render); before it was the engine-neutralized single-line form (at most 201 code points). Same keys.
|
|
@@ -17875,7 +18137,7 @@ components:
|
|
|
17875
18137
|
second card word `contentKind` that server <= 7.125.x derived from the tool name (deleted at 7.126.0, no alias: a consumer reading `contentKind === "content_ask"` reads
|
|
17876
18138
|
`approvalCard === "question"`). ABSENT = the engine minted none (a host-built ask / an older engine / a non-approval gate) — never `generic` by default. Display / triage only; it NEVER
|
|
17877
18139
|
takes part in resume / gate / CAS. The same word rides the `livePending` row top level (= this frame's own value), the operator queue row and the `/v1/approvals/stream` `pending` /
|
|
17878
|
-
`live_pending` frames; the `card_json` card face and the `approval_request` frame's `card`
|
|
18140
|
+
`live_pending` frames; from server >= 7.136.0 the `card_json` card face and the `approval_request` frame's `card` (live mint and reconnect replay alike) carry the same word too (`ApprovalCard.approvalCard`: one read, three faces — before 7.136.0 the card did not carry it, so a replayed frame had none and a reconnecting shell fell back to the generic card).
|
|
17879
18141
|
inputHasBidi:
|
|
17880
18142
|
type: boolean
|
|
17881
18143
|
enum: [true]
|
|
@@ -18154,6 +18416,9 @@ components:
|
|
|
18154
18416
|
argsOmitted: { type: boolean, enum: [true], description: 'Present (true) only when args exceeded the byte cap. Never false.' }
|
|
18155
18417
|
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.' }
|
|
18156
18418
|
risk: { $ref: '#/components/schemas/ApprovalRiskAxes' }
|
|
18419
|
+
approvalCard:
|
|
18420
|
+
allOf: [{ $ref: '#/components/schemas/ToolApprovalCardWord' }]
|
|
18421
|
+
description: 'server >= 7.136.0, ADDITIVE: the engine-minted card word — the SAME word, read once, as the live frame''s top-level `ToolApprovalFrame.approvalCard`; it now rides the live-minted `approval_request` frame''s `card`, the stored `card_json` envelope and the reconnect-replay frame''s `card` (before 7.136.0 the card did not carry it, so a replayed frame had none). ABSENT = the engine minted none / an out-of-set word (the server narrows it again when it mints the card) / a card stored before 7.136.0 — never `generic` by default. Display / triage only; it NEVER takes part in resume / gate / CAS. The stored envelope is strict: a 7.135.x replica cannot read a row carrying this key (replay skips it, the idempotent re-entry goes to the durable park) — roll the fleet in one pass.'
|
|
18157
18422
|
rememberRefused:
|
|
18158
18423
|
type: boolean
|
|
18159
18424
|
enum: [true]
|
|
@@ -18300,6 +18565,27 @@ components:
|
|
|
18300
18565
|
The closed five-word vocabulary of `AllowRuleShadow.member` (server >= 7.117.0 / core 7.42.0 `ALLOW_RULE_MEMBERS`, verbatim and in the order the engine reads the members). The SDK exports
|
|
18301
18566
|
it at runtime as `ALLOW_RULE_MEMBERS`. Owner = core; read it as an open string with a default arm (core may add a member and the server follows).
|
|
18302
18567
|
|
|
18568
|
+
AllowRuleClearance:
|
|
18569
|
+
type: object
|
|
18570
|
+
additionalProperties: false
|
|
18571
|
+
required: [member, entries]
|
|
18572
|
+
description: >
|
|
18573
|
+
`tool_end.gate.disposition.clearedBy` (server >= 7.135.0 / core 7.55.0 `AllowRuleClearance`): the allow-layer member whose rule CLEARED a standing ask (the pair of `AllowRuleShadow`, which is
|
|
18574
|
+
"matched and could NOT clear"). Same `member` / `entries` / `omitted` shape (minted and capped by the same seat), plus `positions` for a LIST member (`request`, `deployment`): the index of every element of the
|
|
18575
|
+
list the run received that is one of those entries (a string listed twice has both indices), so a host reads which line of its own declaration spoke even where the shown text is capped.
|
|
18576
|
+
properties:
|
|
18577
|
+
member: { $ref: '#/components/schemas/AllowRuleMember' }
|
|
18578
|
+
entries:
|
|
18579
|
+
type: array
|
|
18580
|
+
maxItems: 32
|
|
18581
|
+
items: { type: string, maxLength: 512 }
|
|
18582
|
+
description: 'The entries that member stood on (UNTRUSTED for display, secret-redacted, <= 512 chars each, <= 32 listed).'
|
|
18583
|
+
omitted: { type: integer, minimum: 1, description: 'How many entries were not listed (beyond the cap). Absent = none omitted.' }
|
|
18584
|
+
positions:
|
|
18585
|
+
type: array
|
|
18586
|
+
items: { type: integer, minimum: 0 }
|
|
18587
|
+
description: 'LIST members only: the indices, in the list this run received, of the elements that are those entries. Absent for a non-list member.'
|
|
18588
|
+
|
|
18303
18589
|
AllowRuleShadow:
|
|
18304
18590
|
type: object
|
|
18305
18591
|
additionalProperties: false
|
|
@@ -18431,7 +18717,7 @@ components:
|
|
|
18431
18717
|
equality). ONE vocabulary for two faces: a card's rule offer (`RuleOffer.match`, the
|
|
18432
18718
|
server's card schema validates it with this very enum) and a persisted rule row (`GET /v1/rules`).
|
|
18433
18719
|
|
|
18434
|
-
`exact` = this one command only (`Bash(git status)`). `prefix` = the historical colon-star
|
|
18720
|
+
`exact` = this one command only (`Bash(git status)`). `pattern` (server >= 7.135.0 / core 7.55.0) = the MID-STAR command form (`Bash(git * main)`) — the fourth Bash command form a card edit may persist; the persisted `command` is the written pattern itself. `prefix` = the historical colon-star
|
|
18435
18721
|
word-boundary prefix (`Bash(git status:*)`) and the ONLY spelling for a compound prefix form; it stays
|
|
18436
18722
|
a permanent compatibility read. `wildcard` = the trailing space-star form (`Bash(npm run *)`), the
|
|
18437
18723
|
same predicate as `prefix` on a single command body. `subpath` = the `Read(//abs-dir/**)` directory form,
|
|
@@ -18445,11 +18731,11 @@ components:
|
|
|
18445
18731
|
always refuses these two words (no network grant is minted through a card). A replica rolled back to 7.125.x reads such a
|
|
18446
18732
|
row as a damaged row.
|
|
18447
18733
|
|
|
18448
|
-
🔴
|
|
18734
|
+
🔴 TEN MEMBERS, closed (server >= 7.135.0 / core 7.55.0 added `pattern`, between `wildcard` and `subpath` — the engine's order): the server validates the member on both faces. A consumer type narrower than the
|
|
18449
18735
|
mint point is a lie — it lets a `switch` claim exhaustiveness the wire does not honour (SDK <= 16 declared
|
|
18450
18736
|
four here, so a `path` offer and every 7.118.0 skill-card offer were dropped as malformed; SDK <= 21 declared
|
|
18451
18737
|
seven, so every domain grant row on `GET /v1/rules` was dropped the same way).
|
|
18452
|
-
enum: [exact, prefix, wildcard, subpath, path, name, name_prefix, host, subdomain]
|
|
18738
|
+
enum: [exact, prefix, wildcard, pattern, subpath, path, name, name_prefix, host, subdomain]
|
|
18453
18739
|
|
|
18454
18740
|
RuleOfferUncoveredReason:
|
|
18455
18741
|
type: string
|
|
@@ -19785,6 +20071,12 @@ components:
|
|
|
19785
20071
|
runId: { type: string }
|
|
19786
20072
|
status: { type: string }
|
|
19787
20073
|
summary: { type: string }
|
|
20074
|
+
completionId:
|
|
20075
|
+
type: string
|
|
20076
|
+
description: >
|
|
20077
|
+
server >= 7.135.0 — the idempotency anchor of this workflow completion: the SAME id rides every notification path of one completion (this frame / `task_notification` / fleet `bg_notification` / inbox replay) and
|
|
20078
|
+
is the dedup key ACROSS paths (the same value domain as `task_notification.completionId`). ABSENT when the engine gave none (an orphan the service terminated itself) — dedup on `runId` as before. The read faces
|
|
20079
|
+
(`GET /v1/workflows/{id}` etc.) deliberately never carry it. Older servers' re-delivered frames have no such key.
|
|
19788
20080
|
|
|
19789
20081
|
# ── 🔴 #185a (2026-08-08): the DURABLE leg's three APPROVAL arms ────────────────────────────────
|
|
19790
20082
|
# Shape rule for all three: `allOf: [<frame schema>, {the narrowed discriminant}]`. The keys are NOT
|
|
@@ -19960,6 +20252,13 @@ components:
|
|
|
19960
20252
|
boundGrantAbsence:
|
|
19961
20253
|
allOf: [{ $ref: '#/components/schemas/BoundGrantAbsence' }]
|
|
19962
20254
|
description: '`pending` frames only (server >= 7.129.0 / core 7.51.0 #1688) — see PendingCheckpoint.boundGrantAbsence. A `live_pending` frame carries it only inside its `frame`.'
|
|
20255
|
+
boundGrantDigest: { type: string, description: '`pending` frames only (server >= 7.136.0) — see PendingCheckpoint.boundGrantDigest. A `live_pending` frame carries it only inside its `frame`.' }
|
|
20256
|
+
boundGrants:
|
|
20257
|
+
allOf: [{ $ref: '#/components/schemas/BoundSkillGrants' }]
|
|
20258
|
+
description: '`pending` frames only (server >= 7.136.0) — see PendingCheckpoint.boundGrants. DEPLOYMENT TEXT: render with contextual escaping.'
|
|
20259
|
+
classifierNoRuling:
|
|
20260
|
+
allOf: [{ $ref: '#/components/schemas/AutoModeFallbackCause' }]
|
|
20261
|
+
description: '`pending` frames only (server >= 7.136.0) — see PendingCheckpoint.classifierNoRuling.'
|
|
19963
20262
|
askClass:
|
|
19964
20263
|
allOf: [{ $ref: '#/components/schemas/AskClass' }]
|
|
19965
20264
|
description: '`pending` frames only (server >= 7.109.0 / S-934 ②) — see PendingCheckpoint.askClass. A `live_pending` frame carries the pair only inside its `frame`.'
|
|
@@ -19970,20 +20269,35 @@ components:
|
|
|
19970
20269
|
description: '`pending` frames only (server >= 7.109.0) — see PendingCheckpoint.classes.'
|
|
19971
20270
|
|
|
19972
20271
|
ParkedDecideAccepted:
|
|
19973
|
-
type: object
|
|
19974
20272
|
description: >
|
|
19975
20273
|
The 200 body of POST /v1/approvals/{sessionId}/decide when the pending checkpoint belongs to a
|
|
19976
20274
|
PARKED background agent (server 1.267, ASSISTANT-WIRE-CONTRACT §4a parked variant; server
|
|
19977
|
-
parked-decide.ts — exact literal
|
|
19978
|
-
|
|
19979
|
-
|
|
19980
|
-
|
|
19981
|
-
|
|
19982
|
-
|
|
19983
|
-
|
|
19984
|
-
|
|
19985
|
-
|
|
19986
|
-
|
|
20275
|
+
parked-decide.ts — exact literal shapes). TWO ARMS, read by `status` (the SDK type `ParkedDecideAccepted` is their union):
|
|
20276
|
+
(1) `status: "resuming"` — the ACCEPTANCE receipt. The revive drives ASYNCHRONOUSLY — 200 means accepted,
|
|
20277
|
+
not completed; a failed drive honestly re-parks the row and the pending re-appears on the list.
|
|
20278
|
+
(2) `status: "failed"` (server >= 7.136.0; `decision` is always `deny`) — the VOIDED receipt: on the two forms that can
|
|
20279
|
+
never revive (a parked child whose row carries no agent name — an unnamed `Agent` call — or no root-session anchor)
|
|
20280
|
+
a DENY voids the card under its own scope CAS; the card leaves the pending queue and the `/v1/approvals/stream` snapshot,
|
|
20281
|
+
the child ends `failed` (the engine's reconcile), the gated tool never runs, no `remember` is granted — and NOTHING is
|
|
20282
|
+
resuming. Do not wait for a revive that never comes. APPROVE on those forms stays `409 decide.row_unrevivable`; a lost
|
|
20283
|
+
void CAS is the existing `409 decide.gate_moved`.
|
|
20284
|
+
Task-level suspends answer their own shapes (see `ApprovalDecisionResult`): discriminate a parked receipt by `decision`
|
|
20285
|
+
present and `sessionId` absent, then read `status`.
|
|
20286
|
+
oneOf:
|
|
20287
|
+
- type: object
|
|
20288
|
+
required: [taskId, status, decision]
|
|
20289
|
+
additionalProperties: true
|
|
20290
|
+
properties:
|
|
20291
|
+
taskId: { type: string, description: 'The background agent handle (a* domain).' }
|
|
20292
|
+
status: { type: string, enum: [resuming] }
|
|
20293
|
+
decision: { type: string, enum: [approve, deny] }
|
|
20294
|
+
- type: object
|
|
20295
|
+
required: [taskId, status, decision]
|
|
20296
|
+
additionalProperties: true
|
|
20297
|
+
properties:
|
|
20298
|
+
taskId: { type: string, description: 'The background agent handle (a* domain).' }
|
|
20299
|
+
status: { type: string, enum: [failed] }
|
|
20300
|
+
decision: { type: string, enum: [deny] }
|
|
19987
20301
|
|
|
19988
20302
|
FleetMeta:
|
|
19989
20303
|
type: object
|
|
@@ -20484,7 +20798,7 @@ components:
|
|
|
20484
20798
|
🔴 ONE RULE FOR EVERY "EFFECTIVE HALF ONLY" KEY (sdk 9.7.0, after a codex adversarial-review [high]):
|
|
20485
20799
|
this schema's only consumer today is `GET /v1/diagnostics/wiring`'s `static` half, and every key marked
|
|
20486
20800
|
"effective half only" (`leg`, `ask.effective`, `configFingerprint`, `tools`, `mods`, `lsp`,
|
|
20487
|
-
`modelGate`, `autoMode`, `writeProtection`, `readDeny`, `autoConsolidation`, `fileHistory`, `instructions`) is ALWAYS ABSENT on that
|
|
20801
|
+
`modelGate`, `autoMode`, `writeProtection`, `readDeny`, `autoConsolidation`, `fileHistory`, `instructions`, `sessionRules`, `projectMemory`) is ALWAYS ABSENT on that
|
|
20488
20802
|
wire ⇒ THEIR ABSENCE HERE CARRIES NO INFORMATION. The per-key absence readings ("absent = not armed",
|
|
20489
20803
|
"absent = a third state", …) hold for the LIVE FRAME (`Event_wiring_manifest`) and must not be carried
|
|
20490
20804
|
over to this response. For the facts behind those keys: a tenant reads
|
|
@@ -20497,7 +20811,7 @@ components:
|
|
|
20497
20811
|
are EFFECTIVE-half only (the live `wiring_manifest` event) — as are the four per-leg sections
|
|
20498
20812
|
`modelGate`, `autoMode`, `mcp` and `tools`, which describe what THIS leg did and have no static
|
|
20499
20813
|
counterpart — and the STATIC half
|
|
20500
|
-
(GET /v1/diagnostics/wiring) NEVER mints them; every other section, plus `governance`, is always
|
|
20814
|
+
(GET /v1/diagnostics/wiring) NEVER mints them; every other section NOT in the effective-half-only list above, plus `governance`, is always
|
|
20501
20815
|
present on the static half. Fields stay optional because core may add or drop sections and that
|
|
20502
20816
|
must not hard-break a client — read by half, and never wait on a key the half never sends.
|
|
20503
20817
|
🔴 EVERY section is declared HERE, each saying which half mints it (sdk 8.9.0). Before that, `tools`
|
|
@@ -20518,6 +20832,18 @@ components:
|
|
|
20518
20832
|
description: 'Which leg emitted it (effective half only; the static half has no leg identity).'
|
|
20519
20833
|
properties:
|
|
20520
20834
|
kind: { type: string, enum: [root, child, resume] }
|
|
20835
|
+
sessionRules:
|
|
20836
|
+
type: object
|
|
20837
|
+
required: [childrenReadLive]
|
|
20838
|
+
description: >
|
|
20839
|
+
server >= 7.135.0 (engine 7.55.0; effective half only — the static half never mints it): whether the session-rules layer is handed to the delegated legs. Same reading as on the live frame (`Event_wiring_manifest.sessionRules`):
|
|
20840
|
+
`childrenReadLive: true` = a rule written into the session NOW governs an already-running child's NEXT call; `false` = no rules layer; the section ABSENT = an older engine, or this half.
|
|
20841
|
+
properties:
|
|
20842
|
+
childrenReadLive: { type: boolean }
|
|
20843
|
+
projectMemory:
|
|
20844
|
+
type: string
|
|
20845
|
+
description: >
|
|
20846
|
+
server >= 7.135.0 (engine 7.55.0; effective half only): did the leg call the deployment's project-context seat — `on` / `disabled` (the request's `projectMemory: "disabled"`) / `absent` (no seat wired). Open on read; ABSENT = an older engine, or this half.
|
|
20521
20847
|
ask:
|
|
20522
20848
|
type: object
|
|
20523
20849
|
description: 'Approval seam: wired form, which seat it came from, and (effective half) what it adjudicates to.'
|
|
@@ -21285,6 +21611,19 @@ components:
|
|
|
21285
21611
|
usageMissing: { type: boolean, enum: [true] }
|
|
21286
21612
|
stopReason: { type: string }
|
|
21287
21613
|
errorMessage: { type: string, description: 'A post-stream error (contract: not thrown as HTTP).' }
|
|
21614
|
+
errorCode:
|
|
21615
|
+
type: string
|
|
21616
|
+
description: >-
|
|
21617
|
+
server >= 7.135.0 (core 7.55.0, passed through verbatim; failure only): the engine's brain error code of the failed reply (open on read; today `auth` / `invalid_request` / `rate_limit` / `server` / `network` /
|
|
21618
|
+
`http` / `stream_torn` / `refusal` / `length_empty`). ABSENT on success and on older servers.
|
|
21619
|
+
errorKind:
|
|
21620
|
+
type: string
|
|
21621
|
+
enum: [input_too_long, degenerate, length_empty]
|
|
21622
|
+
description: 'server >= 7.135.0 (failure only): the STRUCTURAL failure kind the reply carried, forwarded as is — `input_too_long` (the provider refused the request as over its window), `degenerate`, `length_empty`. Absent when the reply carried none.'
|
|
21623
|
+
inputTooLongRuledOut:
|
|
21624
|
+
type: boolean
|
|
21625
|
+
enum: [true]
|
|
21626
|
+
description: 'server >= 7.135.0 (failure only): present (always `true`) when the failure was a provider refusal whose minter RULED OUT input-too-long as the explanation (core `AssistantMessage.inputTooLongRuledOut`, passed through). It speaks ONLY to that negative: it does not say the status is 400 / 422 and does not say a verbatim resend repeats the failure (the engine also rules input length out for statuses such as 401 / 429 / 500) — triage on `errorCode`. Absent = no such judgment.'
|
|
21288
21627
|
|
|
21289
21628
|
ToolApprovalDecision:
|
|
21290
21629
|
type: string
|
|
@@ -21463,6 +21802,8 @@ components:
|
|
|
21463
21802
|
to settle it): a parked row's `decided` can return to `parked` when the resume leg fails before the approved action starts (the engine reopens the same gate), and
|
|
21464
21803
|
a cancelled resume reads `void` once the server collects the reopened gate (`parked` in between, or `void` for an instant during the reopen).
|
|
21465
21804
|
Older servers answered all of these with `parked` + `decidePath`.
|
|
21805
|
+
🔴 server >= 7.135.0: a gate that was DECIDED and then REOPENED by the engine reads `parked` WITH `reopened` (`ToolApprovalReopened`: the engine's reopen reason + the earlier decision's
|
|
21806
|
+
`decision` / `decidedAtMs` / `decisionNote?`). `reopened` ABSENT = the read cannot say it was reopened (not "confirmed never reopened"). Older servers: always absent.
|
|
21466
21807
|
oneOf:
|
|
21467
21808
|
- $ref: '#/components/schemas/ToolApprovalReadPending'
|
|
21468
21809
|
- $ref: '#/components/schemas/ToolApprovalReadDecided'
|
|
@@ -21500,6 +21841,29 @@ components:
|
|
|
21500
21841
|
properties:
|
|
21501
21842
|
state: { type: string, enum: [parked] }
|
|
21502
21843
|
decidePath: { type: string, description: 'The durable decision path for this ask when it can be built.' }
|
|
21844
|
+
reopened:
|
|
21845
|
+
allOf: [{ $ref: '#/components/schemas/ToolApprovalReopened' }]
|
|
21846
|
+
description: 'server >= 7.135.0: present when the gate was decided and then reopened by the engine (the resume leg failed before the approved action started). Absent = the read cannot say it was reopened.'
|
|
21847
|
+
ToolApprovalReopenReason:
|
|
21848
|
+
type: string
|
|
21849
|
+
description: >
|
|
21850
|
+
`ToolApprovalReopened.reason` (server >= 7.135.0) — the engine's `REOPEN_REASONS`, verbatim and in order (engine-owned; the server echoes a word only when it is in this
|
|
21851
|
+
set, otherwise `reopened` is omitted entirely): `env_failed` (the environment / session side failed) · `tool_unavailable` (the approved tool is not there now — decide again) ·
|
|
21852
|
+
`constraint_rejected` (the decision input was rejected — decide again) · `config_refused` (the configuration was refused). Read open on the consumer side: an unknown word is "reopened, reason unknown".
|
|
21853
|
+
enum: [env_failed, tool_unavailable, constraint_rejected, config_refused]
|
|
21854
|
+
ToolApprovalReopened:
|
|
21855
|
+
type: object
|
|
21856
|
+
description: >
|
|
21857
|
+
`ToolApprovalReadParked.reopened` (server >= 7.135.0): evidence that a DECIDED gate was reopened by the engine. `reason` = the engine's reopen reason; `decision` / `decidedAtMs` / `decisionNote?` = the
|
|
21858
|
+
decision made BEFORE the reopen (the same three keys as a `decided` body). An unreadable earlier decision ⇒ the three keys are absent TOGETHER (only `reason` stays; `decisionNote` may always be absent).
|
|
21859
|
+
Single-instant read: if the row is decided and reopened between the two reads the server re-judges (three rounds in a row ⇒ falls back to plain `parked`).
|
|
21860
|
+
additionalProperties: false
|
|
21861
|
+
required: [reason]
|
|
21862
|
+
properties:
|
|
21863
|
+
reason: { $ref: '#/components/schemas/ToolApprovalReopenReason' }
|
|
21864
|
+
decision: { type: string, enum: [allow, deny] }
|
|
21865
|
+
decidedAtMs: { type: integer }
|
|
21866
|
+
decisionNote: { type: string }
|
|
21503
21867
|
ToolApprovalReadVoid:
|
|
21504
21868
|
allOf:
|
|
21505
21869
|
- $ref: '#/components/schemas/ToolApprovalReadProjection'
|
|
@@ -22217,8 +22581,8 @@ components:
|
|
|
22217
22581
|
match:
|
|
22218
22582
|
allOf: [{ $ref: '#/components/schemas/RuleOfferMatch' }]
|
|
22219
22583
|
description: >
|
|
22220
|
-
The match form — the same
|
|
22221
|
-
`PERSISTED_RULE_MATCHES`): `exact` / `prefix` / `wildcard` / `subpath` / `path`, and from server >= 7.118.0
|
|
22584
|
+
The match form — the same ten-member vocabulary as a card's rule offer (`RuleOfferMatch`, the server's
|
|
22585
|
+
`PERSISTED_RULE_MATCHES`): `exact` / `prefix` / `wildcard` / `pattern` (server >= 7.135.0: the mid-star command form) / `subpath` / `path`, and from server >= 7.118.0
|
|
22222
22586
|
`name` / `name_prefix` (a `Skill(<name>)` / `Skill(<prefix>:*)` rule).
|
|
22223
22587
|
command: { type: string, description: 'What the matcher actually compares against, parsed out of `rule` at mint time and stored so no consumer re-parses. Trust this + `match`, not your own parse of `rule`.' }
|
|
22224
22588
|
adds:
|