@sema-agent/sdk 17.0.0 → 17.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +127 -1
- package/dist/device/index.d.ts +14 -0
- package/dist/device/index.d.ts.map +1 -1
- package/dist/device/index.js.map +1 -1
- package/dist/errors.d.ts +13 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +13 -2
- package/dist/errors.js.map +1 -1
- package/dist/events.d.ts +5 -0
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/health.d.ts +10 -1
- package/dist/health.d.ts.map +1 -1
- package/dist/health.js.map +1 -1
- package/dist/resources/devices.d.ts +2 -1
- package/dist/resources/devices.d.ts.map +1 -1
- package/dist/resources/devices.js +2 -1
- package/dist/resources/devices.js.map +1 -1
- package/dist/resources/rules.d.ts +25 -9
- package/dist/resources/rules.d.ts.map +1 -1
- package/dist/resources/rules.js.map +1 -1
- package/dist/resources/sessions.d.ts +5 -1
- package/dist/resources/sessions.d.ts.map +1 -1
- package/dist/resources/sessions.js +5 -1
- package/dist/resources/sessions.js.map +1 -1
- package/dist/settings.d.ts +7 -8
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +1 -1
- package/dist/transport.d.ts +3 -1
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +4 -1
- package/dist/transport.js.map +1 -1
- package/dist/types.d.ts +63 -25
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/openapi.yaml +122 -39
- package/package.json +1 -1
package/openapi.yaml
CHANGED
|
@@ -5804,7 +5804,7 @@ paths:
|
|
|
5804
5804
|
content:
|
|
5805
5805
|
application/json:
|
|
5806
5806
|
schema: { $ref: '#/components/schemas/CcImportPrepareResult' }
|
|
5807
|
-
'400': { $ref: '#/components/responses/BadRequest' } # request.body_shape — not {layers:[{layer,path,root,content}]}, or
|
|
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 "scope must be 'global' or 'project:<root>' with an absolute root", no ticket minted; <= 7.119.x: an empty `root`, answered with the body-shape sentence)
|
|
5808
5808
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
5809
5809
|
'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
5810
|
'429': { $ref: '#/components/responses/RateLimited' }
|
|
@@ -5931,8 +5931,8 @@ paths:
|
|
|
5931
5931
|
required: false
|
|
5932
5932
|
schema: { type: string, minLength: 1 }
|
|
5933
5933
|
description: >
|
|
5934
|
-
Filter to one scope, spelled `global` or `project:<root>`
|
|
5935
|
-
`request.query_invalid` (never silently unfiltered). Matching is done on the CANONICAL form, so an
|
|
5934
|
+
Filter to one scope, spelled `global` or `project:<root>` (which roots are accepted: see RuleScope). Unreadable
|
|
5935
|
+
or a root the server does not accept ⇒ 400 `request.query_invalid` (never silently unfiltered). Matching is done on the CANONICAL form, so an
|
|
5936
5936
|
equivalent-but-differently-spelled root filters to an empty page.
|
|
5937
5937
|
- name: limit
|
|
5938
5938
|
in: query
|
|
@@ -6015,7 +6015,7 @@ paths:
|
|
|
6015
6015
|
content:
|
|
6016
6016
|
application/json:
|
|
6017
6017
|
schema: { $ref: '#/components/schemas/RuleWriteResult' }
|
|
6018
|
-
'400': { $ref: '#/components/responses/BadRequest' } # request.field_invalid — `behavior: "allow"` (whole-sentence refusal, NO `reason` key), or a content test refused it (closed `reason` + human `detail`: rule_rejected / scope_bidi_controls / scope_control_chars / row_inconsistent / …, the SAME table the local-import preview answers with). request.body_shape — body is not {behavior, rule, scope, principal?}, or `scope` is not `global`/`project:<
|
|
6018
|
+
'400': { $ref: '#/components/responses/BadRequest' } # request.field_invalid — `behavior: "allow"` (whole-sentence refusal, NO `reason` key), or a content test refused it (closed `reason` + human `detail`: rule_rejected / scope_bidi_controls / scope_control_chars / row_inconsistent / …, the SAME table the local-import preview answers with). request.body_shape — body is not {behavior, rule, scope, principal?}, or `scope` is not `global`/`project:<root>` with a root the server accepts (see RuleScope; same sentence as DELETE)
|
|
6019
6019
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
6020
6020
|
'403': { $ref: '#/components/responses/Forbidden' } # auth.operator_only — writing another principal's rules without explicit OPERATOR_PRINCIPALS membership
|
|
6021
6021
|
'429': { $ref: '#/components/responses/RateLimited' }
|
|
@@ -6085,7 +6085,7 @@ paths:
|
|
|
6085
6085
|
content:
|
|
6086
6086
|
application/json:
|
|
6087
6087
|
schema: { $ref: '#/components/schemas/RuleRevokeResult' }
|
|
6088
|
-
'400': { $ref: '#/components/responses/BadRequest' } # request.body_shape — body is not {behavior, rule, scope, principal?} (server >= 7.67.0: `behavior` is REQUIRED and has no default), or `scope` is not `global`/`project:<
|
|
6088
|
+
'400': { $ref: '#/components/responses/BadRequest' } # request.body_shape — body is not {behavior, rule, scope, principal?} (server >= 7.67.0: `behavior` is REQUIRED and has no default), or `scope` is not `global`/`project:<root>` with a root the server accepts (see RuleScope)
|
|
6089
6089
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
6090
6090
|
'403': { $ref: '#/components/responses/Forbidden' } # auth.operator_only — revoking another principal's rule without explicit OPERATOR_PRINCIPALS membership
|
|
6091
6091
|
'429': { $ref: '#/components/responses/RateLimited' }
|
|
@@ -6339,7 +6339,7 @@ paths:
|
|
|
6339
6339
|
content:
|
|
6340
6340
|
application/json:
|
|
6341
6341
|
schema: { $ref: '#/components/schemas/DeviceEnrollResult' }
|
|
6342
|
-
'400': { $ref: '#/components/responses/BadRequest' } # request.body_shape (unknown key / missing required); request.field_invalid (platformOs outside the v1 closed set `darwin|linux` — a third value is never silently accepted; a field over its byte column — a silently truncated value is a DIFFERENT value)
|
|
6342
|
+
'400': { $ref: '#/components/responses/BadRequest' } # request.body_shape (unknown key / missing required); request.field_invalid (platformOs outside the v1 closed set `darwin|linux` — a third value is never silently accepted; a field over its byte column — a silently truncated value is a DIFFERENT value; server >= 7.120.0: `workspaceRoot` not an absolute POSIX path — the token is not consumed)
|
|
6343
6343
|
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
6344
6344
|
'403':
|
|
6345
6345
|
description: >
|
|
@@ -6598,6 +6598,13 @@ components:
|
|
|
6598
6598
|
declared exceeds the roster bound (name 128, contract id / revision 64, `modelGate` 64); the caller cannot route
|
|
6599
6599
|
around it and a verbatim retry never changes it (DETERMINISTIC — the SDK does not auto-retry these codes; they land
|
|
6600
6600
|
on ServiceStateError via the 503 tail, with no wait hint); only the deployment fixing its declaration helps.
|
|
6601
|
+
Server >= 7.119.0 adds `state.scenario_assignment_unknown` to this slot — the center's scenario assignment for the principal names a
|
|
6602
|
+
scenario this deployment does not have; refused before any side effect or billing, zero run, body `detail: { scenario, source }`, NO
|
|
6603
|
+
`Retry-After` (resending before the assignment is re-pointed — or the scenario added back to the deployment — is pointless; then retry
|
|
6604
|
+
verbatim, the serving replica reads the new assignment after its own cache window, one minute by default). The caller did nothing wrong:
|
|
6605
|
+
an explicit unknown `scenario` in the body is still 400 `scenario_unknown`. DETERMINISTIC for the SDK's retry arm (see
|
|
6606
|
+
`ErrorResponse.errorCode`); lands on ServiceStateError. On a resume leg the same refusal folds into 409 `resume_blocked_by_policy`
|
|
6607
|
+
(`blockedBy: state.scenario_assignment_unknown`).
|
|
6601
6608
|
Which of them carry a wait hint is stated ONCE, under `headers.Retry-After` below (kept in one place so
|
|
6602
6609
|
the two statements cannot drift apart).
|
|
6603
6610
|
headers:
|
|
@@ -7118,7 +7125,7 @@ components:
|
|
|
7118
7125
|
key on every submit of that session). ⚠️ A server < 7.104.0 answers 400 `request.body_shape` (unknown key).
|
|
7119
7126
|
permissionMode:
|
|
7120
7127
|
type: string
|
|
7121
|
-
enum: [default, plan, acceptEdits, bypassPermissions, auto]
|
|
7128
|
+
enum: [default, plan, acceptEdits, bypassPermissions, auto, dontAsk]
|
|
7122
7129
|
description: >
|
|
7123
7130
|
🔴 K-32 — server >= 7.106.0 (S-877 / core 7.34.0 design/1111 "one permission mode"), READ THIS FIRST; the long text
|
|
7124
7131
|
below describes <= 7.105.0. The effective mode passes through VERBATIM to the engine (`TaskSpec.permissionMode`); the
|
|
@@ -7131,13 +7138,16 @@ components:
|
|
|
7131
7138
|
`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)
|
|
7132
7139
|
and DISCLOSES each (`tool_end.gate.disposition.released` + one `engine_notice` `permission.ask_released_by_mode` per (mode, class) per run);
|
|
7133
7140
|
immune classes (deployment-authored, ask / org rules, hooks, ancestors, questions …) still ask; a write whose protection
|
|
7134
|
-
cannot be judged is refused (`deniedBy: mode`). Request vocabulary:
|
|
7135
|
-
|
|
7141
|
+
cannot be judged is refused (`deniedBy: mode`). Request vocabulary: SIX words (server >= 7.119.0) — `dontAsk`, the engine's
|
|
7142
|
+
"auto-refuse" mode, is accepted and passes through verbatim: the ENGINE refuses the calls that would ask (no card, no parked row,
|
|
7143
|
+
`tool_end.gate.disposition = { kind: denied, deniedBy: mode, mode: dontAsk, … }`), the run ends normally, and it is never looser
|
|
7144
|
+
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
|
|
7145
|
+
(the engine's `arbitrateByMode`: the `hook` class on a row without `hookAskFloor`). Send it only when `capabilities.permissionModes` carries it: that bit absent = server <= 7.118.x, whose request
|
|
7146
|
+
vocabulary is FIVE words — `dontAsk` on a fresh submit is 400 `request.field_invalid` there. The three sentences below — "omitting both carriers means no mode-derived gate", "`auto`
|
|
7136
7147
|
is armed by the principal's entitlement independent of the mode word", "`bypassPermissions` adds no mode-derived gate" —
|
|
7137
7148
|
hold for <= 7.105.0 only.
|
|
7138
|
-
CC-parity permission-mode INTENT — the
|
|
7139
|
-
|
|
7140
|
-
`dontAsk`). The frontend (TUI shell / web portal) carries the RAW mode; the SERVICE interprets it TIGHTEN-ONLY vs the deployment baseline:
|
|
7149
|
+
CC-parity permission-mode INTENT — the values THIS wire's closed submit-gate accepts (the first five on server <= 7.118.x,
|
|
7150
|
+
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:
|
|
7141
7151
|
`plan` ⇒ mount present_plan (core enablePlanMode) + read-only hands (CC EnterPlanMode research);
|
|
7142
7152
|
`default` adds the manual ask gate on non-exempt writes (scratchpad dirs / remembered session
|
|
7143
7153
|
exemptions still auto-allow — not literally every Write/Edit); the server emits the SAME gate-policy
|
|
@@ -7148,7 +7158,7 @@ components:
|
|
|
7148
7158
|
as plain `default`; `acceptEdits` adds the SAME gate narrowed to auto-allow inside the working
|
|
7149
7159
|
directory — but only when the service has a trusted working directory to scope it to; on a sandbox
|
|
7150
7160
|
execution lane with none wired, `acceptEdits` degrades to asking on every non-exempt write, same
|
|
7151
|
-
as `default`; `bypassPermissions` adds no mode-derived gate at all. None of
|
|
7161
|
+
as `default`; `bypassPermissions` adds no mode-derived gate at all. None of them can ever subtract
|
|
7152
7162
|
from the deployment/operator policy (deny-wins). Omitting this field is NOT itself "no mode-derived
|
|
7153
7163
|
gate" — this field wins over a `settings.permissions.defaultMode` bundle when both are sent, but when
|
|
7154
7164
|
THIS field is omitted the bundled mode (if any) still supplies one; only when neither carrier supplies
|
|
@@ -8114,18 +8124,21 @@ components:
|
|
|
8114
8124
|
enum: [mysql, pg, local, memory]
|
|
8115
8125
|
description: >
|
|
8116
8126
|
The ASSEMBLED backend (same word table; nothing assembled = `memory`). `declared != backend` is legal:
|
|
8117
|
-
`DB_BACKEND=pg` + `SESSION_BACKEND=memory` (deliberately non-durable, no `degradedReason`) /
|
|
8118
|
-
|
|
8119
|
-
|
|
8127
|
+
`DB_BACKEND=pg` + `SESSION_BACKEND=memory` (deliberately non-durable, no `degradedReason`) / a default-derived local
|
|
8128
|
+
store that could not be built (`declared: local`, `backend: memory`, `local_unwritable`). Server >= 7.119.0: a configured
|
|
8129
|
+
SQL store that cannot open is retried inside the wait window and then the boot is REFUSED — it never degrades to memory
|
|
8130
|
+
(server <= 7.118.x degraded it silently under `SESSION_BACKEND=auto`, with the RETIRED word `degradedReason: db_unreachable`).
|
|
8120
8131
|
durable: { type: boolean, description: '`backend !== "memory"`.' }
|
|
8121
8132
|
degradedReason:
|
|
8122
8133
|
type: string
|
|
8123
8134
|
enum: [db_unreachable, local_unwritable]
|
|
8124
8135
|
description: >
|
|
8125
|
-
PRESENT-IFF the degrade arm ran;
|
|
8126
|
-
`db_unreachable` = the SQL family could not open under `SESSION_BACKEND=auto` (connect or DDL, not told apart);
|
|
8136
|
+
PRESENT-IFF the degrade arm ran; the server's own closed set (`STORE_DEGRADED_REASONS`) is ONE word since server >= 7.119.0:
|
|
8127
8137
|
`local_unwritable` = the default-derived local file store could not be built (mkdir / lock / permission / read-only
|
|
8128
|
-
mount / disk full).
|
|
8138
|
+
mount / disk full). ⚰️ RETIRED word `db_unreachable`: the SQL family could not open under `SESSION_BACKEND=auto` (connect or DDL, not told
|
|
8139
|
+
apart) — a server <= 7.118.x (inside the support floor) still sends it; a server >= 7.119.0 NEVER does (a configured SQL store that
|
|
8140
|
+
cannot open is retried, then the boot is refused — the SQL family has no degraded state). Kept in this enum so a valid response from an
|
|
8141
|
+
older server still validates; it is deleted once the support floor rises past 7.118.x. Absent = not degraded.
|
|
8129
8142
|
sql:
|
|
8130
8143
|
allOf: [{ $ref: '#/components/schemas/SqlEngineCapability' }]
|
|
8131
8144
|
description: >
|
|
@@ -9349,11 +9362,32 @@ components:
|
|
|
9349
9362
|
server >= 7.118.0, hardcoded true (a version bit): the three approval decision doors read `decidedBy` (ApprovalDecidedBy).
|
|
9350
9363
|
Send it only when this is present; absent = an older server (the durable doors and `plan_review` 400 it, the live
|
|
9351
9364
|
`respond` drops it silently and answers 200).
|
|
9365
|
+
sessionReadRedaction:
|
|
9366
|
+
type: boolean
|
|
9367
|
+
description: >-
|
|
9368
|
+
server >= 7.120.0, hardcoded true (a predicate-class bit, same family as `approvalDecidedBy`): the session HISTORY read
|
|
9369
|
+
(`GET /v1/sessions/:id`, the `messages` string leaves, every fetch form) passes the same redaction as the live and ledger
|
|
9370
|
+
frames (see SessionRecord). Branch on the bit, not on the server version. Bit absent is NOT `false` and NOT "unredacted":
|
|
9371
|
+
a server <= 7.118.x returns the archive as written; a 7.119.x server already redacts but does not report the bit. A true
|
|
9372
|
+
bit does not mean the read face exists (that is `sessions`; without a session audit face that door answers 501 and this
|
|
9373
|
+
bit is still true), nor that the archive holds no credential (the redaction is read-side only).
|
|
9352
9374
|
approvalReach:
|
|
9353
9375
|
type: boolean
|
|
9354
9376
|
description: >-
|
|
9355
9377
|
server >= 7.118.0, hardcoded true (same word as the request key): TaskRequest.approvalReach is understood. Absent = an
|
|
9356
9378
|
older server — do not send the key.
|
|
9379
|
+
permissionModes:
|
|
9380
|
+
type: array
|
|
9381
|
+
items: { type: string }
|
|
9382
|
+
description: >-
|
|
9383
|
+
server >= 7.119.0 — the permission-mode words this worker's REQUEST face accepts: the engine's `PERMISSION_MODES` whole set, engine order
|
|
9384
|
+
(today six: `default`, `acceptEdits`, `plan`, `auto`, `bypassPermissions`, `dontAsk`). The top-level `TaskRequest.permissionMode`,
|
|
9385
|
+
`settings.permissions.defaultMode` and `GET /v1/capabilities?permissionMode=` read ONE closed set: every word in the bit is accepted by
|
|
9386
|
+
all three, a word outside it is 400 `request.field_invalid` whose sentence lists the same words. Send `dontAsk` only when this bit
|
|
9387
|
+
carries it; ABSENT = server <= 7.118.x (five words, `dontAsk` is a 400). OPEN set: the bit forwards the engine's vocabulary
|
|
9388
|
+
verbatim, so a future engine word shows up here before this document knows it — decide by the bit, do not filter it through the
|
|
9389
|
+
`PermissionMode` schema. It says "this server accepts the word", not "the word takes effect on this submit" (`auto` still needs a
|
|
9390
|
+
classifier seat and an entitlement — see `permissionModeAuto`).
|
|
9357
9391
|
respondFreeFormRules:
|
|
9358
9392
|
type: boolean
|
|
9359
9393
|
description: >
|
|
@@ -9618,8 +9652,9 @@ components:
|
|
|
9618
9652
|
the same false, and a shell must do different things for those. `reason` is present ONLY when
|
|
9619
9653
|
`armed` is false; read its vocabulary as an OPEN set (server already grew it from four words to
|
|
9620
9654
|
six). `model` is omitted when the classifier route cannot be resolved (the server logs the
|
|
9621
|
-
engine's refusal rather than 500-ing the read face). `?permissionMode=<
|
|
9622
|
-
caller's INTENT into the verdict
|
|
9655
|
+
engine's refusal rather than 500-ing the read face). `?permissionMode=<mode word>` folds the
|
|
9656
|
+
caller's INTENT into the verdict (server >= 7.119.0 takes the six words of `capabilities.permissionModes` — `dontAsk` answers
|
|
9657
|
+
`armed: false` / `reason: mode_not_auto`; server <= 7.118.x takes five); anything outside the server's words is a 400
|
|
9623
9658
|
`request.field_invalid`.
|
|
9624
9659
|
# 🔴 required 只有**三位**:武装两键(armed / reason)是 server >= 7.57.0 (S-80)
|
|
9625
9660
|
# 才有的,而本包的支持地板是 3.0.0 => every 7.x <= 7.56.0 server is inside the promised face and
|
|
@@ -12756,6 +12791,12 @@ components:
|
|
|
12756
12791
|
description: >
|
|
12757
12792
|
Session audit (`GET /v1/sessions/:id`) — true shape. `messages` = current model context
|
|
12758
12793
|
(older history folded into a summary message); can be large.
|
|
12794
|
+
Server >= 7.119.0 (wire VALUE change, shape unchanged): string leaves inside `messages` (assistant text / reasoning, tool arguments,
|
|
12795
|
+
tool results, shell output, compaction summaries) pass the SAME redaction as the live and ledger frames — a credential-shaped span reads
|
|
12796
|
+
`«redacted:…»`. Key set, count and segment order are verbatim; a history with no credential-shaped span is byte-identical; the archive itself is
|
|
12797
|
+
untouched (the redaction is read-side only), and `?blobCap=` truncation runs AFTER redaction. A caller that rebuilds a model context from this
|
|
12798
|
+
read gets the placeholder, not the original string. Server >= 7.120.0 reports this with the capability bit `sessionReadRedaction`
|
|
12799
|
+
(a 7.119.x server redacts but does not report it).
|
|
12759
12800
|
# 🔴 **暂不封闭**(census 轴一裁定,2026-07-30):本体是 core `StoredSession.buildContext()` 的投影
|
|
12760
12801
|
# (server `audit.ts` auditFromStorage),再叠 server 自己的两条 additive 后处理(windowMessages /
|
|
12761
12802
|
# truncateMessageBlobs)与路由层追加的 owner —— 键集由「core 投影 × 查询参数」共同决定,不是一个
|
|
@@ -13574,8 +13615,10 @@ components:
|
|
|
13574
13615
|
7.104.0 / S-271 — a deployment-declared tool exceeds the roster bound), `config.tool_schema_bound` (503, server >=
|
|
13575
13616
|
7.106.0 / core 7.35.0 #765 — a tool's `parameters` schema exceeds the roster row's key bound; "same family, same tier";
|
|
13576
13617
|
<= 7.105.0 answered the synchronous leg 200 + a failed body), `corrupt` (500 — the session rule store
|
|
13577
|
-
cannot read its own bytes)
|
|
13578
|
-
fail-closed).
|
|
13618
|
+
cannot read its own bytes), `internal.memory_control_plane_corrupt` (500 — the memory control plane refuses
|
|
13619
|
+
fail-closed) and `state.scenario_assignment_unknown` (503, server >= 7.119.0 — the center's scenario assignment for the
|
|
13620
|
+
principal is dangling; only re-pointing the assignment, or adding the scenario back to the deployment, helps). Every other 5xx
|
|
13621
|
+
code keeps the status-based retry.
|
|
13579
13622
|
🔴 `request.host_posture_refused` (422) has TWO triggers (same code, same status — "you wrote it right, this
|
|
13580
13623
|
deployment will not grant that host posture"): (1) the write-containment face (`permissionMode: bypassPermissions` ⇒
|
|
13581
13624
|
`writeFace: open`; read `capabilities.taskWriteFaceOpen` first); (2) server >= 7.106.0 / S-895: `inheritEnv: "all"` on a
|
|
@@ -13657,10 +13700,19 @@ components:
|
|
|
13657
13700
|
row's configuration was refused — `taskConfig` (change the configuration, then decide the SAME card again) or
|
|
13658
13701
|
`inheritedGate` (the row's recorded mode seed is bad — the run can only be cancelled). Also on 400 `request.field_invalid` for a
|
|
13659
13702
|
`settings.hooks` tool-event matcher that selects an engine alias but not its canonical name (server >= 7.115.0 / S-1025):
|
|
13660
|
-
`field` is always the literal `settings.hooks` (see `detail`).
|
|
13703
|
+
`field` is always the literal `settings.hooks` (see `detail`). Also on 400 `request.body_shape` (server >= 7.119.0), on the THREE
|
|
13704
|
+
tool-approval decision doors (`POST /v1/tool-approvals/{id}/respond`, `POST /v1/tasks/{taskId}/asks/{askId}/decision`,
|
|
13705
|
+
`POST /v1/approvals/{sessionId}/decide`) and ONLY there: the body carried the retired key `settledBy` (any value but `undefined` —
|
|
13706
|
+
`null` and `""` count), the refusal landed before any decision, and `field` is the literal `settledBy`; the three doors now answer
|
|
13707
|
+
the SAME sentence. Every such 400 carries it, even when another defect in the same body was hit first (the sentence then names that
|
|
13708
|
+
defect). Branch on the code plus `field`, never on the sentence; a bad body WITHOUT that key carries no `field`. SDK: `err.extra.field`.
|
|
13661
13709
|
detail:
|
|
13662
13710
|
description: >
|
|
13663
|
-
🔴
|
|
13711
|
+
🔴 SHAPES differ by code — branch on `field` (or the `errorCode`), never guess from the type of `detail`. On 503
|
|
13712
|
+
`state.scenario_assignment_unknown` (server >= 7.119.0): an OBJECT `{ scenario, source }` — `scenario` = the dangling scenario name,
|
|
13713
|
+
`source` ∈ `ruling` (the center's assignment for this principal names a scenario this deployment does not have) / `deployment`
|
|
13714
|
+
(the deployment default `DEFAULT_SCENARIO` is dangling — the server refuses to BOOT on that, so a request reaches it only on an
|
|
13715
|
+
embedder that assembles `resolveSpec` itself). On 400
|
|
13664
13716
|
`request.field_invalid` for a `settings.hooks` tool-event matcher (server >= 7.115.0 / S-1025; additive, the sentence and the code
|
|
13665
13717
|
are unchanged): an OBJECT `{ event, alias, canonical }` — `event` = the tool event of the refused group (the first refused one when
|
|
13666
13718
|
several are), `alias` / `canonical` = the engine catalog's alias and canonical name (closed strings, never the caller's raw bytes),
|
|
@@ -13675,6 +13727,12 @@ components:
|
|
|
13675
13727
|
event: { type: string }
|
|
13676
13728
|
alias: { type: string }
|
|
13677
13729
|
canonical: { type: string }
|
|
13730
|
+
- type: object
|
|
13731
|
+
required: [scenario, source]
|
|
13732
|
+
additionalProperties: false
|
|
13733
|
+
properties:
|
|
13734
|
+
scenario: { type: string }
|
|
13735
|
+
source: { type: string, enum: [ruling, deployment] }
|
|
13678
13736
|
- type: string
|
|
13679
13737
|
count:
|
|
13680
13738
|
type: integer
|
|
@@ -14266,16 +14324,24 @@ components:
|
|
|
14266
14324
|
enum: [default, acceptEdits, plan, auto, bypassPermissions, dontAsk]
|
|
14267
14325
|
description: >
|
|
14268
14326
|
core 7.34.0 `PERMISSION_MODES` (six words). CLOSED on the gate record (the server screens it with core `isPermissionMode`;
|
|
14269
|
-
an out-of-set word withholds the whole `gate`).
|
|
14270
|
-
7.
|
|
14271
|
-
|
|
14327
|
+
an out-of-set word withholds the whole `gate`). The REQUEST face (`TaskRequest.permissionMode`) takes the same six words from
|
|
14328
|
+
server 7.119.0 (`capabilities.permissionModes`); on server <= 7.118.x it takes FIVE — `dontAsk` on a fresh submit is 400
|
|
14329
|
+
`request.field_invalid` there — yet `dontAsk` can still appear here on those versions (e.g. an unattended leg run under
|
|
14330
|
+
`UNATTENDED_PERMISSION_MODE=dontAsk`).
|
|
14272
14331
|
AskClass:
|
|
14273
14332
|
type: string
|
|
14274
|
-
enum: [content_question, hook, ancestor, unverifiable_delete, transcript_write, org_rule, governance_unavailable, rule_unreadable, ask_rule, denial_limit_fallback, classifier_no_ruling, requires_user_interaction, operator_forced, shell_floor, write_protection_unresolved, probe, write_protection, tool_marks_mcp, tool_marks_a2a, policy_rra, artifact_shared_read, mode, unstated, ordinary]
|
|
14333
|
+
enum: [content_question, hook, ancestor, dangerous_delete, unverifiable_delete, transcript_write, org_rule, governance_unavailable, rule_unreadable, ask_rule, denial_limit_fallback, classifier_no_ruling, requires_user_interaction, operator_forced, shell_floor, write_protection_unresolved, probe, write_protection, tool_marks_mcp, tool_marks_a2a, policy_rra, artifact_shared_read, mode, unstated, ordinary]
|
|
14275
14334
|
description: >
|
|
14276
|
-
core `ASK_CLASSES` (twenty-two words as of core 7.40.0, twenty-three as of core 7.41.0, twenty-four as of core 7.43.0 — 7.34.0 minted twenty; `shell_floor` joined in 7.39.0 #1260 and rides
|
|
14335
|
+
core `ASK_CLASSES` (twenty-two words as of core 7.40.0, twenty-three as of core 7.41.0, twenty-four as of core 7.43.0, twenty-five as of core 7.45.0 — 7.34.0 minted twenty; `shell_floor` joined in 7.39.0 #1260 and rides
|
|
14277
14336
|
server >= 7.113.0; `unstated` joined in 7.40.0 and rides server >= 7.115.0; `requires_user_interaction` joined in 7.41.0 and rides
|
|
14278
|
-
server >= 7.116.0; `classifier_no_ruling` joined in 7.43.0 #1353 and rides server >= 7.118.0
|
|
14337
|
+
server >= 7.116.0; `classifier_no_ruling` joined in 7.43.0 #1353 and rides server >= 7.118.0; `dangerous_delete` joined in 7.45.0 and rides
|
|
14338
|
+
server >= 7.119.0) — which CLASS an ask falls in (the columns of the mode × class arbitration table).
|
|
14339
|
+
`dangerous_delete` = a DELETE OF A PROTECTED PLACE: an `rm` / `rmdir` whose target is the filesystem root, a top-level directory, the home
|
|
14340
|
+
directory, the task root / working directory / an added working directory or an ancestor of one (including `rm -rf *` at the task root and
|
|
14341
|
+
`rm -rf ~/*`), or a shell handed a script that is only assembled at run time (`bash -c "$CMD"`, `eval "$(…)"`). ONLY A PERSON'S ANSWER clears
|
|
14342
|
+
it: no mode (`bypassPermissions` included), no allow (request `settings.permissions.allow`, operator `APPROVAL_GRANT`, a stored allow row, a
|
|
14343
|
+
skill's tool list, a hook's allow) and no `auto` classifier does; the frame carries `requiresRealApproval: true`, nobody answering means the
|
|
14344
|
+
call does not run (the unattended leg refuses), and it is bypass-IMMUNE (not one of the ten releasable classes).
|
|
14279
14345
|
`classifier_no_ruling` = the auto-mode classifier did not rule (it could not run — `error` / `timeout` — or replied with no verdict —
|
|
14280
14346
|
`parse_error`), so a person decides: the denial-limit fallback's row (bypass-immune, no allow rule clears it, the classifier is not asked
|
|
14281
14347
|
again); the live frame and the inbox row also carry the cause as `classifierNoRuling`.
|
|
@@ -19531,6 +19597,20 @@ components:
|
|
|
19531
19597
|
description: >
|
|
19532
19598
|
Where a persisted rule applies (core `RuleScope`). `project.root` is the directory prefix that decides
|
|
19533
19599
|
which cwds the rule is live under.
|
|
19600
|
+
|
|
19601
|
+
🔴 WHICH ROOTS ARE ACCEPTED — the one statement every other mention in this file points to (the cc-import
|
|
19602
|
+
layer `root`, and the `project:<root>` discriminant string on write / revoke / the list filter):
|
|
19603
|
+
server >= 7.120.0 accepts only a COMPLETE ABSOLUTE PATH — POSIX `/…`, a Windows drive root `X:\…` / `X:/…`,
|
|
19604
|
+
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 whose
|
|
19606
|
+
`error` is exactly "scope must be 'global' or 'project:<root>' with an absolute root" — code
|
|
19607
|
+
`request.body_shape` on write / revoke / cc-import prepare, `request.query_invalid` on the list filter.
|
|
19608
|
+
Server <= 7.119.x checks only that the root is non-empty and keeps relative roots as written; such rows take
|
|
19609
|
+
no part in any check on 7.120.0 — SQL backends delete them with a one-time migration at boot, while on the
|
|
19610
|
+
file (`local`) backend they stay in the store, are absent from the listing, cannot be revoked, and each run
|
|
19611
|
+
gets an `engine_notice` `permission.rule_row_dropped` naming them. Rewrite them with the project's full path.
|
|
19612
|
+
An EMPTY root is refused on every version (an empty prefix contains every cwd). The root's truthfulness is
|
|
19613
|
+
never validated — only its spelling.
|
|
19534
19614
|
oneOf:
|
|
19535
19615
|
- type: object
|
|
19536
19616
|
additionalProperties: false
|
|
@@ -19542,7 +19622,7 @@ components:
|
|
|
19542
19622
|
required: [kind, root]
|
|
19543
19623
|
properties:
|
|
19544
19624
|
kind: { type: string, enum: [project] }
|
|
19545
|
-
root: { type: string, minLength: 1, description: 'The canonical directory this rule is scoped to. NEVER empty — an empty prefix contains EVERY cwd, which would silently promote a project rule to a global one.' }
|
|
19625
|
+
root: { type: string, minLength: 1, description: 'The canonical directory this rule is scoped to. NEVER empty — an empty prefix contains EVERY cwd, which would silently promote a project rule to a global one. Server >= 7.120.0: a complete absolute path (see the RuleScope description).' }
|
|
19546
19626
|
|
|
19547
19627
|
RuleBehavior:
|
|
19548
19628
|
type: string
|
|
@@ -19618,9 +19698,12 @@ components:
|
|
|
19618
19698
|
cloud deployment has no access to the user's filesystem — that is the deployment shape, not a bypass:
|
|
19619
19699
|
what is read is still only the allow bucket.
|
|
19620
19700
|
|
|
19621
|
-
🔴 `root`
|
|
19622
|
-
|
|
19623
|
-
|
|
19701
|
+
🔴 `root` follows the RuleScope rule (server >= 7.120.0: a complete absolute path; otherwise 400
|
|
19702
|
+
`request.body_shape` with "scope must be 'global' or 'project:<root>' with an absolute root" and no ticket
|
|
19703
|
+
minted). It applies to ALL layers alike — a `userSettings` layer's root never becomes a scope, but it is the
|
|
19704
|
+
same field under the same check. On <= 7.119.x only an empty root is refused (with the body-shape sentence).
|
|
19705
|
+
Its TRUTHFULNESS is deliberately NOT validated: the server has no such tree to check against, and pretending
|
|
19706
|
+
to validate would be a lie. It is the user's own label for "which cwds should this rule be live under".
|
|
19624
19707
|
# 封闭:server 侧 zod 是 `.strict()`(把 `content` 拼成 `contents` 的客户端应当场 400,而不是拿到
|
|
19625
19708
|
# 一份「零候选」的预览去纳闷)。
|
|
19626
19709
|
additionalProperties: false
|
|
@@ -19817,7 +19900,7 @@ components:
|
|
|
19817
19900
|
allOf: [{ $ref: '#/components/schemas/RuleBehavior' }]
|
|
19818
19901
|
description: 'Which of the three this row is. Part of the row''s IDENTITY — pass it back VERBATIM to revoke, or the delete aims at another behavior''s same-text row.'
|
|
19819
19902
|
rule: { type: string, description: 'Canonical rule text — `Bash(git status)` (exact) or `Bash(git status:*)` (prefix). Pass back VERBATIM to revoke.' }
|
|
19820
|
-
scope: { type: string, description: 'Scope discriminant string: `global`, or `project:<root>`
|
|
19903
|
+
scope: { type: string, description: 'Scope discriminant string: `global`, or `project:<root>` (which roots: see RuleScope — on server >= 7.120.0 every listed project row has a complete absolute root; an older server may list relative ones). Pass back VERBATIM to revoke.' }
|
|
19821
19904
|
tool:
|
|
19822
19905
|
type: string
|
|
19823
19906
|
# 🔴 只钉非空,**不借**输入面那条 `maxLength: 190`(server 的 `LocalImportRowSchema` 帽的是**收进来的**
|
|
@@ -19918,7 +20001,7 @@ components:
|
|
|
19918
20001
|
type: string
|
|
19919
20002
|
minLength: 1
|
|
19920
20003
|
maxLength: 4104
|
|
19921
|
-
description: 'The scope discriminant string — `global` or `project:<root>`
|
|
20004
|
+
description: 'The scope discriminant string — `global` or `project:<root>` (which roots are accepted: see RuleScope; an empty root would match every cwd). Unreadable, or a root the server does not accept ⇒ 400 `request.body_shape`, never guessed into `global`. Cap = "project:".length + server MAX_CWD_CHARS (8+4096), same source as RuleRevokeRequest.'
|
|
19922
20005
|
principal: { type: string, minLength: 1, maxLength: 190, description: 'OPERATOR-ONLY cross-tenant write. Absent (or your own principal) = write your own rule. Gated exactly like the revoke half.' }
|
|
19923
20006
|
|
|
19924
20007
|
RuleWriteResult:
|
|
@@ -20082,7 +20165,7 @@ components:
|
|
|
20082
20165
|
at an `allow` that got defaulted onto the same-text `deny` deletes a refusal that was meant to stay,
|
|
20083
20166
|
and hands the caller a 200. core's `sameRuleIdentity` names this exact failure.
|
|
20084
20167
|
rule: { type: string, minLength: 1, maxLength: 1024, description: 'The canonical rule text, VERBATIM as `RuleListResult.rules[].rule` gave it.' }
|
|
20085
|
-
scope: { type: string, minLength: 1, maxLength: 4104, description: 'The scope discriminant string — `global` or `project:<root>`
|
|
20168
|
+
scope: { type: string, minLength: 1, maxLength: 4104, description: 'The scope discriminant string — `global` or `project:<root>` (which roots are accepted: see RuleScope; an empty root would match every cwd; a root the server does not accept ⇒ 400 `request.body_shape`). VERBATIM as the listing gave it. Cap = "project:".length + server MAX_CWD_CHARS (8+4096) — the 1088 previously written here was the same stale independent copy the server itself fixed (rules.ts MAX_RULE_SCOPE_CHARS 顶注), found by the A-335 anchor sweep.' }
|
|
20086
20169
|
principal: { type: string, minLength: 1, maxLength: 190, description: 'OPERATOR-ONLY cross-tenant revoke. Absent (or your own principal) = revoke your own rule.' }
|
|
20087
20170
|
|
|
20088
20171
|
RemovalLiveness:
|
|
@@ -20427,7 +20510,7 @@ components:
|
|
|
20427
20510
|
description: 'The v1 CLOSED SET. A third value (e.g. `win32`) ⇒ 400 request.field_invalid — never silently accepted.'
|
|
20428
20511
|
platformArch: { type: string, maxLength: 32, description: 'At most 32 **UTF-8 bytes** (producer gates byte length; `maxLength` is the looser character bound, see the unit convention).' }
|
|
20429
20512
|
displayName: { type: string, maxLength: 255, description: 'Echoed back by `GET /v1/devices` as `name`, and HONESTLY ABSENT there when empty. At most 255 **UTF-8 bytes** (producer gates byte length; `maxLength` is the looser character bound).' }
|
|
20430
|
-
workspaceRoot: { type: string, minLength: 1, maxLength: 1024, description: 'The device-side root every instruction resolves against.
|
|
20513
|
+
workspaceRoot: { type: string, minLength: 1, maxLength: 1024, description: 'The device-side root every instruction resolves against (and the `cwd` of `exec` / `execStream` when neither the session nor its delegation parents registered a working directory). Server >= 7.120.0: an ABSOLUTE POSIX path — empty, relative (`work`, `./w`) or `~/…` ⇒ 400 request.field_invalid, `error` starting "workspaceRoot must be an absolute POSIX path", the token NOT consumed (resolve the root on the device first). Server <= 7.119.x: only non-empty is checked, and a device registered with a relative root has its sessions refused when 7.120.0 builds their execution environment — re-enroll with an absolute root (new `deviceId`; revoke the old one). At most 1024 **UTF-8 bytes** (producer gates byte length; `maxLength` is the looser character bound) ⇒ over it 400 request.field_invalid (a silently truncated value is a DIFFERENT value).' }
|
|
20431
20514
|
|
|
20432
20515
|
DeviceEnrollResult:
|
|
20433
20516
|
type: object
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/sdk",
|
|
3
|
-
"version": "17.
|
|
3
|
+
"version": "17.2.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",
|