@sema-agent/sdk 17.2.0 → 18.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +163 -0
- package/dist/client.d.ts +3 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +4 -0
- package/dist/client.js.map +1 -1
- package/dist/errors.d.ts +19 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +19 -0
- package/dist/errors.js.map +1 -1
- package/dist/events.d.ts +14 -2
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/health.d.ts +95 -31
- package/dist/health.d.ts.map +1 -1
- package/dist/health.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/resources/admin.d.ts +65 -0
- package/dist/resources/admin.d.ts.map +1 -0
- package/dist/resources/admin.js +27 -0
- package/dist/resources/admin.js.map +1 -0
- package/dist/resources/approvals.d.ts +6 -3
- package/dist/resources/approvals.d.ts.map +1 -1
- package/dist/resources/approvals.js +4 -2
- package/dist/resources/approvals.js.map +1 -1
- package/dist/resources/assistant.d.ts +5 -4
- package/dist/resources/assistant.d.ts.map +1 -1
- package/dist/resources/assistant.js +5 -4
- package/dist/resources/assistant.js.map +1 -1
- package/dist/resources/leader.d.ts +7 -1
- package/dist/resources/leader.d.ts.map +1 -1
- package/dist/resources/leader.js +7 -1
- package/dist/resources/leader.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 +2 -1
- package/dist/resources/ops.js.map +1 -1
- package/dist/resources/rules.d.ts +5 -4
- package/dist/resources/rules.d.ts.map +1 -1
- package/dist/resources/rules.js.map +1 -1
- package/dist/settings.d.ts +2 -2
- package/dist/types.d.ts +68 -17
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/openapi.yaml +251 -37
- package/package.json +2 -2
package/openapi.yaml
CHANGED
|
@@ -184,6 +184,10 @@ tags:
|
|
|
184
184
|
description: v2 leader pipeline (gated; E2B + git push). NOT the default door-B brain.
|
|
185
185
|
- name: metrics
|
|
186
186
|
description: Worker health/cost (ops; uses metricsToken, not a principal).
|
|
187
|
+
- name: admin
|
|
188
|
+
description: >
|
|
189
|
+
Operator-only `/v1/admin/*` actions on THIS engine instance. Today: the drain endpoint (server >= 7.121.0 contract
|
|
190
|
+
body `DrainRequest` / receipt `DrainReceipt`, owned by `@sema-agent/settings-schema` `./fleet`).
|
|
187
191
|
|
|
188
192
|
paths:
|
|
189
193
|
|
|
@@ -3230,7 +3234,9 @@ paths:
|
|
|
3230
3234
|
Frames: `meta` ({type,version,mode:"approvals-delta",pollMs}), then `synced` ({type,count}) once the
|
|
3231
3235
|
first full snapshot has been emitted, then `pending`/`resolved` deltas; plus `heartbeat` ({type}) on the
|
|
3232
3236
|
keep-alive tick and a terminal `error` ({type,errorCode:"STREAM_MAX_DURATION",…}) when the 15-min cap
|
|
3233
|
-
fires.
|
|
3237
|
+
fires — or, server >= 7.122.0, `error` with `errorCode:"draining"` at the moment the instance enters drain (same code and
|
|
3238
|
+
sentence as the billable-submit 503 `draining`; the server closes the stream right after the frame, reconnect to the
|
|
3239
|
+
replacement instance). (Corrected 2026-07-31: this list used to name only meta/pending/resolved — a consumer written to
|
|
3234
3240
|
it silently drops three frame kinds it really receives.) Each data payload mirrors its SSE event name in
|
|
3235
3241
|
`data.type` — proxy-safe dispatch. Cross-replica by
|
|
3236
3242
|
construction (polls the SHARED checkpoint table). 15-min cap + heartbeats; a DB blip retries, never
|
|
@@ -3731,8 +3737,12 @@ paths:
|
|
|
3731
3737
|
`ErrorResponse`-shaped. Codes: "request.body_shape" (bad/missing `decision`, OR an unrecognised
|
|
3732
3738
|
top-level key — server >= 7.86.0 / S-438 key closure, the body carries `unknownKeys` /
|
|
3733
3739
|
`unsupportedKeys`) · "request.field_conflict" (`edit` without a non-empty `editedPlan`;
|
|
3734
|
-
`editedPlan` present on approve/reject; `permissionModeAfter` sent with `
|
|
3735
|
-
`permissionModeAfter` on a task
|
|
3740
|
+
`editedPlan` present on approve/reject; `permissionModeAfter` sent with `reject`;
|
|
3741
|
+
`permissionModeAfter` on a task whose stored permission mode is not `plan`) — match these two by CODE;
|
|
3742
|
+
server >= 7.122.0: `approve` and `edit` both carry the plan out of plan mode and both take the key, and a
|
|
3743
|
+
run's mode word has ONE source, the stored submit body (an operator `AUTONOMY=plan` task is stored as `plan`
|
|
3744
|
+
and takes the key); <= 7.121.x only `approve` took it and the second conflict read "not submitted with
|
|
3745
|
+
`permissionMode:"plan"`" ·
|
|
3736
3746
|
"request.field_invalid" (non-string `reason`; `permissionModeAfter` outside the two-word closed
|
|
3737
3747
|
set — zero widening arm) · "request.path_malformed" (a bad percent-encoded path segment —
|
|
3738
3748
|
server >= 7.86.0 / S-430 turned that family from 500 `internal.error` into a 400 across 16 doors).
|
|
@@ -4664,7 +4674,8 @@ paths:
|
|
|
4664
4674
|
(`LEADER_ENABLED` off) the answer depends on the server: server >= 7.116.0 mounts the route unconditionally and answers
|
|
4665
4675
|
**501 `capability.leader_endpoint_required`** (new code; under multi-tenant the identity gate's 401 still comes first);
|
|
4666
4676
|
<= 7.115.x did not register the route at all → the generic **404** `not_found.route`. Detect "leader unavailable" by
|
|
4667
|
-
`errorCode` (or the `capabilities.leader` bit
|
|
4677
|
+
`errorCode` (or the `capabilities.leader` bit — server >= 7.122.0 also reads false on a deployment whose operator runs `AUTONOMY=plan`, where a submit answers
|
|
4678
|
+
422 `request.autonomy_lane_refused` instead; see `Capabilities.leader`), not by the status alone.
|
|
4668
4679
|
|
|
4669
4680
|
|
|
4670
4681
|
🔴 IDEMPOTENCY (server >= 7.24.0): this POST now consumes the `Idempotency-Key` header — the header is
|
|
@@ -4713,6 +4724,20 @@ paths:
|
|
|
4713
4724
|
content:
|
|
4714
4725
|
application/json:
|
|
4715
4726
|
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
4727
|
+
'422':
|
|
4728
|
+
description: >-
|
|
4729
|
+
errorCode "request.autonomy_lane_refused" (server >= 7.122.0) — the deployment runs the operator `AUTONOMY=plan`: every task starts
|
|
4730
|
+
in plan mode and leaves it only when a person approves its plan through plan review, and a leader task's workers have no plan
|
|
4731
|
+
review channel, so they could neither write nor hand their plan to anyone who can approve it. REFUSED at the door, NO run created;
|
|
4732
|
+
a replay with the same `Idempotency-Key` gets the same 422 (the idempotency key is not consumed). The `capabilities.leader` bit
|
|
4733
|
+
reads false on such a deployment (the same judgement as this refusal) — read it, or `GET /v1/policy` `autonomy`, beforehand. Exits: submit the work as a run (`POST /v1/runs`, plan reviewed through
|
|
4734
|
+
`POST /v1/assistant/tasks/{taskId}/plan_review`), or ask the operator to set `AUTONOMY=read-only` or `ask` (leader tasks run
|
|
4735
|
+
there). Not the hosted-posture refusal (`request.host_posture_refused`): that one is the tenant axis, this one is the AUTONOMY
|
|
4736
|
+
axis. A change to `plan` after acceptance is caught where the run is born: the 202'd run ends with the same sentence in
|
|
4737
|
+
`GET /v1/leader/{leaderRunId}` `error` and no worker is started.
|
|
4738
|
+
content:
|
|
4739
|
+
application/json:
|
|
4740
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
4716
4741
|
'409':
|
|
4717
4742
|
description: >-
|
|
4718
4743
|
errorCode "conflict.leader_run_exists" (server >= 7.24.0) — your `Idempotency-Key` hit a leader run
|
|
@@ -5595,6 +5620,65 @@ paths:
|
|
|
5595
5620
|
'403': { description: 'Multi-tenant worker: wiring diagnostics are operator-only (`auth.operator_only`). With an EMPTY `OPERATOR_PRINCIPALS` the answer is instead 501 `capability.operator_principals_required` (server >= 7.116.0; any identity, ahead of authorization — branch on `errorCode`, not the status).' }
|
|
5596
5621
|
'404': { description: 'This worker serves no wiring diagnostics (older server, or a process not assembled by the composition root).' }
|
|
5597
5622
|
|
|
5623
|
+
/v1/admin/drain:
|
|
5624
|
+
parameters:
|
|
5625
|
+
- $ref: '#/components/parameters/PrincipalHeader'
|
|
5626
|
+
post:
|
|
5627
|
+
tags: [admin]
|
|
5628
|
+
operationId: adminDrain
|
|
5629
|
+
x-status: live # server >= 7.121.0 contract body; 7.35.0–7.120.x took a retired `{reason}` body.
|
|
5630
|
+
summary: Put THIS engine instance into draining by a deadline (operator-only).
|
|
5631
|
+
description: >
|
|
5632
|
+
Server >= 7.121.0. The body is the contract `DrainRequest` (owned by `@sema-agent/settings-schema` >= 9.0.0 `./fleet`), the answer
|
|
5633
|
+
the contract `DrainReceipt`. Entering drain: new work is refused (billable submits 503 `draining`; HITL answers — including the
|
|
5634
|
+
durable `/decide` — and resumes are ADMITTED), `GET /readyz` turns 503, preemptible in-flight legs park durably at their next clean
|
|
5635
|
+
turn boundary, live approval cards are re-routed to durable parks; the engine stops itself when in-flight reaches zero or at
|
|
5636
|
+
`deadlineAt` (fixed when entered — a later hot change to the drain window does not move it). After a drain entered through this
|
|
5637
|
+
endpoint, the FIRST stop signal the platform sends is absorbed (deadline unchanged) and only a later one, at least the minimum gap
|
|
5638
|
+
apart, hard-stops — so the platform stop timeout (Docker `stop_grace_period`, systemd `TimeoutStopSec`, k8s
|
|
5639
|
+
`terminationGracePeriodSeconds`) must be >= the requested deadline.
|
|
5640
|
+
IDENTITY — the request names WHICH instance, compared field by field (no state change on a mismatch, 409 `conflict.fleet_identity`
|
|
5641
|
+
naming the field, never echoing the value): `worker` = the engine's worker name (`SEMA_REGISTRY_WORKER`; an engine without a center
|
|
5642
|
+
lane has none, so every request mismatches); `expectedGeneration` = the fleet generation (`/health.generation`), ABSENT AGAINST ABSENT
|
|
5643
|
+
(omitting it is the standalone form, not a wildcard — it mismatches a fleet member); `scope` = the tenant scope, both sides read as a
|
|
5644
|
+
value (the engine's = env `FLEET_SCOPE`; unset on the engine and omitted in the request both read as the default scope `global`);
|
|
5645
|
+
`instanceId` (`/health.instanceId`) is compared only when present.
|
|
5646
|
+
IDEMPOTENT — the same `actionId` (or any other action) while already draining answers 200 `already_draining` and echoes the FIRST
|
|
5647
|
+
drain's `since` / `deadlineAt`, changing nothing. Clients do not auto-retry this POST; re-send with the same `actionId` to retry.
|
|
5648
|
+
RETIRED (zero alias): the 7.35.0–7.120.x `{reason}` "shutdown reason declaration" body (it only recorded a sentence and never
|
|
5649
|
+
drained) now answers 400 `request.field_invalid`; `/health.drainReason` and the `reason` key on 503 `draining` bodies are gone too.
|
|
5650
|
+
Gate order (same as every operator face): identity -> authorization -> body shape -> drain entry -> four-part identity.
|
|
5651
|
+
requestBody:
|
|
5652
|
+
required: true
|
|
5653
|
+
content:
|
|
5654
|
+
application/json:
|
|
5655
|
+
schema: { $ref: '#/components/schemas/DrainRequest' }
|
|
5656
|
+
responses:
|
|
5657
|
+
'200':
|
|
5658
|
+
description: Draining (this call entered it) or already draining (the first drain's facts, unchanged).
|
|
5659
|
+
content:
|
|
5660
|
+
application/json:
|
|
5661
|
+
schema: { $ref: '#/components/schemas/DrainReceipt' }
|
|
5662
|
+
'400': { $ref: '#/components/responses/BadRequest' } # request.field_invalid — the body is not a DrainRequest (including the retired `{reason}` form); nothing was changed
|
|
5663
|
+
'401': { $ref: '#/components/responses/Unauthorized' } # auth.unauthorized (credential gate) / auth.principal_required (REQUIRE_PRINCIPAL deployment, no usable identity)
|
|
5664
|
+
'403': { description: '`auth.operator_only` — OPERATOR_PRINCIPALS is non-empty and the caller is not in it.' }
|
|
5665
|
+
'409':
|
|
5666
|
+
description: >-
|
|
5667
|
+
`conflict.fleet_identity` (server >= 7.121.0) — the request's four-part identity (`scope` / `worker` / `expectedGeneration` /
|
|
5668
|
+
`instanceId`) does not match this engine; the sentence names the mismatched fields (never the values). Nothing was changed.
|
|
5669
|
+
Compare with the target engine's `GET /health` (`instanceId` / `generation`), its worker name and `FLEET_SCOPE`, then re-send.
|
|
5670
|
+
content:
|
|
5671
|
+
application/json:
|
|
5672
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
5673
|
+
'501':
|
|
5674
|
+
description: >-
|
|
5675
|
+
`capability.operator_principals_required` — OPERATOR_PRINCIPALS is empty, so no identity is an operator on this deployment (any
|
|
5676
|
+
deployment shape, ahead of authorization). `capability.drain_state_required` — the host has no shutdown chain wired (an embedded
|
|
5677
|
+
engine), so there is no drain to enter (answered after the body check). Branch on `errorCode`.
|
|
5678
|
+
content:
|
|
5679
|
+
application/json:
|
|
5680
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
5681
|
+
|
|
5598
5682
|
/v1/sendfile-links:
|
|
5599
5683
|
parameters:
|
|
5600
5684
|
- $ref: '#/components/parameters/PrincipalHeader'
|
|
@@ -5804,7 +5888,7 @@ paths:
|
|
|
5804
5888
|
content:
|
|
5805
5889
|
application/json:
|
|
5806
5890
|
schema: { $ref: '#/components/schemas/CcImportPrepareResult' }
|
|
5807
|
-
'400': { $ref: '#/components/responses/BadRequest' } # request.body_shape — not {layers:[{layer,path,root,content}]}, or a layer `root` the server does not accept (server >= 7.120.0: not a complete absolute path — see RuleScope; sentence "
|
|
5891
|
+
'400': { $ref: '#/components/responses/BadRequest' } # request.body_shape — not {layers:[{layer,path,root,content}]}, or a layer `root` the server does not accept (server >= 7.120.0: not a complete absolute path — see RuleScope; sentence "layers[<i>].root must be an absolute path" on >= 7.121.0, the scope sentence on 7.120.x; no ticket minted; <= 7.119.x: an empty `root`, answered with the body-shape sentence)
|
|
5808
5892
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
5809
5893
|
'413': { $ref: '#/components/responses/PayloadTooLarge' } # request.payload_too_large — more than 200 candidates across all submitted layers; SHORTEN and resend (retrying the same payload cannot help)
|
|
5810
5894
|
'429': { $ref: '#/components/responses/RateLimited' }
|
|
@@ -6589,7 +6673,12 @@ components:
|
|
|
6589
6673
|
⚠️ On the billable submit set (every POST that starts a model turn — the server's
|
|
6590
6674
|
`isBillableSubmitPath`, which is wider than the three task/run endpoints) this
|
|
6591
6675
|
503 slot is SHARED with producers that are not auth at all, so `errorCode` — not the status — is the
|
|
6592
|
-
branch key: `draining` (this replica is shutting down; retry against a replacement -> DrainingError
|
|
6676
|
+
branch key: `draining` (this replica is shutting down; retry against a replacement -> DrainingError; server >= 7.121.0
|
|
6677
|
+
refuses only NEW work while draining — HITL answers, including the durable `/decide`, and resumes are admitted — and the body
|
|
6678
|
+
carries no `reason` key any more),
|
|
6679
|
+
`state.lease_expired` (server >= 7.121.0: this fleet member's serving lease has expired and the center has been unreachable
|
|
6680
|
+
for the deployment's `FLEET_LEASE_OUTAGE_MAX_MS`; new work only — HITL answers and resumes pass, in-flight runs are untouched;
|
|
6681
|
+
it lifts when the center grants again; retry later or route elsewhere -> ServiceStateError),
|
|
6593
6682
|
`state.model_roster_pending` (roster not loaded yet; retry -> ServiceStateError), and (server >=7.0.0,
|
|
6594
6683
|
synchronous `POST /v1/tasks` only) `memory.admission_required` — the org-memory admission directory is
|
|
6595
6684
|
transiently undecidable, refused fail-closed BEFORE any model call, mapped to MemoryAdmissionError.
|
|
@@ -6612,7 +6701,7 @@ components:
|
|
|
6612
6701
|
schema: { type: integer }
|
|
6613
6702
|
description: >
|
|
6614
6703
|
Seconds to wait before retrying. Presence is per producer, not per status:
|
|
6615
|
-
`draining` always sends it (15), `state.model_roster_pending` always sends it (5),
|
|
6704
|
+
`draining` always sends it (15), `state.model_roster_pending` always sends it (5), `state.lease_expired` always sends it (60),
|
|
6616
6705
|
`memory.admission_required` sends it ONLY when the engine supplied a hint — a steady-state refusal
|
|
6617
6706
|
(no resolver wired) honestly carries neither this header nor the body's `retryAfterSec`.
|
|
6618
6707
|
The auth legs (401 bad token / 503 missing token) never send it.
|
|
@@ -7138,7 +7227,12 @@ components:
|
|
|
7138
7227
|
`config.permission_mode_unavailable`. `bypassPermissions` RELEASES the ten releasable ask classes (server >= 7.115.0: the tenth is `unstated`, a server-tool call nobody stated)
|
|
7139
7228
|
and DISCLOSES each (`tool_end.gate.disposition.released` + one `engine_notice` `permission.ask_released_by_mode` per (mode, class) per run);
|
|
7140
7229
|
immune classes (deployment-authored, ask / org rules, hooks, ancestors, questions …) still ask; a write whose protection
|
|
7141
|
-
cannot be judged is refused (`deniedBy: mode`)
|
|
7230
|
+
cannot be judged is refused (`deniedBy: mode`) on the file tools — and, from server >= 7.122.0 / core 7.47.0, RELEASED on the SHELL face
|
|
7231
|
+
(an eleventh class, `write_protection_unresolved`, for a caller-supplied tool whose wire name is exactly `Bash` or `Monitor` and which
|
|
7232
|
+
declares a write-path target; see `ModeRelease.reason`). `plan` (server >= 7.122.0): the engine's plan mode and nothing the service adds —
|
|
7233
|
+
the tool table equals `default`'s, the engine mounts the plan-presenting tool, and a write or any non-read-only call is asked AT CALL TIME by the
|
|
7234
|
+
engine's plan gate (a card where somebody can answer, a refusal where nobody can; a delegated sub-agent inherits plan as its ceiling); up to
|
|
7235
|
+
7.121.x the service also mapped `plan` to read-only hands, withheld the delegation tool and refused `Workflow`. Request vocabulary: SIX words (server >= 7.119.0) — `dontAsk`, the engine's
|
|
7142
7236
|
"auto-refuse" mode, is accepted and passes through verbatim: the ENGINE refuses the calls that would ask (no card, no parked row,
|
|
7143
7237
|
`tool_end.gate.disposition = { kind: denied, deniedBy: mode, mode: dontAsk, … }`), the run ends normally, and it is never looser
|
|
7144
7238
|
than `default`. One exception: a PreToolUse hook's OWN ask, when no other class in that ask's set backs it, is still handed to a person
|
|
@@ -7148,7 +7242,7 @@ components:
|
|
|
7148
7242
|
hold for <= 7.105.0 only.
|
|
7149
7243
|
CC-parity permission-mode INTENT — the values THIS wire's closed submit-gate accepts (the first five on server <= 7.118.x,
|
|
7150
7244
|
plus `dontAsk` from 7.119.0 = the engine's whole mode vocabulary, `capabilities.permissionModes`). The frontend (TUI shell / web portal) carries the RAW mode; the SERVICE interprets it TIGHTEN-ONLY vs the deployment baseline:
|
|
7151
|
-
`plan` ⇒ mount present_plan (core enablePlanMode) + read-only hands (CC EnterPlanMode research);
|
|
7245
|
+
`plan` ⇒ mount present_plan (core enablePlanMode) + read-only hands (CC EnterPlanMode research) — that is the <= 7.121.x reading; server >= 7.122.0: see the `plan` sentence in the first block;
|
|
7152
7246
|
`default` adds the manual ask gate on non-exempt writes (scratchpad dirs / remembered session
|
|
7153
7247
|
exemptions still auto-allow — not literally every Write/Edit); the server emits the SAME gate-policy
|
|
7154
7248
|
for `auto` as for `default` — sending `auto` is NOT itself what arms core's auto-mode classifier; that
|
|
@@ -7250,6 +7344,22 @@ components:
|
|
|
7250
7344
|
Pin a SEPARATE (usually cheaper) model for compaction. Validated against the catalog on submit — an
|
|
7251
7345
|
unknown ref is a 400, not a silent fallback to the main model's price.
|
|
7252
7346
|
appendSystemPrompt: { type: string, description: Text appended to the assembled system prompt for this task. }
|
|
7347
|
+
outputStyle:
|
|
7348
|
+
type: object
|
|
7349
|
+
required: [name]
|
|
7350
|
+
additionalProperties: false
|
|
7351
|
+
description: >-
|
|
7352
|
+
Server >= 7.121.0 (send only when `capabilities.outputStyle` is true; an older server answers 400 `request.body_shape` for the
|
|
7353
|
+
top-level key): the output style's PER-TURN line, handed verbatim to the engine's seat of the same name. Each attachment cycle the
|
|
7354
|
+
engine states "<name> output style is active. <turnReminder>" in its own marker frame (the engine's default sentence when
|
|
7355
|
+
`turnReminder` is absent), echoed on the stream as `steering_injected` with `source: "output_style"`. One fact, one seat: the
|
|
7356
|
+
style's BODY (the guide text) still goes in `settings.outputStyle`; this key carries only the name and the per-turn line.
|
|
7357
|
+
The value's owner is the engine (exactly these two keys, `name` non-empty and at most 256 characters, `turnReminder` a non-empty
|
|
7358
|
+
string when present); the server does not judge it — a bad value is accepted and refused at prepare, the run ends `failed` with
|
|
7359
|
+
code `config.output_style_invalid` (never silently ignored).
|
|
7360
|
+
properties:
|
|
7361
|
+
name: { type: string, minLength: 1, maxLength: 256 }
|
|
7362
|
+
turnReminder: { type: string, minLength: 1 }
|
|
7253
7363
|
promptProfile:
|
|
7254
7364
|
type: string
|
|
7255
7365
|
enum: [simple, classic]
|
|
@@ -8993,7 +9103,16 @@ components:
|
|
|
8993
9103
|
asyncRuns: { type: boolean }
|
|
8994
9104
|
artifacts: { type: boolean }
|
|
8995
9105
|
approvals: { type: boolean }
|
|
8996
|
-
leader:
|
|
9106
|
+
leader:
|
|
9107
|
+
type: boolean
|
|
9108
|
+
description: >-
|
|
9109
|
+
The `POST /v1/leader` lane. server >= 7.122.0 reads the conjunction of two facts: the leader face is mounted (`LEADER_ENABLED` etc.) AND the
|
|
9110
|
+
operator entry floor takes leader submissions — the same judgement as the 422 `request.autonomy_lane_refused` at the door (a leader task's
|
|
9111
|
+
workers have no plan review channel). So on a deployment whose operator runs `AUTONOMY=plan` the bit reads false and a direct submit still
|
|
9112
|
+
answers 422 `request.autonomy_lane_refused`; with `AUTONOMY=read-only` / `ask` / unset the bit follows the face. A false bit from an absent face
|
|
9113
|
+
answers 501 `capability.leader_endpoint_required` on submit (404 `not_found.route` on <= 7.115.x) — tell the two falses apart by the submit's
|
|
9114
|
+
`errorCode`, or read `GET /v1/policy` `autonomy` beforehand. <= 7.121.x (historical reading): the bit read the face only — true on a `plan`
|
|
9115
|
+
deployment, no prediction of the refusal.
|
|
8997
9116
|
version: { type: string }
|
|
8998
9117
|
scenarios:
|
|
8999
9118
|
type: array
|
|
@@ -9221,6 +9340,8 @@ components:
|
|
|
9221
9340
|
bgNotifyFailClosed: { type: boolean }
|
|
9222
9341
|
steerPriority: { type: string }
|
|
9223
9342
|
hookFailureNotice: { type: boolean, description: 'server >= 7.48.0 (#281): this binary emits a SECOND `hook_notice` kind, `hook_non_blocking_failure` (the user''s own hook broke: exit != 0 and != 2 / timeout / spawn failure / bad JSON). Absent = an older worker that only emits `hook_decision_unavailable` — branch by `kind`, never crash on an unknown one.' }
|
|
9343
|
+
leaseClient: { type: boolean, description: 'server >= 7.121.0, a version bit (always true, rides with the `fleet` object): this binary carries the serving-lease CLIENT — when the engine is a fleet member (`FLEET_GENERATION`) and the center declares in its heartbeat reply that it answers renewals (`servingLease`), the engine renews and is governed by the lease. Deliberately NOT named `servingLease` (that is the center''s bit): this says the client exists, not that a lease is in force — read `/health.leaseState` for that. Absent = an older worker.' }
|
|
9344
|
+
generationEcho: { type: boolean, description: 'server >= 7.121.0, a version bit (always true, rides with the `fleet` object): this binary echoes env `FLEET_GENERATION` as `generation` on the heartbeat and on `/health` (with `leaseState` / `leaseUntil`), and the drain endpoint `POST /v1/admin/drain` compares the four-part identity including `expectedGeneration`. Absent = an older worker.' }
|
|
9224
9345
|
workspace:
|
|
9225
9346
|
description: >
|
|
9226
9347
|
#3 (server 1.299–7.51): workspace-browse capability family — an OBJECT when the E19 snapshot-store
|
|
@@ -9257,6 +9378,13 @@ components:
|
|
|
9257
9378
|
effortSelection: { type: boolean, description: "`reasoningEffort` accepted per request." }
|
|
9258
9379
|
compactionModel: { type: boolean, description: "A separate model may be pinned for compaction." }
|
|
9259
9380
|
appendSystemPrompt: { type: boolean, description: "Per-request system-prompt append is honoured." }
|
|
9381
|
+
outputStyle:
|
|
9382
|
+
type: boolean
|
|
9383
|
+
description: >-
|
|
9384
|
+
server >= 7.121.0, hardcoded true (a predicate-class bit, same family as `approvalDecidedBy` / `sessionReadRedaction`): the
|
|
9385
|
+
top-level request key TaskRequest.outputStyle (the output style's per-turn line) is accepted and handed verbatim to the engine.
|
|
9386
|
+
Send the key only when this is present; absent = an older server, which answers 400 for it. Not the same thing as
|
|
9387
|
+
`taskSettings.outputStyle` (that bit says `settings.outputStyle`, the style BODY, is accepted) — two seats, two facts.
|
|
9260
9388
|
toolOutput: { type: boolean, description: "`tool_end` carries the model-facing output." }
|
|
9261
9389
|
messageIdentity: { type: boolean, description: "Content events carry `eventId` (+ `parentToolCallId` for sub-agents)." }
|
|
9262
9390
|
forwardSubagentEvents: { type: boolean, description: "Sub-agent events are forwarded onto the parent stream." }
|
|
@@ -9835,13 +9963,16 @@ components:
|
|
|
9835
9963
|
taskWriteFaceOpen:
|
|
9836
9964
|
type: boolean
|
|
9837
9965
|
description: >
|
|
9838
|
-
server >= 7.95.0 (S-591; value meaning refined at 7.96.0 / S-613; mint `routes/capabilities.ts
|
|
9839
|
-
`taskWriteFaceRefusal(deps.config) === undefined &&
|
|
9966
|
+
server >= 7.95.0 (S-591; value meaning refined at 7.96.0 / S-613; mint `routes/capabilities.ts` =
|
|
9967
|
+
`taskWriteFaceRefusal(deps.config) === undefined && autonomyKeepsOpenWriteFace(deps.config.autonomy)` from server >= 7.122.0;
|
|
9968
|
+
up to 7.121.x the right half was `autonomyOverrides(deps.config.autonomy).writeFace !== "roots"`)
|
|
9840
9969
|
— DISCLOSURE BIT OF THE WRITE-CONTAINMENT FACE: does this deployment honour the task-level "open the write
|
|
9841
9970
|
fence" declaration (`permissionMode:"bypassPermissions"` ⇒ `TaskSpec.writeFace:"open"`, writes outside the
|
|
9842
9971
|
workspace roots)? `false` has two forms: (1) the hosted-posture gate refuses ⇒ sending that mode gets
|
|
9843
|
-
`422 request.host_posture_refused`; (2) the deployment runs `AUTONOMY=read-only
|
|
9844
|
-
accepted but the write face is clamped back to roots — the declaration silently does nothing.
|
|
9972
|
+
`422 request.host_posture_refused`; (2) the deployment runs `AUTONOMY=read-only` ⇒ the request is
|
|
9973
|
+
accepted but the write face is clamped back to roots — the declaration silently does nothing; server >= 7.122.0: `AUTONOMY=plan`
|
|
9974
|
+
reads `false` too, but because the entry mode word is clamped to `plan` at admission (the engine's plan mode runs instead of
|
|
9975
|
+
`bypassPermissions`; up to 7.121.x it was the same read-only-hands + roots clamp as `AUTONOMY=read-only`, and a hosted deployment answered 422 `request.host_posture_refused` where it now accepts the request into plan). Three states
|
|
9845
9976
|
are folded into one bit on purpose: the caller has exactly one decision (send that key or not); tier and
|
|
9846
9977
|
evidence live in the refusal body and the operator's `GET /v1/diagnostics/wiring`. It speaks ONLY for the
|
|
9847
9978
|
write-containment cell — the other two columns of `bypassPermissions` are unaffected.
|
|
@@ -12755,8 +12886,9 @@ components:
|
|
|
12755
12886
|
REQUIRED iff `decision==="edit"` (FORBIDDEN otherwise → 400).
|
|
12756
12887
|
🔴 THE BODY KEY SET IS CLOSED (server >= 7.86.0 / S-438): an unrecognised top-level key is refused with
|
|
12757
12888
|
400 `request.body_shape` plus the `unknownKeys` / `unsupportedKeys` machine tables — refused rather
|
|
12758
|
-
than dropped, because a misspelled `permissionModeAfter` would otherwise silently
|
|
12759
|
-
|
|
12889
|
+
than dropped, because a misspelled `permissionModeAfter` would otherwise silently fold to `default`
|
|
12890
|
+
(the task keeps asking before each write after its plan was approved) while the caller believes the
|
|
12891
|
+
mode was settled.
|
|
12760
12892
|
required: [decision]
|
|
12761
12893
|
additionalProperties: false
|
|
12762
12894
|
properties:
|
|
@@ -12767,18 +12899,35 @@ components:
|
|
|
12767
12899
|
type: string
|
|
12768
12900
|
enum: [default, acceptEdits]
|
|
12769
12901
|
description: >
|
|
12770
|
-
server >= 7.86.0 (S-433, P1
|
|
12771
|
-
|
|
12772
|
-
|
|
12773
|
-
|
|
12774
|
-
|
|
12775
|
-
|
|
12902
|
+
server >= 7.86.0 (S-433, P1) — WHICH PERMISSION MODE THIS TASK CONTINUES IN once the plan is approved.
|
|
12903
|
+
`acceptEdits` = writes stop asking; `default` = keep asking (AND is the folded value when the key is
|
|
12904
|
+
absent, so an older shell executes plans unchanged). The decision writes the mode back into the task's
|
|
12905
|
+
stored submit body, so every later park -> resume continues in it and never falls back to plan.
|
|
12906
|
+
🔴 server >= 7.122.0 — ONE JUDGE, ONE SOURCE: plan is only the engine's `permissionMode:"plan"`. Since 7.122.0
|
|
12907
|
+
the service adds no read-only clamp of its own, so there is none to lift: the tool table equals `default`'s,
|
|
12908
|
+
and a write or any non-read-only call is asked (somebody can answer) or refused (nobody can) AT CALL TIME by
|
|
12909
|
+
the engine's plan gate. A run's mode word has ONE source, the stored submit body; its two writers are the submit door
|
|
12910
|
+
and this write-back. A decision that carries the plan out of plan mode — `approve` (the original plan) or
|
|
12911
|
+
`edit` (the person's revised plan; the engine proceeds with it) — writes this key back (absent => `default`);
|
|
12912
|
+
only `reject` (the review goes back to redo the plan, plan mode stays) does not. Before 7.122.0 the service
|
|
12913
|
+
also mapped plan to read-only hands; this key was added in 7.86.0 because, before it, approving a plan was a
|
|
12914
|
+
BLANK CHEQUE (the plan was approved while the read-only clamp stayed on and every write kept asking); and on
|
|
12915
|
+
7.86.0-7.121.x `edit` + this key was a 400 while `edit` itself wrote back `plan`, the continuation still held
|
|
12916
|
+
by the read-only hands. All of that is gone since 7.122.0.
|
|
12917
|
+
(A deployment's `AUTONOMY=read-only` static fence is a separate thing: since 7.122.0 it is all the service's governance
|
|
12918
|
+
layer re-folds on each resume, it has nothing to do with approving a plan, and approval does not lift it.)
|
|
12919
|
+
🔴 THREE 400s, each with its own code (match by CODE, not by sentence — the two `request.field_conflict`
|
|
12920
|
+
sentences were reworded in 7.122.0, codes unchanged): a value outside the two-word closed set =>
|
|
12776
12921
|
`request.field_invalid` (ZERO widening arm — this bit decides whether the model has hands after
|
|
12777
12922
|
approval, so folding a misspelling into either mode is a silent downgrade on the security axis);
|
|
12778
|
-
sending it with `
|
|
12779
|
-
|
|
12780
|
-
settled); sending it for a task
|
|
12781
|
-
|
|
12923
|
+
sending it with `reject` => `request.field_conflict`, server sentence `permissionModeAfter is only valid with a
|
|
12924
|
+
decision that carries the plan out ('approve' or 'edit'; got 'reject')` (a silent drop there would let the caller
|
|
12925
|
+
believe the mode was settled); sending it for a task whose STORED permission mode is not `plan` (the model
|
|
12926
|
+
entered plan mode itself, so approving returns it to the mode it was in before planning) =>
|
|
12927
|
+
`request.field_conflict`, server sentence `permissionModeAfter does not apply to this task: it was not
|
|
12928
|
+
started in plan mode (its stored permission mode is not "plan"), so approving the plan returns it to the mode
|
|
12929
|
+
it was in before planning`. A task STARTED in plan mode is one the request put there, or one an operator
|
|
12930
|
+
`AUTONOMY=plan` stamped at the submit door (its stored word is `plan`): the key is accepted for both.
|
|
12782
12931
|
⚠️ DIRECT-DOOR deployments: this key rides the HMAC envelope's TRAILING EXTENSION OBJECT (server
|
|
12783
12932
|
7.87.0: `{answer?, permissionModeAfter?}`, present keys in lexicographic order; 7.86.0's bare
|
|
12784
12933
|
trailing slot is DELETED with zero double-read) ⇒ a signer must sign the new shape, and mixed
|
|
@@ -13624,6 +13773,14 @@ components:
|
|
|
13624
13773
|
`writeFace: open`; read `capabilities.taskWriteFaceOpen` first); (2) server >= 7.106.0 / S-895: `inheritEnv: "all"` on a
|
|
13625
13774
|
hosted deployment (`REQUIRE_PRINCIPAL=true`; reach = the hosted posture only; read `capabilities.projectContext` first).
|
|
13626
13775
|
Remove the key (or send `inheritEnv: "scrub"`) and resend. Resume legs fold it into 409 `resume_blocked_by_policy`.
|
|
13776
|
+
🔴 `request.autonomy_lane_refused` (422, server >= 7.122.0): the deployment's operator `AUTONOMY` does not take tasks on this LANE.
|
|
13777
|
+
Today's only trigger is `AUTONOMY=plan` × `POST /v1/leader` — plan leaves plan mode only through a person approving the plan (plan
|
|
13778
|
+
review), a leader task's workers have no plan review channel, so the refusal is at the door and NO run is created (a replay with the
|
|
13779
|
+
same `Idempotency-Key` gets the same 422 and does not consume the key). Same family as `host_posture_refused` but a different axis:
|
|
13780
|
+
that one is the hosted / tenant posture axis (remove the key and resend); this one is the AUTONOMY axis (nothing to remove — submit
|
|
13781
|
+
as a run via `POST /v1/runs`, or ask the operator for `AUTONOMY=read-only` / `ask`, under which leader tasks run). Read the live
|
|
13782
|
+
config: a hot change takes effect on the next request; read `GET /v1/policy` `autonomy` beforehand (the `capabilities.leader` bit
|
|
13783
|
+
reads false on such a deployment).
|
|
13627
13784
|
error: { type: string }
|
|
13628
13785
|
errorMessage: { type: string }
|
|
13629
13786
|
activeTaskId:
|
|
@@ -14362,7 +14519,9 @@ components:
|
|
|
14362
14519
|
bypass-IMMUNE (not releasable).
|
|
14363
14520
|
CLOSED on the gate record (screened with core `isAskClass`). `bypassPermissions` releases only the ten RELEASABLE classes
|
|
14364
14521
|
(`transcript_write` / `rule_unreadable` / `probe` / `write_protection` / `tool_marks_mcp` / `tool_marks_a2a` /
|
|
14365
|
-
`artifact_shared_read` / `mode` / `unstated` / `ordinary`)
|
|
14522
|
+
`artifact_shared_read` / `mode` / `unstated` / `ordinary`) — on every face — plus, from server >= 7.122.0 / core 7.47.0, an eleventh on the SHELL
|
|
14523
|
+
face only: `write_protection_unresolved` (core `releasableAskClassesFor(face)`: shell 11, other faces 10; on the file tools that class is
|
|
14524
|
+
refused, `deniedBy: mode`); every other class (deployment-authored `operator_forced`, ask / org rules, hook,
|
|
14366
14525
|
ancestor, content question, …) asks under every mode.
|
|
14367
14526
|
ModeRelease:
|
|
14368
14527
|
type: object
|
|
@@ -14384,8 +14543,19 @@ components:
|
|
|
14384
14543
|
mandate: { $ref: '#/components/schemas/PersistedRuleMandate' }
|
|
14385
14544
|
reason:
|
|
14386
14545
|
type: string
|
|
14387
|
-
enum: [rule_unreadable]
|
|
14388
|
-
description:
|
|
14546
|
+
enum: [rule_unreadable, write_protection_unresolved]
|
|
14547
|
+
description: >
|
|
14548
|
+
WHAT the release went over — one word: the FIRST member (in core `MODE_RELEASE_REASONS` array order) that the ask's class
|
|
14549
|
+
set holds; ABSENT when the set holds none. CLOSED set — the server screens it with core `isModeReleaseReason`, so a word
|
|
14550
|
+
outside it withholds the whole `gate` from the frame (and a consumer that dispatches on the word must learn each new one).
|
|
14551
|
+
`rule_unreadable` = the release went over a rule this call could not be read against (the rule store was unreadable — a
|
|
14552
|
+
security-axis fail-open direction the server discloses on its own).
|
|
14553
|
+
`write_protection_unresolved` (server >= 7.122.0 / core 7.47.0) = the release went over a write whose target the
|
|
14554
|
+
write-protection judge could not RESOLVE (whether it lands on the protected table is unknown). It is released on the SHELL
|
|
14555
|
+
face only: a caller-supplied tool whose wire name is exactly `Bash` or `Monitor` and which declares a write-path target,
|
|
14556
|
+
under `bypassPermissions`; on the file tools the same unresolved write is still refused (`deniedBy: mode`). The engine's
|
|
14557
|
+
own `Bash` / `Monitor` cannot mint this class and the server mounts no such tool — it comes from a caller-embedded tool of
|
|
14558
|
+
those names. Before server 7.122.0 / core 7.47.0 the set was `rule_unreadable` alone.
|
|
14389
14559
|
|
|
14390
14560
|
GateClassifierAttribution:
|
|
14391
14561
|
# sdk 9.5.0:具名 —— 同一份形挂在 `GateDisposition` 的两只臂上,内联会立刻是两份会各自漂的镜像。
|
|
@@ -15509,6 +15679,17 @@ components:
|
|
|
15509
15679
|
was armed but declined/failed (check the store, check authorisation), `false` = there was no lane at all
|
|
15510
15680
|
(wire one up). The two recovery verbs differ, so a consumer MUST render them apart — NEVER fold them into
|
|
15511
15681
|
one "nobody approved it".
|
|
15682
|
+
`server.model_unreachable` (server-minted, audience `user`; server >= 7.108.0, `taskId` added in server 7.121.0) — a model call on
|
|
15683
|
+
this leg ended in error and its last request failed AT CONNECT (VPN switched mid-session / the proxy read at boot went stale / the
|
|
15684
|
+
gateway is gone) — not the provider's answer. `{ code, targetHost, proxyInUse?, remedy, sessionId, taskId? }`: `code` one of the
|
|
15685
|
+
connect-failure set (`ECONNREFUSED` / `ENOTFOUND` / `EAI_AGAIN` / `EHOSTUNREACH` / `ENETUNREACH` / `UND_ERR_CONNECT_TIMEOUT`),
|
|
15686
|
+
`targetHost` the model endpoint's `host:port` (a proxy address never rides this frame), `proxyInUse` present only when this hop
|
|
15687
|
+
went through a proxy and only as the variable NAME (`HTTP_PROXY` / `HTTPS_PROXY`), `remedy` a fixed sentence. `taskId`
|
|
15688
|
+
(server >= 7.121.0) = this leg's run resource id (streaming leg: `X-Task-Id` / the `meta` frame's `taskId`; background leg: the
|
|
15689
|
+
submit receipt's `taskId`; resume leg: the resumed run's id) — the same value as that run's terminal and its run-domain codes'
|
|
15690
|
+
`detail.taskId`; absent when the leg has no run resource (a streaming leg on a deployment without a run store) or on an older
|
|
15691
|
+
server. NO `runId` (the model-call layer cannot see the engine's run identity): a resume leg and its original leg share the
|
|
15692
|
+
`taskId`. Once per leg per target; it says "this endpoint is unreachable", not "this run failed".
|
|
15512
15693
|
`session.records_skipped` (K-24; server >= 7.104.0 / S-612 form B; contract §17.4 / appendix D.3) — 🔴 SERVER-MINTED
|
|
15513
15694
|
(not in core's register; owner, audience `user` and mint all live in the server). The session's saved log was
|
|
15514
15695
|
OPENED and some records could not be read and were skipped (file session backend only — both SQL backends refuse a
|
|
@@ -17767,13 +17948,16 @@ components:
|
|
|
17767
17948
|
🔴 Its arrival means the RUN IS STILL ALIVE — the 15-minute stream cap fired. The correct handling is to
|
|
17768
17949
|
RECONNECT with `Last-Event-ID` and keep reading (the durable leg stamps `id:` on every frame); rendering
|
|
17769
17950
|
it as a terminal would declare a live task dead. `done` / `failed` are the terminal arms; this one is not.
|
|
17770
|
-
Known `errorCode`: `STREAM_MAX_DURATION` (
|
|
17771
|
-
|
|
17951
|
+
Known `errorCode`: `STREAM_MAX_DURATION` (the 15-minute cap) · `draining` (server >= 7.122.0: the instance entered drain / is being
|
|
17952
|
+
replaced — each of the eight read-only subscription streams gets this frame at the moment drain begins and is then closed by the server;
|
|
17953
|
+
same code and sentence as the billable-submit 503 `draining`, same reconnect protocol: reconnect with `Last-Event-ID`, the replacement
|
|
17954
|
+
instance serves it; NOT a run failure; the same reason family as the cap — the server closes a stream for flow control)
|
|
17955
|
+
(open set — branch on the code, degrade unknown codes to the generic "reconnectable stream-control signal").
|
|
17772
17956
|
additionalProperties: false
|
|
17773
17957
|
required: [type, errorCode]
|
|
17774
17958
|
properties:
|
|
17775
17959
|
type: { const: error }
|
|
17776
|
-
errorCode: { type: string, description: 'STREAM_MAX_DURATION (open set).' }
|
|
17960
|
+
errorCode: { type: string, description: 'STREAM_MAX_DURATION | draining (server >= 7.122.0) (open set).' }
|
|
17777
17961
|
message: { type: string }
|
|
17778
17962
|
Event_question:
|
|
17779
17963
|
type: object
|
|
@@ -19593,6 +19777,33 @@ components:
|
|
|
19593
19777
|
The three user-editable CC settings layers this version reads (core `ImportedSettingsLayer`). The two
|
|
19594
19778
|
layers it does NOT read are named in `CcImportPreview.uncovered` rather than being silently absent.
|
|
19595
19779
|
|
|
19780
|
+
DrainRequest:
|
|
19781
|
+
type: object
|
|
19782
|
+
required: [actionId, worker, deadlineAt]
|
|
19783
|
+
description: >-
|
|
19784
|
+
The drain endpoint's request (contract `DrainRequest`, `@sema-agent/settings-schema` >= 9.0.0 `./fleet`): "put this instance into
|
|
19785
|
+
draining by this deadline". See `POST /v1/admin/drain` for how the identity fields are compared.
|
|
19786
|
+
properties:
|
|
19787
|
+
actionId: { type: string, minLength: 1, description: 'Idempotency key: the same id again answers `already_draining` and changes nothing. Hand-issued actions pick their own (e.g. `manual:<uuid>`).' }
|
|
19788
|
+
worker: { type: string, minLength: 1, description: The engine's worker name (`SEMA_REGISTRY_WORKER`). }
|
|
19789
|
+
deadlineAt: { type: integer, minimum: 0, description: Epoch milliseconds by which the engine stops on its own. }
|
|
19790
|
+
scope: { type: string, minLength: 1, description: 'The tenant scope; omitted = the default scope `global` (compared against env `FLEET_SCOPE`, unset = `global`).' }
|
|
19791
|
+
expectedGeneration: { type: string, pattern: '^(0|[1-9][0-9]*)$', description: 'The fleet generation as a canonical decimal string (`/health.generation`); absent against absent — omit it only for a non-member.' }
|
|
19792
|
+
instanceId: { type: string, minLength: 1, description: The engine's per-process identity (`/health.instanceId`); compared only when present. }
|
|
19793
|
+
term: { type: string, minLength: 1, description: The claim term the sending executor holds for this action (center-issued, opaque); absent on a direct or hand-issued call. }
|
|
19794
|
+
DrainReceipt:
|
|
19795
|
+
type: object
|
|
19796
|
+
required: [actionId, since, deadlineAt, state]
|
|
19797
|
+
additionalProperties: false
|
|
19798
|
+
description: >-
|
|
19799
|
+
The drain endpoint's answer (contract `DrainReceipt`): the engine's drain fact plus how this call found it. `state: draining` = this
|
|
19800
|
+
call entered drain; `already_draining` = it already was (including a drain the engine entered on its own), and the receipt reports the
|
|
19801
|
+
FIRST drain's facts.
|
|
19802
|
+
properties:
|
|
19803
|
+
actionId: { type: string, minLength: 1, description: The action that entered this drain. }
|
|
19804
|
+
since: { type: integer, minimum: 0, description: 'Epoch ms the drain began (the same value as `/health.drainingSince`).' }
|
|
19805
|
+
deadlineAt: { type: integer, minimum: 0, description: Epoch ms the engine stops on its own (fixed when the drain was entered). }
|
|
19806
|
+
state: { type: string, enum: [draining, already_draining] }
|
|
19596
19807
|
RuleScope:
|
|
19597
19808
|
description: >
|
|
19598
19809
|
Where a persisted rule applies (core `RuleScope`). `project.root` is the directory prefix that decides
|
|
@@ -19602,9 +19813,12 @@ components:
|
|
|
19602
19813
|
layer `root`, and the `project:<root>` discriminant string on write / revoke / the list filter):
|
|
19603
19814
|
server >= 7.120.0 accepts only a COMPLETE ABSOLUTE PATH — POSIX `/…`, a Windows drive root `X:\…` / `X:/…`,
|
|
19604
19815
|
or a UNC root `\\host\…` (the engine's durable-scope predicate; every server entry calls it rather than
|
|
19605
|
-
keeping a copy). A relative root (`proj`, `./x`, `~/x`) or a drive without a root (`C:`, `C:x`) is a 400
|
|
19606
|
-
`
|
|
19607
|
-
|
|
19816
|
+
keeping a copy). A relative root (`proj`, `./x`, `~/x`) or a drive without a root (`C:`, `C:x`) is a 400 — code
|
|
19817
|
+
`request.body_shape` on write / revoke / cc-import prepare, `request.query_invalid` on the list filter. Branch on `errorCode`;
|
|
19818
|
+
the sentence is for people: on write / revoke / the list filter the `error` is exactly "scope must be 'global' or
|
|
19819
|
+
'project:<root>' with an absolute root"; on cc-import prepare (whose body has no `scope` field) server >= 7.121.0 answers
|
|
19820
|
+
"layers[<i>].root must be an absolute path" (`<i>` = the first refused layer, from 0; same predicate), while 7.120.x
|
|
19821
|
+
answered with the scope sentence.
|
|
19608
19822
|
Server <= 7.119.x checks only that the root is non-empty and keeps relative roots as written; such rows take
|
|
19609
19823
|
no part in any check on 7.120.0 — SQL backends delete them with a one-time migration at boot, while on the
|
|
19610
19824
|
file (`local`) backend they stay in the store, are absent from the listing, cannot be revoked, and each run
|
|
@@ -19699,8 +19913,8 @@ components:
|
|
|
19699
19913
|
what is read is still only the allow bucket.
|
|
19700
19914
|
|
|
19701
19915
|
🔴 `root` follows the RuleScope rule (server >= 7.120.0: a complete absolute path; otherwise 400
|
|
19702
|
-
`request.body_shape`
|
|
19703
|
-
|
|
19916
|
+
`request.body_shape` and no ticket minted — the `error` is "layers[<i>].root must be an absolute path" on server >= 7.121.0,
|
|
19917
|
+
naming the first refused layer, and the scope sentence on 7.120.x). It applies to ALL layers alike — a `userSettings` layer's root never becomes a scope, but it is the
|
|
19704
19918
|
same field under the same check. On <= 7.119.x only an empty root is refused (with the body-shape sentence).
|
|
19705
19919
|
Its TRUTHFULNESS is deliberately NOT validated: the server has no such tree to check against, and pretending
|
|
19706
19920
|
to validate would be a lie. It is the user's own label for "which cwds should this rule be live under".
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "18.1.0",
|
|
4
4
|
"description": "Typed, zero-runtime-dependency SDK for the Sema agent fleet usage plane. The shared substrate for all doors (CC/Codex MCP façade + web). Server-side only — tokens never enter the browser.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "BUSL-1.1",
|
|
@@ -52,6 +52,6 @@
|
|
|
52
52
|
"prepublishOnly": "rm -f tsconfig.tsbuildinfo && npm run build && npm run typecheck --workspaces=false --prefix ../.. && npm test --workspaces=false --prefix ../.. && npm run prepack"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@sema-agent/settings-schema": "^
|
|
55
|
+
"@sema-agent/settings-schema": "^9.0.0"
|
|
56
56
|
}
|
|
57
57
|
}
|