@sema-agent/sdk 11.2.1 → 12.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 +102 -0
- package/dist/control-types.d.ts +12 -10
- package/dist/control-types.d.ts.map +1 -1
- package/dist/control-types.js +1 -1
- package/dist/control-types.js.map +1 -1
- package/dist/errors.d.ts +9 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +11 -3
- package/dist/errors.js.map +1 -1
- package/dist/events.d.ts +10 -0
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/health.d.ts +118 -6
- package/dist/health.d.ts.map +1 -1
- package/dist/health.js +51 -1
- package/dist/health.js.map +1 -1
- package/dist/index.d.ts +13 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/registry/auth.d.ts +36 -16
- package/dist/registry/auth.d.ts.map +1 -1
- package/dist/registry/auth.js +17 -4
- package/dist/registry/auth.js.map +1 -1
- package/dist/registry/errors.d.ts +6 -5
- package/dist/registry/errors.d.ts.map +1 -1
- package/dist/registry/errors.js +6 -5
- package/dist/registry/errors.js.map +1 -1
- package/dist/registry/index.d.ts +3 -3
- package/dist/registry/index.js +3 -3
- package/dist/registry/scopes-effective.d.ts +34 -6
- package/dist/registry/scopes-effective.d.ts.map +1 -1
- package/dist/registry/scopes-effective.js +2 -2
- package/dist/registry/scopes-effective.js.map +1 -1
- package/dist/resources/approvals.d.ts +41 -0
- package/dist/resources/approvals.d.ts.map +1 -1
- package/dist/resources/approvals.js.map +1 -1
- package/dist/resources/sessions.d.ts +40 -1
- package/dist/resources/sessions.d.ts.map +1 -1
- package/dist/resources/sessions.js +48 -0
- package/dist/resources/sessions.js.map +1 -1
- package/dist/resources/tool-approvals.d.ts +102 -14
- package/dist/resources/tool-approvals.d.ts.map +1 -1
- package/dist/resources/tool-approvals.js +49 -1
- package/dist/resources/tool-approvals.js.map +1 -1
- package/dist/types.d.ts +180 -13
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/openapi.yaml +463 -14
- package/package.json +2 -2
- package/registry-openapi.yaml +6 -5
package/openapi.yaml
CHANGED
|
@@ -2322,6 +2322,106 @@ paths:
|
|
|
2322
2322
|
'422': { $ref: '#/components/responses/UnprocessableEntity' }
|
|
2323
2323
|
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
2324
2324
|
|
|
2325
|
+
/v1/sessions/{sessionId}/background:
|
|
2326
|
+
parameters:
|
|
2327
|
+
- $ref: '#/components/parameters/PrincipalHeader'
|
|
2328
|
+
- in: path
|
|
2329
|
+
name: sessionId
|
|
2330
|
+
required: true
|
|
2331
|
+
schema: { type: string }
|
|
2332
|
+
get:
|
|
2333
|
+
tags: [sessions]
|
|
2334
|
+
operationId: sessionsBackgroundList
|
|
2335
|
+
x-status: live # S-745 (server 7.102.0; core 7.32.0 #1107); SDK sessions.background.
|
|
2336
|
+
summary: The session's background tasks (the exit sheet's "keeps running / will stop" material).
|
|
2337
|
+
description: >
|
|
2338
|
+
S-745 (server >= 7.102.0; core 7.32.0 #1107; contract §16 "embedded-shape contract"; mint
|
|
2339
|
+
`src/http/routes/background.ts`). 200 `{ rows }` — each row is core `TaskRegistry.list()`'s row projected
|
|
2340
|
+
KEY BY KEY by an explicit whitelist (`task_id` renamed `id`; `toolUseId` / `updatedAt` deliberately
|
|
2341
|
+
stripped). Only THIS session's rows: the access tuple is the session's own `{owner: sid, sessionId: sid,
|
|
2342
|
+
scope}` and visibility is core's fail-closed `canAccess` (the session's session-resident shells, the run row
|
|
2343
|
+
whose task id is the session id, workflows this session started, background agents rooted at this
|
|
2344
|
+
session). `retained` rides ONLY when true (core's retain predicate: env / task lane / row mark) — present =
|
|
2345
|
+
"keeps running" on the exit sheet; absent = an `includeRetained:false` stop WILL stop it. `description` is
|
|
2346
|
+
the model's description, falling back to the launch command text (content family: redacted, cut at 500
|
|
2347
|
+
chars). At most 500 rows (core `list()`'s own cap). 🔴 IN-PROCESS: only rows on THIS replica.
|
|
2348
|
+
Zero model work: not billable, not refused by drain. Gates (same family as `mcp/reconnect`): 501
|
|
2349
|
+
`capability.session_ownership_required` (no `sessionStorage.ownerOf`) · 404 `not_found.session` — unknown
|
|
2350
|
+
session AND someone else's session answer the SAME code and SAME message (no existence oracle); an EXPLICIT
|
|
2351
|
+
operator may read any session · 400 `request.path_malformed`. Probe with `capabilities.background.listFace`;
|
|
2352
|
+
ABSENT key = an older server, where this path is 404 `not_found.route` (same status, different code).
|
|
2353
|
+
responses:
|
|
2354
|
+
'200':
|
|
2355
|
+
description: The session's background rows (read the row schema for the `retained` / `status` readings).
|
|
2356
|
+
content:
|
|
2357
|
+
application/json:
|
|
2358
|
+
schema: { $ref: '#/components/schemas/SessionBackgroundList' }
|
|
2359
|
+
'400': { $ref: '#/components/responses/BadRequest' }
|
|
2360
|
+
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
2361
|
+
'404': { $ref: '#/components/responses/NotFound' }
|
|
2362
|
+
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
2363
|
+
|
|
2364
|
+
/v1/sessions/{sessionId}/background/stop:
|
|
2365
|
+
parameters:
|
|
2366
|
+
- $ref: '#/components/parameters/PrincipalHeader'
|
|
2367
|
+
- in: path
|
|
2368
|
+
name: sessionId
|
|
2369
|
+
required: true
|
|
2370
|
+
schema: { type: string }
|
|
2371
|
+
post:
|
|
2372
|
+
tags: [sessions]
|
|
2373
|
+
operationId: sessionsBackgroundStop
|
|
2374
|
+
x-status: live # S-745 (server 7.102.0; core 7.32.0 #1107); SDK sessions.backgroundStop.
|
|
2375
|
+
summary: Stop the session's background tasks — soft, then one grace, then a synchronous hard kill; receipts are complete before 200.
|
|
2376
|
+
description: >
|
|
2377
|
+
S-745 (server >= 7.102.0; contract §16; mint `src/http/routes/background.ts`). The SAME session-level
|
|
2378
|
+
convergence function as the `DELETE /v1/sessions/{sessionId}` cascade: SOFT (core's session anchor SIGTERMs
|
|
2379
|
+
and settles the session's background agents / workflows; every still-running shell row the hard face will
|
|
2380
|
+
revisit gets a per-row soft stop — with `includeRetained:true` the retained live services receive SIGTERM
|
|
2381
|
+
here too) → GRACE (the hard face waits until every row it will revisit is past "its soft-stop instant +
|
|
2382
|
+
`HOST_BG_KILL_GRACE_MS`", default 1000 ms; nothing to wait for ⇒ no wait) → HARD (core
|
|
2383
|
+
`killAllBackgroundShellsNow` — a synchronous process-group SIGKILL; a shell ignoring SIGTERM does not
|
|
2384
|
+
survive it). 🔴 THE RECEIPTS ARE COMPLETE BEFORE THE 200: with background rows the answer is one grace
|
|
2385
|
+
slower — budget the shell's exit wait in seconds.
|
|
2386
|
+
Body `{ includeRetained }` is REQUIRED with NO default (core's rule: the caller states which kind of stop
|
|
2387
|
+
this is): `true` = also stop the explicitly retained live services (the shell's "Exit and stop tasks");
|
|
2388
|
+
`false` = keep them (they come back as `retained_skipped`; `sema kill`'s session-level reap). The body
|
|
2389
|
+
gate is STRICT — absent / non-boolean / an extra key ⇒ 400 `request.body_shape`.
|
|
2390
|
+
Receipts carry SHELL rows only (`background_bash` / `monitor`); `outcome` is core's four words passed
|
|
2391
|
+
through VERBATIM — `killed` (a live process group was reaped now) · `already_gone` (already exited, or
|
|
2392
|
+
already hard-killed — incl. exiting within the grace) · `retained_skipped` (kept by
|
|
2393
|
+
`includeRetained:false`) · `no_pgid` (NO synchronous hard kill landed: remote / sandbox lanes have no
|
|
2394
|
+
host-local process group — e2b / k8s·kata / local-docker / ssh / device / adb always answer it — or win32 /
|
|
2395
|
+
a refused signal; core already sent an ordinary kill ⇒ "MAY STILL BE RUNNING", neither a failure nor ever
|
|
2396
|
+
"stopped").
|
|
2397
|
+
🔴 CREDENTIAL-GATED (server >= 7.102.0 as released): on a worker with no service credential
|
|
2398
|
+
(`SERVICE_AUTH_TOKEN(S)`) and without `ALLOW_UNAUTHED_WRITES`, this path answers 503
|
|
2399
|
+
`auth.service_token_required` BEFORE routing (same code and sentence as every other mutating door) — the
|
|
2400
|
+
principal header is self-asserted there, and stopping background processes is irreversible.
|
|
2401
|
+
`capabilities.background.exitFaces` does NOT include "credentials ready" (the same family gap as the
|
|
2402
|
+
`memoryCompliance` row) — branch on that code. Other gates as the list path: 501
|
|
2403
|
+
`capability.session_ownership_required` · 404 `not_found.session` (unknown and foreign sessions alike) · 400
|
|
2404
|
+
`request.path_malformed`; this path is rate-limited (429). NOT called by run cancel (Esc): session-resident
|
|
2405
|
+
background shells live across turns (CC parity). A delegated helper's shells hang on the helper's own
|
|
2406
|
+
session and are out of this door's reach. Probe with `capabilities.background.exitFaces`.
|
|
2407
|
+
requestBody:
|
|
2408
|
+
required: true
|
|
2409
|
+
content:
|
|
2410
|
+
application/json:
|
|
2411
|
+
schema: { $ref: '#/components/schemas/SessionBackgroundStopRequest' }
|
|
2412
|
+
responses:
|
|
2413
|
+
'200':
|
|
2414
|
+
description: The receipts (shell rows only). Read `no_pgid` as "may still be running".
|
|
2415
|
+
content:
|
|
2416
|
+
application/json:
|
|
2417
|
+
schema: { $ref: '#/components/schemas/SessionBackgroundStopResult' }
|
|
2418
|
+
'400': { $ref: '#/components/responses/BadRequest' }
|
|
2419
|
+
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
2420
|
+
'404': { $ref: '#/components/responses/NotFound' }
|
|
2421
|
+
'429': { $ref: '#/components/responses/RateLimited' }
|
|
2422
|
+
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
2423
|
+
'503': { $ref: '#/components/responses/Unauthorized' } # `auth.service_token_required` — the credential-gated write door (no service credential and no ALLOW_UNAUTHED_WRITES), before routing.
|
|
2424
|
+
|
|
2325
2425
|
/v1/sessions/{sessionId}/memory-status:
|
|
2326
2426
|
parameters:
|
|
2327
2427
|
- $ref: '#/components/parameters/PrincipalHeader'
|
|
@@ -3031,6 +3131,15 @@ paths:
|
|
|
3031
3131
|
(REOPENED) and re-appears on `/v1/approvals`. SDK → ParkedResumeStartupError. Client action:
|
|
3032
3132
|
re-fetch the pending list and decide again, fixing what was rejected. (Before 5.12.0 this shape
|
|
3033
3133
|
collapsed into the 409 `decide.revive_rejected`.)
|
|
3134
|
+
🔴 core 7.32.0 (#1110) ADDS A CAUSE (server >= 7.102.0; contract appendix A.1, MIGRATION 7.102.0): an
|
|
3135
|
+
`approve` on a child parked on an INHERITED tool (a tool family the child inherits from the scenario
|
|
3136
|
+
layer — the task tools, WebFetch …) whose redemption cannot hand over the inherited seat ⇒ core refuses
|
|
3137
|
+
BEFORE consuming the approval: the approval stays PENDING and a `deny` still settles it. From server 7.102.0
|
|
3138
|
+
a ONE-LEVEL row (its root session = the parent session, and that root session STILL belongs to this card's
|
|
3139
|
+
tenant) is redeemed with the seat re-resolved from the root session, so it no longer lands here; a DEEPER
|
|
3140
|
+
(grandchild) row, or one whose root session was deleted / changed owner, still does (core #1112 pending) —
|
|
3141
|
+
render it as "this card can only be denied / wait for a server upgrade". Not a regression: 7.31.x children
|
|
3142
|
+
never had those tools.
|
|
3034
3143
|
content:
|
|
3035
3144
|
application/json:
|
|
3036
3145
|
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
@@ -3808,6 +3917,32 @@ paths:
|
|
|
3808
3917
|
substitution), the command bytes were unreadable, or this ask belongs to one of the seven
|
|
3809
3918
|
families that never get offers — so do NOT diagnose the deployment's rule lane from one
|
|
3810
3919
|
frame or from that one refusal.
|
|
3920
|
+
settledBy:
|
|
3921
|
+
type: string
|
|
3922
|
+
enum: [policy]
|
|
3923
|
+
description: >-
|
|
3924
|
+
server #1016 (>= 7.93.3, core 7.26.2), ADDITIVE — the SETTLEMENT SOURCE of this answer.
|
|
3925
|
+
`"policy"` is a MACHINE REFUSAL, NEVER THE USER'S WORDS: the deployment's own policy answered
|
|
3926
|
+
this card, not a person. ABSENT = today's shape (read as a person's answer).
|
|
3927
|
+
|
|
3928
|
+
Same word, same source and the same three-question rationale as the durable leg's key
|
|
3929
|
+
(`POST /v1/approvals/{sessionId}/decide`, ApprovalDecision.settledBy) — see that schema for
|
|
3930
|
+
the full account. `decision:"deny"` ONLY: an allow-family decision carrying this key is a
|
|
3931
|
+
contradiction, refused BEFORE THE DECISION (400 `request.body_shape`, the same sentence as
|
|
3932
|
+
the durable leg) rather than after — the engine's refusal cannot travel back up this HTTP
|
|
3933
|
+
leg, and by then this door's own side effects (the session allow-all grant, a persisted
|
|
3934
|
+
rule, a DECIDED row that replays as a plain approval) have already landed. Because the
|
|
3935
|
+
refusal precedes the decision, the ask is NOT settled: the card is still open and the same
|
|
3936
|
+
`approvalId` can be answered again. The PARKED late-acceptance arm reads the same key.
|
|
3937
|
+
|
|
3938
|
+
SHAPE, not word: a non-string is a 400. A word core does NOT know travels UNTOUCHED — this
|
|
3939
|
+
door still answers 200 (its 200 only ever meant "your answer was delivered") and the ENGINE
|
|
3940
|
+
refuses it fail-closed, settling as `approver_contract`, NEVER as `policy_refused`: a
|
|
3941
|
+
misspelled word must not be rendered as "the deployment's policy refused".
|
|
3942
|
+
|
|
3943
|
+
No capability bit: an older server ignores unknown keys and answers 200, so the refusal is
|
|
3944
|
+
still read as a person's there. Judge by server version, or read back whether
|
|
3945
|
+
`tool_end.gate.settlement.kind` ever shows `policy_refused`.
|
|
3811
3946
|
note:
|
|
3812
3947
|
type: string
|
|
3813
3948
|
maxLength: 2048
|
|
@@ -3828,6 +3963,23 @@ paths:
|
|
|
3828
3963
|
NOT strict (hand-written parser, unknown keys are ignored), so an older server answers 200 and
|
|
3829
3964
|
records nothing. Bit absent = old server, do not offer the field. Bit present ⇒ read the
|
|
3830
3965
|
per-call truth from the ack's `noteRecorded`.
|
|
3966
|
+
readRootGrant:
|
|
3967
|
+
type: string
|
|
3968
|
+
minLength: 1
|
|
3969
|
+
description: >-
|
|
3970
|
+
S-720 (server >= 7.102.0 / core 7.32.0 #1093), ADDITIVE — "Yes, and add directory": the frame's
|
|
3971
|
+
`readRootCandidate.dir` sent back BYTE FOR BYTE (a STRING — never normalised, cut or composed; not an
|
|
3972
|
+
object). Beside `allow` it also adds that directory to THIS RUN's read directories (read faces only).
|
|
3973
|
+
🔴 `decision:"allow"` ONLY — on `allow_session` / `deny` the server refuses BEFORE the decision with 400
|
|
3974
|
+
`request.body_shape` (the card stays open; answer the same `approvalId` again). SHAPE gate: a non-empty
|
|
3975
|
+
string of at most core's `READ_ROOT_CANDIDATE_DIR_MAX`, else the same 400 (an over-long value is refused
|
|
3976
|
+
whole, never cut — a cut directory is another directory). The server judges SHAPE, never VALUE: whether
|
|
3977
|
+
it equals the card's string is the ENGINE's call, and the verdict arrives only as an `engine_notice` —
|
|
3978
|
+
`approval.read_root_granted` (the run's read roots really widened) or `approval.read_root_grant_rejected`
|
|
3979
|
+
(nothing changed; the decision stands). The 200 never says which. Reach: THIS RUN only (the ask row has no
|
|
3980
|
+
such column, so replay / failover / durable resume do not carry it) and THIS DOOR only (the durable
|
|
3981
|
+
`/decide` and the in-stream `…/asks/{askId}/decision` doors do not read it). An older server ignores the
|
|
3982
|
+
unknown key and answers 200 with a plain allow (no capability bit yet) — trust the notice.
|
|
3831
3983
|
responses:
|
|
3832
3984
|
'200':
|
|
3833
3985
|
description: Ack (`decision` echoed).
|
|
@@ -6532,15 +6684,27 @@ components:
|
|
|
6532
6684
|
rewindFiles:
|
|
6533
6685
|
type: boolean
|
|
6534
6686
|
description: >
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6687
|
+
RETIRED SPELLING (the whole-tree snapshot epoch; S-15 / design/381, server >= 7.52 — note corrected in sdk
|
|
6688
|
+
11.4.0, the same stale-note family as `rewindFilesTo`, board [8437] U3). Server `src/http/wire-types.ts`: still
|
|
6689
|
+
accepted on the wire — its capture sense (true, no resumeAt) is a tolerated no-op with a deprecation disclosure;
|
|
6690
|
+
its restore sense (true + resumeAt) is core's TYPED migration rejection naming `restoreFiles` (restore semantics
|
|
6691
|
+
really changed: whole tree ⇒ tracked set; the server never remaps it silently). Send `restoreFiles` (probe
|
|
6692
|
+
`capabilities.restoreFiles`); this key stays declared only for <= 7.51 servers.
|
|
6538
6693
|
rewindFilesTo:
|
|
6539
6694
|
type: string
|
|
6540
6695
|
description: >
|
|
6541
|
-
CC Rewind "code"-only (core 1.166.0 TaskSpec.rewindFilesTo).
|
|
6542
|
-
|
|
6543
|
-
|
|
6696
|
+
CC Rewind "code"-only (core 1.166.0 TaskSpec.rewindFilesTo; server "R8"). Converge the files this session
|
|
6697
|
+
edited (the TRACKED set) to the history boundary at a prior USER message WITHOUT forking the conversation (the
|
|
6698
|
+
session leaf is untouched — only the files move). Use instead of resumeAt+restoreFiles when the user wants only
|
|
6699
|
+
files reverted. 🔴 The value is a HANDLE, not an entry id (corrected in sdk 11.4.0, board [8437] U3): the SAME
|
|
6700
|
+
kind of handle as `resumeAt`, resolved through the SAME anchor store — typically the `taskId` from that turn's
|
|
6701
|
+
202 receipt (the server keys the user-message anchor by the run's taskId). Server `src/boot/resolve-spec.ts:686-697`:
|
|
6702
|
+
`resumeAnchorStore.resolve(sessionId, handle, principal)` → entry id; unknown handle ⇒ 404
|
|
6703
|
+
`rewind_files_to.unknown_event`; no session ⇒ 422 `rewind_files_to.no_session`; no anchor store / no getLeafId ⇒
|
|
6704
|
+
501. ⚠️ The 501 is NOT the capability's whole predicate: `capabilities.rewindFilesTo` also requires the
|
|
6705
|
+
file-history store (capture face); without it the server does not 501 — core refuses in the run with
|
|
6706
|
+
`rewind.store_unconfigured` — so probe the bit first. Honored ONLY when `resumeAt` is absent. One-shot at submit
|
|
6707
|
+
(resume legs strip it, server >= 7.72.0).
|
|
6544
6708
|
restoreFiles:
|
|
6545
6709
|
type: boolean
|
|
6546
6710
|
description: >-
|
|
@@ -7931,6 +8095,40 @@ components:
|
|
|
7931
8095
|
not inside the HMAC payload, so accepting it unsigned would be tamperable); 501 without an exemption
|
|
7932
8096
|
store. On the parked-background-agent leg the grant lands on the child's ROOT/HOST session (the whole
|
|
7933
8097
|
session tree shares it). The 200 body echoes `rememberApplied` when a store is wired.
|
|
8098
|
+
settledBy:
|
|
8099
|
+
type: string
|
|
8100
|
+
enum: [policy]
|
|
8101
|
+
description: >-
|
|
8102
|
+
server #1016 (>= 7.93.3, core 7.26.2), ADDITIVE — WHO made this decision. `"policy"` is a MACHINE
|
|
8103
|
+
REFUSAL, NEVER THE USER''S WORDS: the deployment''s own policy answered this card (a headless lane —
|
|
8104
|
+
CI, a background batch, a shell refusing by a standing deployment posture). ABSENT = today''s shape
|
|
8105
|
+
(`person`), so an unrevised caller is byte-for-byte unchanged.
|
|
8106
|
+
|
|
8107
|
+
WHY IT EXISTS: without the word, a policy refusal is byte-identical to "a person pressed No", and the
|
|
8108
|
+
model reads "the user doesn''t want to proceed; STOP and wait for the user to tell you how to proceed"
|
|
8109
|
+
— a sentence about a person, in a run where none is coming. With it the engine mints a POLICY sentence
|
|
8110
|
+
instead, this request''s `reason` travels as the POLICY''s words (not as the user''s guidance), and the
|
|
8111
|
+
settlement is recorded as `policy_refused` (`who.party: "none"`).
|
|
8112
|
+
|
|
8113
|
+
CONSTRAINTS: `decision:"deny"` only — only a person approves an action that EXECUTES, so
|
|
8114
|
+
`{decision:"approve", settledBy:"policy"}` is a contradiction, refused by the SERVER before the
|
|
8115
|
+
decision (400 `request.field_conflict`, the SAME SENTENCE as the live door) with the engine''s own
|
|
8116
|
+
pre-CAS refusal (`checkpoint.invalid_outcome`) behind it as depth; the server does NOT silently drop
|
|
8117
|
+
the key. It is therefore MUTUALLY EXCLUSIVE with `remember` (which is approve-only) — one body
|
|
8118
|
+
cannot carry both. The vocabulary''s owner is still core: the server accepts the KEY and relays the
|
|
8119
|
+
VALUE verbatim, so a word core does not know is refused by the engine, never by a server-side
|
|
8120
|
+
second judge of the vocabulary.
|
|
8121
|
+
REFUSED on a direct-door worker (400 `settled_by_not_in_proof` — not inside the HMAC payload, same
|
|
8122
|
+
rule as `remember` / `updatedInput` / `checkpointToken`); a non-direct-door deployment is unchanged.
|
|
8123
|
+
|
|
8124
|
+
SHAPE, not word: a non-string is 400 `request.field_invalid` (same family as `reason must be a
|
|
8125
|
+
string`). A word core does NOT know travels UNTOUCHED and is refused BY THE ENGINE pre-CAS:
|
|
8126
|
+
409 + `errorCode: "resume_outcome_invalid"` + `field: "hostDecision"` + `retriable: true`, and the
|
|
8127
|
+
card STAYS PENDING (re-decide the same coordinates with a corrected body). NOTE this family no
|
|
8128
|
+
longer answers `approval_binding_mismatch`: from server 7.93.3 the `policy_ask` gate splits
|
|
8129
|
+
`invalid_outcome` by `field`, and the non-binding seats (`hostDecision`, `approver`) answer
|
|
8130
|
+
`resume_outcome_invalid` — "you approved the wrong action" is a sentence about a different fault.
|
|
8131
|
+
The binding seats and the field-absent shape are byte-for-byte unchanged.
|
|
7934
8132
|
|
|
7935
8133
|
ApprovalRow:
|
|
7936
8134
|
type: object
|
|
@@ -8127,7 +8325,16 @@ components:
|
|
|
8127
8325
|
with no explicit allowlist); ABSENT = an older server (degrade to not teaching, not validating).
|
|
8128
8326
|
resumeAt: { type: boolean, description: "E18 resume-at-message anchors are resolvable." }
|
|
8129
8327
|
rewindFiles: { type: boolean, description: "E19 working-tree snapshot/restore is wired." }
|
|
8130
|
-
rewindFilesTo:
|
|
8328
|
+
rewindFilesTo:
|
|
8329
|
+
type: boolean
|
|
8330
|
+
description: >-
|
|
8331
|
+
Code-only rewind (`TaskRequest.rewindFilesTo`) is wired — mint `routes/capabilities.ts:839` =
|
|
8332
|
+
`Boolean(deps.fileHistoryStore && deps.resumeAnchorStore && deps.sessionStorage?.getLeafId)`: it needs the
|
|
8333
|
+
file-history store (to restore) AND the anchor map (to resolve the target HANDLE). Corrected in sdk 11.4.0
|
|
8334
|
+
(board [8437] U3): the store is the FILE-HISTORY store (not the pre-S-15 whole-tree snapshot store), and since
|
|
8335
|
+
server 7.97.0 (S-589) that seat is the CAPTURE face = backend AND the `FILE_HISTORY_CAPTURE` knob — a deployment
|
|
8336
|
+
that turns capture off reports this bit false together with `rewindFiles` / `restoreFiles` / `sessionSync`
|
|
8337
|
+
(and `fileHistoryCapture: "off"`).
|
|
8131
8338
|
restoreFiles:
|
|
8132
8339
|
type: boolean
|
|
8133
8340
|
description: >-
|
|
@@ -8691,6 +8898,70 @@ components:
|
|
|
8691
8898
|
properties:
|
|
8692
8899
|
provider: { type: string, description: 'host | e2b | k8s | ssh | adb | local-docker | device — typed from the server''s RemoteExecProvider; `REMOTE_EXEC` unset ⇒ `host`.' }
|
|
8693
8900
|
toolsOnThisHost: { type: boolean, description: 'The tools run on the process that answered this request (server-absolute paths mean something to the model''s tools).' }
|
|
8901
|
+
taskWriteFaceOpen:
|
|
8902
|
+
type: boolean
|
|
8903
|
+
description: >
|
|
8904
|
+
server >= 7.95.0 (S-591; value meaning refined at 7.96.0 / S-613; mint `routes/capabilities.ts:653` =
|
|
8905
|
+
`taskWriteFaceRefusal(deps.config) === undefined && autonomyOverrides(deps.config.autonomy).writeFace !== "roots"`)
|
|
8906
|
+
— DISCLOSURE BIT OF THE WRITE-CONTAINMENT FACE: does this deployment honour the task-level "open the write
|
|
8907
|
+
fence" declaration (`permissionMode:"bypassPermissions"` ⇒ `TaskSpec.writeFace:"open"`, writes outside the
|
|
8908
|
+
workspace roots)? `false` has two forms: (1) the hosted-posture gate refuses ⇒ sending that mode gets
|
|
8909
|
+
`422 request.host_posture_refused`; (2) the deployment runs `AUTONOMY=read-only|plan` ⇒ the request is
|
|
8910
|
+
accepted but the write face is clamped back to roots — the declaration silently does nothing. Three states
|
|
8911
|
+
are folded into one bit on purpose: the caller has exactly one decision (send that key or not); tier and
|
|
8912
|
+
evidence live in the refusal body and the operator's `GET /v1/diagnostics/wiring`. It speaks ONLY for the
|
|
8913
|
+
write-containment cell — the other two columns of `bypassPermissions` are unaffected.
|
|
8914
|
+
ABSENT = an older worker (<= 7.94) ⇒ read as `true` (contract appendix B.1: nothing refused it back then).
|
|
8915
|
+
taskApproverPosture:
|
|
8916
|
+
type: boolean
|
|
8917
|
+
description: >
|
|
8918
|
+
server >= 7.95.0 (S-591 leg ③; mint `routes/capabilities.ts:659` = `taskApproverPostureHonored(deps.config)`,
|
|
8919
|
+
the SAME predicate as the real consumer) — DISCLOSURE BIT OF `approverPosture`: does this deployment honour
|
|
8920
|
+
the submit body's host-posture statement ("this run's approval cards are auto-answered by the host
|
|
8921
|
+
itself")? `false` ⇒ the key is IGNORED (the request is still 202-accepted; the server logs
|
|
8922
|
+
`task_approver_posture_ignored`) — deliberately NOT refused: the resume legs replay the persisted body
|
|
8923
|
+
verbatim and the caller cannot remove it, so a refusal would brick a parked task forever. Same reach as
|
|
8924
|
+
the hosted-gate half of `taskWriteFaceOpen` (hosted posture ⇒ both false); `AUTONOMY=read-only|plan`
|
|
8925
|
+
only clears `taskWriteFaceOpen`, never this bit.
|
|
8926
|
+
ABSENT = an older worker (<= 7.94) ⇒ read as `true` (contract appendix B.1: it passed through back then).
|
|
8927
|
+
fileHistoryCapture:
|
|
8928
|
+
type: string
|
|
8929
|
+
enum: ['off', on-always]
|
|
8930
|
+
description: >
|
|
8931
|
+
server >= 7.97.0 (S-589; mint `routes/capabilities.ts:847` = `fileHistoryCaptureOf(deps.fileHistoryStore)`,
|
|
8932
|
+
closed word set owned by the server's `src/file-history-capture.ts` `FILE_HISTORY_CAPTURE_WORD_SET`) —
|
|
8933
|
+
CAN FILE-HISTORY CAPTURE BE TURNED OFF. Derived from the ASSEMBLY RESULT (capture face = backend AND the
|
|
8934
|
+
`FILE_HISTORY_CAPTURE` deployment knob), NOT an echo of the knob — a deployment without the backend is
|
|
8935
|
+
`off` too; the SAME judgement as `rewindFiles` / `restoreFiles` / `rewindFilesTo` / `sessionSync`.
|
|
8936
|
+
`off` = this deployment captures no first-touch snapshots and has no rewind / restore / code-only rewind /
|
|
8937
|
+
session-sync ⇒ render neither a "turn capture off" switch nor a rewind entry. `on-always` = capturing, and
|
|
8938
|
+
it CANNOT be turned off per session (core's first-touch capture is process-wide) ⇒ render one read-only true
|
|
8939
|
+
sentence, never a switch that cannot switch.
|
|
8940
|
+
🔴 A third word `on-optional` ("this session may skip capture") is DELIBERATELY UNDECLARED by the server (it
|
|
8941
|
+
waits for a per-session no-capture seat in core); when it lands it is an additive server change and this
|
|
8942
|
+
enum grows with it. Keep a default arm (unknown word ⇒ treat as unknown, render no switch). Turning capture
|
|
8943
|
+
off does NOT delete what was already captured.
|
|
8944
|
+
ABSENT = an older worker (<= 7.96) ⇒ fall back to `rewindFiles` (`true` ⇒ `on-always`, `false` ⇒ `off`).
|
|
8945
|
+
background:
|
|
8946
|
+
type: object
|
|
8947
|
+
additionalProperties: true
|
|
8948
|
+
description: >
|
|
8949
|
+
server >= 7.102.0 (S-745 / core 7.32.0 #1107; mint `routes/capabilities.ts:308` = `{ listFace:
|
|
8950
|
+
sessionBackgroundFacesAvailable(deps), exitFaces: sessionBackgroundFacesAvailable(deps) }`) — presence of the
|
|
8951
|
+
session background-task doors: `listFace` = `GET /v1/sessions/{sessionId}/background`, `exitFaces` =
|
|
8952
|
+
`POST /v1/sessions/{sessionId}/background/stop` (contract §16). Both bits use the SAME predicate as the two
|
|
8953
|
+
doors' 501 (the session-ownership face `sessionStorage.ownerOf`), so "says yes but 501s" is structurally
|
|
8954
|
+
impossible; without it both bits are explicitly `false` and both doors answer 501
|
|
8955
|
+
`capability.session_ownership_required`. ENDPOINT-GATE FORM: `false` ⇒ do not call. True only promises the
|
|
8956
|
+
endpoint — not that this replica holds any background row of that session (the registry is in-process).
|
|
8957
|
+
⚠️ `exitFaces` does NOT cover "credentials ready": on a worker with no service credential and without
|
|
8958
|
+
`ALLOW_UNAUTHED_WRITES` the bit is true while the stop door answers 503 `auth.service_token_required` —
|
|
8959
|
+
branch on that code (the same family gap as `memoryCompliance`). ABSENT = an older server (both doors 404)
|
|
8960
|
+
⇒ the shell's exit dialog offers only "Stay / Exit", never "Exit and stop tasks".
|
|
8961
|
+
required: [listFace, exitFaces]
|
|
8962
|
+
properties:
|
|
8963
|
+
listFace: { type: boolean }
|
|
8964
|
+
exitFaces: { type: boolean }
|
|
8694
8965
|
WriteProtectionCapability:
|
|
8695
8966
|
type: object
|
|
8696
8967
|
additionalProperties: false
|
|
@@ -10746,6 +11017,13 @@ components:
|
|
|
10746
11017
|
sessionId: { type: string }
|
|
10747
11018
|
requiresRealApproval: { type: boolean, enum: [true] }
|
|
10748
11019
|
governanceForced: { type: boolean, enum: [true] }
|
|
11020
|
+
mandated: { type: boolean, enum: [true], description: 'server >= 7.101.0 (T4①): the mandated bit, same layer and shape as the two flags above (present only when true); the SAME value as `frame.mandated` (read once when the entry is minted).' }
|
|
11021
|
+
mandate:
|
|
11022
|
+
allOf: [{ $ref: '#/components/schemas/PersistedRuleMandate' }]
|
|
11023
|
+
description: 'server >= 7.102.0 (S-721): which word the mandated bit stands on — same layer and shape as `mandated`, the SAME value as `frame.mandate`. Absence never names a word.'
|
|
11024
|
+
origin:
|
|
11025
|
+
allOf: [{ $ref: '#/components/schemas/AskOrigin' }]
|
|
11026
|
+
description: 'server >= 7.102.0 (S-755 / cli L-695): WHO raised this ask, read once together with `frame.origin` when the entry is minted. The durable `pending[]` rows of the same response carry it top-level too — one reading for both row families. OPEN set (see AskOrigin).'
|
|
10749
11027
|
fromSubagent: { type: boolean, enum: [true], description: 'The ask originates from a delegated subagent.' }
|
|
10750
11028
|
originTaskId: { type: string, description: 'S-52 C2 (server ≥7.52, A-075.87): the delegated child taskId (= the child''s core runSourceTaskId, uuid) — correlates this live ask to the child run row. Minted by the SAME conditional spread as `fromSubagent`: the two keys are always both present or both absent (三键恒等亲证在案).' }
|
|
10751
11029
|
contentKind: { type: string, description: 'S-62 (server >= 7.6x): content-question kind — `content_ask` when the gated tool is AskUserQuestion (the SAME word as the two durable read faces and core''s summarize face). Absent = an ordinary tool ask. Display/triage only; it NEVER takes part in decision routing.' }
|
|
@@ -11054,6 +11332,27 @@ components:
|
|
|
11054
11332
|
presence may differ between the two legs for one ask. Derived from hot-reloadable governance knobs —
|
|
11055
11333
|
long subscribers follow the stream's re-emitted frames. Absence ≠ "not governance-forced"; it means
|
|
11056
11334
|
"no governance-origin evidence". Never written as false.
|
|
11335
|
+
# ── park-row facts (server `src/approval-card.ts` `ParkRowFacts` — the five facts core mints on the parked
|
|
11336
|
+
# `PendingAction.tool_approval` arm, projected by `parkRowFacts`, the SAME projection on both stores and on the
|
|
11337
|
+
# `/stream` `pending` frame). DISPLAY / TRIAGE projection, never a permission input; each present only when
|
|
11338
|
+
# true / a word. sdk 11.4.0 declares all five (the first three were already on the wire since 7.100.0 / 7.101.0).
|
|
11339
|
+
requiresRealApproval:
|
|
11340
|
+
type: boolean
|
|
11341
|
+
enum: [true]
|
|
11342
|
+
description: 'server >= 7.100.0 (S-700): this parked ask can only be cleared by a REAL HUMAN (core park-row twin seat, strict `=== true`). Absent = not marked, never "clearable without a person".'
|
|
11343
|
+
mandated:
|
|
11344
|
+
type: boolean
|
|
11345
|
+
enum: [true]
|
|
11346
|
+
description: 'server >= 7.101.0 (S-663 part 2 / core 7.31.0 #1079): the durable twin of the mandated bit (no rule can clear this ask). Independent of `requiresRealApproval` (which implies it) and `ruleOffersAbsence` — projected bit by bit, never inferred.'
|
|
11347
|
+
mandate:
|
|
11348
|
+
allOf: [{ $ref: '#/components/schemas/PersistedRuleMandate' }]
|
|
11349
|
+
description: 'server >= 7.102.0 (S-721): which word the mandated bit stands on — the park-row twin seat read through `readClosedWordSeat(…, "mandate")` (core `isPersistedRuleMandate`); an out-of-set word reads as absent. Answers the same as the inbox row for the same row.'
|
|
11350
|
+
origin:
|
|
11351
|
+
allOf: [{ $ref: '#/components/schemas/AskOrigin' }]
|
|
11352
|
+
description: 'server >= 7.102.0 (S-755 / cli L-695 / C-R111): WHO raised this ask — the park-row twin seat `PendingAction.tool_approval.origin` read through `readClosedWordSeat(…, "origin")` (core `isAskOrigin`). Same word as the live card frame and the inbox row. Absent = an old row (parked before core 7.5.0) or an out-of-set word — NOT "policy".'
|
|
11353
|
+
ruleOffersAbsence:
|
|
11354
|
+
allOf: [{ $ref: '#/components/schemas/RuleOffersAbsence' }]
|
|
11355
|
+
description: 'server >= 7.100.0 (S-700): WHY the park row offers no rule — the same narrow read and closed three-word set as the live card frame and `card_json`.'
|
|
11057
11356
|
hasBidiControls:
|
|
11058
11357
|
type: boolean
|
|
11059
11358
|
enum: [true]
|
|
@@ -11160,6 +11459,20 @@ components:
|
|
|
11160
11459
|
🔴 NEVER minted as `false` (the OMIT contract this row's other flags follow); absence is "not marked",
|
|
11161
11460
|
never "confirmed clearable without a person". The value comes WHOLE from core (`summarizeCheckpoint`
|
|
11162
11461
|
projects the park row's own bit) — the server neither recomputes nor redacts it.
|
|
11462
|
+
mandated:
|
|
11463
|
+
type: boolean
|
|
11464
|
+
enum: [true]
|
|
11465
|
+
description: >-
|
|
11466
|
+
server >= 7.101.0 (S-663 part 2 / core 7.31.0 #1079), ADDITIVE, present ONLY when true: the durable twin of
|
|
11467
|
+
the mandated bit (core `summarizeCheckpoint` screens the park row's `PendingAction.tool_approval.mandated`
|
|
11468
|
+
to a literal `true`; the server mints the key on strict `=== true`). Declared in sdk 11.4.0 — this schema is
|
|
11469
|
+
CLOSED, so before that a strict validator rejected every row that carried it.
|
|
11470
|
+
mandate:
|
|
11471
|
+
allOf: [{ $ref: '#/components/schemas/PersistedRuleMandate' }]
|
|
11472
|
+
description: >-
|
|
11473
|
+
server >= 7.102.0 (S-721 / core 7.32.0 #1092): which word the mandated bit stands on (core
|
|
11474
|
+
`CheckpointSummary.mandate`, already screened by core's `isPersistedRuleMandate`; the server does not screen
|
|
11475
|
+
twice). Answers the same as the operator queue row for the same park row.
|
|
11163
11476
|
denialLimitFallback:
|
|
11164
11477
|
$ref: '#/components/schemas/DenialLimitFallback'
|
|
11165
11478
|
description: >-
|
|
@@ -11789,6 +12102,73 @@ components:
|
|
|
11789
12102
|
budgetMs: { type: integer }
|
|
11790
12103
|
error: { type: string }
|
|
11791
12104
|
|
|
12105
|
+
SessionBackgroundRow:
|
|
12106
|
+
type: object
|
|
12107
|
+
description: >
|
|
12108
|
+
One row of `GET /v1/sessions/{sessionId}/background` (S-745, server >= 7.102.0; mint
|
|
12109
|
+
`src/http/routes/background.ts` `SessionBackgroundRow`) = core `TaskRegistry.list()`'s row projected key by
|
|
12110
|
+
key (`task_id` renamed `id`; `toolUseId` / `updatedAt` stripped). The three word sets are OWNED BY CORE
|
|
12111
|
+
(7.32.1 `SemaTaskType` / `SemaTaskStatus`), transcribed verbatim. 🔴 IN-PROCESS: only rows on this replica.
|
|
12112
|
+
Response projection: declared key by key AND open (additive keys between SDK releases must not make a legal
|
|
12113
|
+
row unreadable — the LivePendingRow ruling).
|
|
12114
|
+
additionalProperties: true
|
|
12115
|
+
required: [id, type, status, createdAt, sessionScoped]
|
|
12116
|
+
properties:
|
|
12117
|
+
id: { type: string, description: 'core `task_id` (renamed). A receipt''s `id` is the same value.' }
|
|
12118
|
+
description: { type: string, description: 'The model''s description, falling back to the launch command text (core keeps no separate raw command). Content family: redacted, cut at 500 characters. UNTRUSTED for display.' }
|
|
12119
|
+
type: { type: string, enum: [background_bash, workflow, background_agent, monitor], description: 'core `SemaTaskType`.' }
|
|
12120
|
+
status: { type: string, enum: [pending, running, parked, completed, failed, killed, cancelled], description: 'core `SemaTaskStatus` (`parked` = a background agent suspended on a pending approval — neither live nor terminal).' }
|
|
12121
|
+
createdAt: { type: integer, description: 'Registration time (epoch ms).' }
|
|
12122
|
+
sessionScoped: { type: boolean, description: '`true` = session-resident (lives across turns); `false` = run-scoped.' }
|
|
12123
|
+
retained:
|
|
12124
|
+
type: boolean
|
|
12125
|
+
enum: [true]
|
|
12126
|
+
description: >-
|
|
12127
|
+
core's retain predicate (env declaration / task lane / row mark — any ⇒ kept) — present ONLY when true,
|
|
12128
|
+
never minted as false, and only ever on a shell row (`background_bash` / `monitor`; core `list()` row
|
|
12129
|
+
doc). Present = "keeps running" on the exit sheet; absent = an `includeRetained:false` stop WILL stop it.
|
|
12130
|
+
SessionBackgroundList:
|
|
12131
|
+
type: object
|
|
12132
|
+
description: '`GET /v1/sessions/{sessionId}/background` 200 body (contract §16). An idle session answers `{ rows: [] }`.'
|
|
12133
|
+
additionalProperties: true
|
|
12134
|
+
required: [rows]
|
|
12135
|
+
properties:
|
|
12136
|
+
rows:
|
|
12137
|
+
type: array
|
|
12138
|
+
items: { $ref: '#/components/schemas/SessionBackgroundRow' }
|
|
12139
|
+
SessionBackgroundStopRequest:
|
|
12140
|
+
type: object
|
|
12141
|
+
description: >
|
|
12142
|
+
`POST /v1/sessions/{sessionId}/background/stop` body — server `StopBodySchema = z.object({ includeRetained:
|
|
12143
|
+
z.boolean() }).strict()`: EXACTLY this key, REQUIRED, NO default. `true` = also stop explicitly retained live
|
|
12144
|
+
services ("Exit and stop tasks"); `false` = keep them (`retained_skipped`). Absent / non-boolean / an extra
|
|
12145
|
+
key ⇒ 400 `request.body_shape`.
|
|
12146
|
+
additionalProperties: false
|
|
12147
|
+
required: [includeRetained]
|
|
12148
|
+
properties:
|
|
12149
|
+
includeRetained: { type: boolean }
|
|
12150
|
+
SessionBackgroundReceipt:
|
|
12151
|
+
type: object
|
|
12152
|
+
description: >
|
|
12153
|
+
One receipt of the stop door — SHELL rows only (`background_bash` / `monitor`). `outcome` = core 7.32.1
|
|
12154
|
+
`BackgroundShellHardKillReceipt.outcome` (`BackgroundHardKillOutcome` ∪ `retained_skipped`), passed through
|
|
12155
|
+
VERBATIM: `killed` / `already_gone` (both = "this row is reaped") · `retained_skipped` (kept, process alive) ·
|
|
12156
|
+
`no_pgid` (no synchronous hard kill landed — MAY STILL BE RUNNING; never render it as stopped).
|
|
12157
|
+
additionalProperties: true
|
|
12158
|
+
required: [id, outcome]
|
|
12159
|
+
properties:
|
|
12160
|
+
id: { type: string, description: 'The row id (core taskId).' }
|
|
12161
|
+
outcome: { type: string, enum: [killed, already_gone, retained_skipped, no_pgid] }
|
|
12162
|
+
SessionBackgroundStopResult:
|
|
12163
|
+
type: object
|
|
12164
|
+
description: '`POST /v1/sessions/{sessionId}/background/stop` 200 body. The receipts are COMPLETE before the 200 (soft → grace → hard is awaited).'
|
|
12165
|
+
additionalProperties: true
|
|
12166
|
+
required: [receipts]
|
|
12167
|
+
properties:
|
|
12168
|
+
receipts:
|
|
12169
|
+
type: array
|
|
12170
|
+
items: { $ref: '#/components/schemas/SessionBackgroundReceipt' }
|
|
12171
|
+
|
|
11792
12172
|
# ── 2c session-sync (P1d) — the cloud-as-a-SYNC-PEER schemas ──────────────────────────────────────────────
|
|
11793
12173
|
SyncEntry:
|
|
11794
12174
|
type: object
|
|
@@ -12479,12 +12859,18 @@ components:
|
|
|
12479
12859
|
the ROUTING question "nobody reachable" and no park took the ask) · `approver_error` (it threw) ·
|
|
12480
12860
|
`approver_contract` (it answered outside its contract) · `presentation_failed` (args/edit could not be
|
|
12481
12861
|
safely presented or adopted) · `blanket_allow_refused` (a blanket `onAsk:"allow"` met a
|
|
12482
|
-
`requiresRealApproval` ask) · `
|
|
12862
|
+
`requiresRealApproval` ask) · `policy_refused` (server >= 7.93.3 / core 7.26.2, #1016 — THE
|
|
12863
|
+
DEPLOYMENT''S OWN POLICY refused: the approval channel reported that a MACHINE, not a person, ended
|
|
12864
|
+
this wait. Distinct from `human_refused` because the party differs and the model is told a different
|
|
12865
|
+
thing — a person''s "no" is the user''s direction, a policy''s is a capability of this run; distinct
|
|
12866
|
+
from `no_approver` because a channel WAS wired and answered. This family carries NO `note` seat: the
|
|
12867
|
+
note seat belongs to the two human words, whose ABSENCE is a control-flow fact) · `task_aborted`
|
|
12868
|
+
(the wait''s abort signal ended it).
|
|
12483
12869
|
required: [kind, who, when]
|
|
12484
12870
|
properties:
|
|
12485
12871
|
kind:
|
|
12486
12872
|
type: string
|
|
12487
|
-
enum: [no_approver, approver_unavailable, approver_error, approver_contract, presentation_failed, blanket_allow_refused, task_aborted]
|
|
12873
|
+
enum: [no_approver, approver_unavailable, approver_error, approver_contract, presentation_failed, blanket_allow_refused, policy_refused, task_aborted]
|
|
12488
12874
|
who:
|
|
12489
12875
|
type: object
|
|
12490
12876
|
additionalProperties: false
|
|
@@ -13585,6 +13971,17 @@ components:
|
|
|
13585
13971
|
spec-resolver, which now passes the notice seat). Consequence for consumers that assert on ledger
|
|
13586
13972
|
CONTENTS: a resume leg's ledger MAY now carry one extra `engine_notice` row it did not before — assert
|
|
13587
13973
|
"may appear", never an exact row count or order (and consume idempotently: reconnect replay shows it again).
|
|
13974
|
+
`approval.read_root_granted` / `approval.read_root_grant_rejected` (server >= 7.102.0 / S-720 / core 7.32.0
|
|
13975
|
+
#1093) — the ENGINE's verdict on a `readRootGrant` answer (POST /v1/tool-approvals/{id}/respond), at most one
|
|
13976
|
+
frame per answered ask. GRANTED = this run's read directories really include it now (core: the ONLY evidence the
|
|
13977
|
+
run widened; read faces only, this run only) — `{dir, covers?, root, toolName, toolCallId, sessionId, runId,
|
|
13978
|
+
taskId?}`, `root` = the canonical spelling the engine holds. REJECTED = nothing changed and the decision stands
|
|
13979
|
+
(say so plainly) — `{reason, offered?, requested?, toolName, toolCallId, sessionId, runId, taskId?}`, `reason` one of
|
|
13980
|
+
core's eight words (`on_refusal` / `not_a_string` / `no_candidate` / `mismatch` / `unresolvable` /
|
|
13981
|
+
`resolves_elsewhere` / `admits_artifact_store` — the directory contains, lies inside or is the local artifact
|
|
13982
|
+
store; unreachable on a server 7.102.0 deployment, which wires no artifact host — / `no_read_roots`), passed
|
|
13983
|
+
through verbatim by the server (echo-only, not enumerated) — read it as an OPEN set. `toolCallId` joins to the
|
|
13984
|
+
`tool_approval` frame.
|
|
13588
13985
|
`delegation.ask_unresolvable` (server >= 7.69.0 / core 7.10.0 #648) — an `ask` reached a FINAL DENY with
|
|
13589
13986
|
NOBODY having ruled on it: the approver consulted for the call answered `unavailable` and no durable park
|
|
13590
13987
|
caught it afterwards. The deny itself is unchanged (`tool_end.gate.settlement.kind:"approver_unavailable"`
|
|
@@ -14258,8 +14655,18 @@ components:
|
|
|
14258
14655
|
description: >
|
|
14259
14656
|
(server >= 7.93.0, core 7.26.0 #997) This card was MANDATED — a read-station / rule-lane forced ask (a rule can
|
|
14260
14657
|
never clear it; an approver's yes cannot release a deny-listed read). Present only when true, literal `true`;
|
|
14261
|
-
absent = an ordinary ask.
|
|
14262
|
-
(
|
|
14658
|
+
absent = an ordinary ask. ⚠️ CORRECTED (sdk 11.4.0): the durable parked row DOES carry a twin bit since core
|
|
14659
|
+
7.31.0 #1079 (`PendingAction.tool_approval.mandated`), projected since server 7.101.0 onto the operator queue
|
|
14660
|
+
row / the `/stream` `pending` frame / the inbox row (S-663 part 2) and the `livePending` row top level (T4①)
|
|
14661
|
+
— four faces, one bit. `card_json` does not carry it (`ApprovalCardSchema` is `.strict()`).
|
|
14662
|
+
mandate:
|
|
14663
|
+
allOf: [{ $ref: '#/components/schemas/PersistedRuleMandate' }]
|
|
14664
|
+
description: >-
|
|
14665
|
+
server >= 7.102.0 (S-721 / core 7.32.0 #1092), "tool_approval" only, ADDITIVE — which word the `mandated`
|
|
14666
|
+
bit stands on (server `src/tool-approval.ts:841`, read through `readClosedWordSeat(req, "mandate")` =
|
|
14667
|
+
core's `isPersistedRuleMandate` screen). Present only when the WHOLE cause of `mandated:true` is that one
|
|
14668
|
+
word; absence never names a word and is not "not mandated". Same value on the `livePending` row, the
|
|
14669
|
+
operator queue row and the inbox row; NOT on `card_json` / `approval_request`.
|
|
14263
14670
|
denialLimitFallback: { $ref: '#/components/schemas/DenialLimitFallback' }
|
|
14264
14671
|
parked:
|
|
14265
14672
|
type: boolean
|
|
@@ -14561,6 +14968,13 @@ components:
|
|
|
14561
14968
|
|
|
14562
14969
|
The SAME type is the `origin` member of `GateOutcome` on `tool_end` — one vocabulary, two faces.
|
|
14563
14970
|
|
|
14971
|
+
server >= 7.102.0 (S-755 / cli L-695 / C-R111): the word now also rides the `livePending` row top level
|
|
14972
|
+
(read once with the frame's) and the operator queue row (`GET /v1/approvals` `pending[]` + the `/stream`
|
|
14973
|
+
`pending` frame — the park-row twin seat, screened by core's `isAskOrigin`), besides the frame and the inbox
|
|
14974
|
+
row — five faces, one word. `card_json` / the `approval_request` frame still do not carry it (the card is
|
|
14975
|
+
`.strict()`). The eleven known words are exported at runtime as the SDK's `ASK_ORIGINS` (core 7.32.1
|
|
14976
|
+
`ASK_ORIGINS`, verbatim and in order) — known words, NOT an enforcement table.
|
|
14977
|
+
|
|
14564
14978
|
RuleOffersAbsence:
|
|
14565
14979
|
type: string
|
|
14566
14980
|
enum: [mandated, shadowed, lane_cannot_speak]
|
|
@@ -14578,6 +14992,26 @@ components:
|
|
|
14578
14992
|
server-side narrow read, so both faces carry identical values; a word outside the set is treated as
|
|
14579
14993
|
malformed and the key is not minted at all (the server never passes an unknown word through).
|
|
14580
14994
|
|
|
14995
|
+
PersistedRuleMandate:
|
|
14996
|
+
type: string
|
|
14997
|
+
enum: [operator_always, tool_marks, probe_mandate, probe_unanswered, write_protection, write_protection_unresolved]
|
|
14998
|
+
description: >
|
|
14999
|
+
WHICH WORD a mandated ask stands on (server >= 7.102.0 / S-721 / core 7.32.0 #1092) — core's
|
|
15000
|
+
`PERSISTED_RULE_MANDATES` six words, transcribed verbatim and in order (core 7.32.1
|
|
15001
|
+
`dist/core/ask-origin.d.ts:349`; the vocabulary's owner is core). Rides FOUR faces with one value: the
|
|
15002
|
+
`tool_approval` frame, the `livePending` row top level, the operator queue row (`GET /v1/approvals`
|
|
15003
|
+
`pending[]` + the `/v1/approvals/stream` `pending` frame) and the inbox row. NOT on `card_json` / the
|
|
15004
|
+
`approval_request` frame (live or reconnect replay — `ApprovalCardSchema` is `.strict()`), same as `mandated`.
|
|
15005
|
+
🔴 A TRUE CLOSED SET, deliberately unlike `AskOrigin`: on every face the server screens it through core's
|
|
15006
|
+
`isPersistedRuleMandate` (`approval-card.ts` `readClosedWordSeat`; the inbox face is screened by core's own
|
|
15007
|
+
`summarizeCheckpoint`) and an out-of-set word reads as ABSENT, never on the wire.
|
|
15008
|
+
🔴 ABSENCE NEVER NAMES A WORD and is NOT "not mandated": another door (governance / hook / ancestor) or more
|
|
15009
|
+
than one reason ⇒ absent; whether the ask is mandated is `mandated`. For an ENGINE-MINTED value, present ⇒
|
|
15010
|
+
`mandated` is true (core: present ⇔ that word is the bit's WHOLE reason); the converse does not hold. ⚠️ On the
|
|
15011
|
+
durable faces (queue row / inbox row) the server projects the two seats INDEPENDENTLY (it does not bind `mandate`
|
|
15012
|
+
to `mandated`, `approval-card.ts` `readClosedWordSeat`), so a hand-edited or generation-skewed row may carry one
|
|
15013
|
+
without the other — read `mandated` for the bit, never infer it from this word. Echo-only — the server never
|
|
15014
|
+
branches on the word.
|
|
14581
15015
|
DenialLimitKind:
|
|
14582
15016
|
type: string
|
|
14583
15017
|
enum: [consecutive, total]
|
|
@@ -15133,14 +15567,15 @@ components:
|
|
|
15133
15567
|
type: object
|
|
15134
15568
|
description: >
|
|
15135
15569
|
Decision-maker identity assertion (design/171 §5.1; the cross-repo source of truth is
|
|
15136
|
-
`@sema-agent/
|
|
15570
|
+
`@sema-agent/settings-schema` ActorAssertionWire — the SDK holds a value copy; the package was named
|
|
15571
|
+
`@sema-agent/registry-core` before 1.0.0).
|
|
15137
15572
|
|
|
15138
15573
|
NORMATIVE, not a style note: an ACTOR NEVER PARTICIPATES IN THE PERMISSION DECISION — authority always
|
|
15139
15574
|
belongs to the principal; this shape exists only for audit/echo/presentation. `id` is ALWAYS server-minted
|
|
15140
15575
|
(= the verified principal; an auth-off deployment mints the `"_"` sentinel), and a wire requester may
|
|
15141
15576
|
submit ONLY `label`.
|
|
15142
15577
|
required: [id]
|
|
15143
|
-
additionalProperties: false #
|
|
15578
|
+
additionalProperties: false # settings-schema's ActorAssertionWire is .strict()
|
|
15144
15579
|
properties:
|
|
15145
15580
|
id: { type: string, minLength: 1, maxLength: 256, description: 'Server-minted principal ("_" sentinel when auth is off). Never submittable by the requester.' }
|
|
15146
15581
|
label: { type: string, maxLength: 256, description: 'Unverified display text — the ONLY field a requester may submit (server redacts + bounds it). UNTRUSTED.' }
|
|
@@ -15151,7 +15586,7 @@ components:
|
|
|
15151
15586
|
description: >
|
|
15152
15587
|
Audit axis for which authorization path accepted the decision: `owner` (row owner) or `operator`
|
|
15153
15588
|
(explicit operator seat). CLOSED — verbatim-equal to the owning schema
|
|
15154
|
-
(
|
|
15589
|
+
(settings-schema ActorAssertionWire). Widening it here without widening the owner is copy drift.
|
|
15155
15590
|
|
|
15156
15591
|
AskDecisionBody:
|
|
15157
15592
|
type: object
|
|
@@ -15800,6 +16235,20 @@ components:
|
|
|
15800
16235
|
SAME projection as the `GET /v1/approvals` row (`projectPendingForWire`), declared here explicitly so
|
|
15801
16236
|
a stream consumer sees it typed instead of through the open index signature. Present ONLY when true;
|
|
15802
16237
|
absence = "not detected", never "confirmed clean" (see PendingCheckpoint.hasBidiControls).
|
|
16238
|
+
# sdk 11.4.0 (che-OV adversarial review [low] F5): the `pending` frame spreads the PendingCheckpoint row and the
|
|
16239
|
+
# `live_pending` frame (server >= 7.87.0) spreads the LivePendingRow — so the rows' park-row facts / mandate bit /
|
|
16240
|
+
# origin word ride these frames with the same names and values. Declared for the same reason as hasBidiControls.
|
|
16241
|
+
requiresRealApproval: { type: boolean, enum: [true], description: '`pending` / `live_pending` frames — see PendingCheckpoint / LivePendingRow.requiresRealApproval.' }
|
|
16242
|
+
mandated: { type: boolean, enum: [true], description: '`pending` / `live_pending` frames (server >= 7.101.0) — see the row schemas.' }
|
|
16243
|
+
mandate:
|
|
16244
|
+
allOf: [{ $ref: '#/components/schemas/PersistedRuleMandate' }]
|
|
16245
|
+
description: '`pending` / `live_pending` frames (server >= 7.102.0 / S-721) — see PendingCheckpoint.mandate / LivePendingRow.mandate.'
|
|
16246
|
+
origin:
|
|
16247
|
+
allOf: [{ $ref: '#/components/schemas/AskOrigin' }]
|
|
16248
|
+
description: '`pending` / `live_pending` frames (server >= 7.102.0 / S-755) — see PendingCheckpoint.origin / LivePendingRow.origin. OPEN set.'
|
|
16249
|
+
ruleOffersAbsence:
|
|
16250
|
+
allOf: [{ $ref: '#/components/schemas/RuleOffersAbsence' }]
|
|
16251
|
+
description: '`pending` frames only (server >= 7.100.0 / S-700) — see PendingCheckpoint.ruleOffersAbsence.'
|
|
15803
16252
|
|
|
15804
16253
|
ParkedDecideAccepted:
|
|
15805
16254
|
type: object
|