@sema-agent/sdk 9.0.0 → 9.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 +49 -0
- package/dist/errors.d.ts +23 -10
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +25 -9
- package/dist/errors.js.map +1 -1
- package/dist/events.d.ts +30 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/resources/approvals.d.ts +10 -6
- package/dist/resources/approvals.d.ts.map +1 -1
- package/dist/resources/approvals.js +10 -6
- package/dist/resources/approvals.js.map +1 -1
- package/dist/resources/runs.d.ts +35 -1
- package/dist/resources/runs.d.ts.map +1 -1
- package/dist/resources/runs.js +39 -0
- package/dist/resources/runs.js.map +1 -1
- package/dist/resources/tool-approvals.d.ts +29 -8
- package/dist/resources/tool-approvals.d.ts.map +1 -1
- package/dist/resources/tool-approvals.js +9 -3
- package/dist/resources/tool-approvals.js.map +1 -1
- package/dist/types.d.ts +144 -6
- package/dist/types.d.ts.map +1 -1
- package/openapi.yaml +376 -16
- package/package.json +1 -1
package/openapi.yaml
CHANGED
|
@@ -918,6 +918,104 @@ paths:
|
|
|
918
918
|
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
919
919
|
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
920
920
|
|
|
921
|
+
/v1/runs/{taskId}/memory/capture-optout:
|
|
922
|
+
parameters:
|
|
923
|
+
- $ref: '#/components/parameters/PrincipalHeader'
|
|
924
|
+
- $ref: '#/components/parameters/TaskIdPath'
|
|
925
|
+
post:
|
|
926
|
+
tags: [runs]
|
|
927
|
+
operationId: runsMemoryCaptureOptOut
|
|
928
|
+
x-status: live # server >= 7.70.0 — the mid-run flip verb for the session memory-capture opt-out.
|
|
929
|
+
summary: Opt this SESSION out of long-term memory capture, mid-run.
|
|
930
|
+
description: >
|
|
931
|
+
"We got into something that should not be remembered." From this moment the session commits NOTHING to
|
|
932
|
+
long-term memory, already-committed contributions leave the consolidation pool, and write-root residue
|
|
933
|
+
is swept. ONE-WAY: there is no reverse verb, repeat calls are idempotent (`outcome:"existed"`), and
|
|
934
|
+
getting capture back needs a NEW session.
|
|
935
|
+
🔴 The SAME record as the `memoryCapture:"off"` submit-time declaration, reached through a second
|
|
936
|
+
ingress — so "declare it on the next submit" is the fallback for MOST refusals. It is not the answer to
|
|
937
|
+
all of them: read the per-errorCode recovery notes on the 409/503 arms below (one 409 is a PARTIAL
|
|
938
|
+
SUCCESS whose retry lane is this very verb, one names another replica, and one is a deployment-shape
|
|
939
|
+
fact the declaration hits too).
|
|
940
|
+
Owner-gated on the VERIFIED principal (a bare sessionId relay would let anyone switch off anyone's
|
|
941
|
+
memory); a non-owner gets the SAME 404 string as an unknown run (no existence oracle). The engine
|
|
942
|
+
re-adjudicates the per-principal entitlement at flip time — the service does not replicate that ruling.
|
|
943
|
+
Runs no model (not billable, no drain/roster gate); rate-limited as a mutating verb. Gate the UI entry
|
|
944
|
+
on `capabilities.runMemoryCaptureOptOut`.
|
|
945
|
+
requestBody:
|
|
946
|
+
required: false
|
|
947
|
+
content:
|
|
948
|
+
application/json:
|
|
949
|
+
schema:
|
|
950
|
+
type: object
|
|
951
|
+
additionalProperties: false # STRICT server-side — a mistyped key is a 400, not "no reason given".
|
|
952
|
+
properties:
|
|
953
|
+
reason: { type: string, minLength: 1, maxLength: 500, description: 'Optional one-line audit note. Does not affect the ruling.' }
|
|
954
|
+
responses:
|
|
955
|
+
'200':
|
|
956
|
+
description: Flipped — `created` on the first call, `existed` on an idempotent repeat.
|
|
957
|
+
content:
|
|
958
|
+
application/json:
|
|
959
|
+
schema: { $ref: '#/components/schemas/MemoryCaptureOptOutResult' }
|
|
960
|
+
'400':
|
|
961
|
+
description: >-
|
|
962
|
+
errorCode "request.body_shape" — the body must be `{}` or `{ reason }` (non-empty, at most 500
|
|
963
|
+
chars); this verb takes no other keys.
|
|
964
|
+
content:
|
|
965
|
+
application/json:
|
|
966
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
967
|
+
'401': { $ref: '#/components/responses/Unauthorized' }
|
|
968
|
+
'403':
|
|
969
|
+
description: >-
|
|
970
|
+
errorCode "memory.capture_optout_denied" — this principal's entitlement does not permit the opt-out.
|
|
971
|
+
TERMINAL: the verdict is a deployment/center fact, so retrying changes nothing.
|
|
972
|
+
content:
|
|
973
|
+
application/json:
|
|
974
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
975
|
+
'404': { $ref: '#/components/responses/NotFound' }
|
|
976
|
+
'409':
|
|
977
|
+
description: >-
|
|
978
|
+
Four DIFFERENT situations share this status; the recovery action is per errorCode, not per status.
|
|
979
|
+
(1) "steering.not_running" — this verb needs a LIVE turn and there is none. THREE of its four causes
|
|
980
|
+
(terminal / parked / no steerable face on this replica) are fixed the same way: declare
|
|
981
|
+
`memoryCapture: "off"` on this session's next NEW submit. ⚠️ For a PARKED run that matters twice
|
|
982
|
+
over — a resumed continuation rebuilds its spec from the PERSISTED body and cannot take a new
|
|
983
|
+
declaration, so content captured until that next submit stays captured. The FOURTH cause is
|
|
984
|
+
different: when the run is live on ANOTHER replica the service says so explicitly, and the recovery
|
|
985
|
+
is to RESEND this verb to the owning replica (the next-submit declaration also works).
|
|
986
|
+
(2) "memory.capture_optout_sweep_failed" — 🔴 PARTIAL SUCCESS, not a rejection: the one-way opt-out
|
|
987
|
+
record STANDS (capture is already off) and only the residue sweep failed on named paths. A repeat
|
|
988
|
+
call IS the retry lane; leaving it un-retried leaves that named residue on the authoritative plane.
|
|
989
|
+
(3) "memory.capture_optout_unavailable" — this run mounted no memory session, so there is nothing to
|
|
990
|
+
opt out of; no action is owed.
|
|
991
|
+
(4) "config.memory_capture_unsupported" — a DEPLOYMENT-SHAPE fact (no capture record store on this
|
|
992
|
+
worker, so the record would not survive to a resume replica). 🔴 The submit-time declaration hits the
|
|
993
|
+
SAME wall on this shape — do not advertise it as the workaround; the fix is on the deployment.
|
|
994
|
+
content:
|
|
995
|
+
application/json:
|
|
996
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
997
|
+
'422':
|
|
998
|
+
description: 'errorCode "steering.invalid_content" — the engine refused the reason payload.'
|
|
999
|
+
content:
|
|
1000
|
+
application/json:
|
|
1001
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
1002
|
+
'429':
|
|
1003
|
+
description: >-
|
|
1004
|
+
errorCode "limit.rate_exceeded" — mutating verb, rate-limited only (no quota/lease gate; it runs no
|
|
1005
|
+
model). `Retry-After` (seconds) set.
|
|
1006
|
+
content:
|
|
1007
|
+
application/json:
|
|
1008
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
1009
|
+
'501': { $ref: '#/components/responses/NotImplemented' }
|
|
1010
|
+
'503':
|
|
1011
|
+
description: >-
|
|
1012
|
+
errorCode "memory.capture_optout_unpersisted" — the record could not be durably written (a store-mark
|
|
1013
|
+
failure, or a failing consolidation-epoch bump). The engine REFUSES rather than holding the flip
|
|
1014
|
+
in-process, so capture is still ON. RETRYABLE (the verb is idempotent).
|
|
1015
|
+
content:
|
|
1016
|
+
application/json:
|
|
1017
|
+
schema: { $ref: '#/components/schemas/ErrorResponse' }
|
|
1018
|
+
|
|
921
1019
|
/v1/runs/{taskId}/subagents/{target}/output:
|
|
922
1020
|
parameters:
|
|
923
1021
|
- $ref: '#/components/parameters/PrincipalHeader'
|
|
@@ -2554,16 +2652,20 @@ paths:
|
|
|
2554
2652
|
`POST /v1/assistant/tasks/{taskId}/resume`. Retrying the same body never succeeds.
|
|
2555
2653
|
SEVENTH group (server >= 7.69.0 / S-185, the PARKED WORKFLOW-CHILD lane): `decide.workflow_host_unknown`
|
|
2556
2654
|
and `decide.workflow_host_not_parked`. The pending belongs to a workflow child that parked on an
|
|
2557
|
-
approval gate, and the deployment could not hand the decision to that workflow's HOST session
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2655
|
+
approval gate, and the deployment could not hand the decision to that workflow's HOST session. Both
|
|
2656
|
+
bodies carry `runId` (the WORKFLOW run) and NO `taskId`. NOTHING was consumed: the child's checkpoint
|
|
2657
|
+
stays PENDING and the card is still listable and re-decidable. SDK → DecideWorkflowHostError (`.runId`
|
|
2658
|
+
is the handle). `_host_unknown` = the run carries no originating session at all (a directly started
|
|
2659
|
+
`runWorkflow`, not a Workflow tool call) → NO retry value, a person resumes that `runId`.
|
|
2660
|
+
`_host_not_parked` = the host is not currently parked awaiting this run. ⚰️ RETIRED at server 7.72.0,
|
|
2661
|
+
no alias, but this SDK still maps it: `SUPPORTED_SERVER_FLOOR` is 3.0.0 and this code was introduced
|
|
2662
|
+
at 7.69.0, so a still-supported server in the [7.69.0, 7.72.0) window can genuinely send it, and for
|
|
2663
|
+
that window the old contract holds — retry once it parks again, or resume that `runId` yourself. A
|
|
2664
|
+
server >= 7.72.0 will never send this code again: that version replaced the dead end with a SECOND
|
|
2665
|
+
leg that instead mints a fresh run on the same host session, so against a current server the SAME
|
|
2666
|
+
decide either resumes the parked host or starts that new run (both land on the byte-identical
|
|
2667
|
+
acceptance shape) — a host session already busy with another run instead answers the ordinary 409
|
|
2668
|
+
`conflict.session_active_run`.
|
|
2567
2669
|
SIXTH group (A-075.10, TIME-BASED retry-later pair): `resume.usage_window_exhausted` (#449 G1,
|
|
2568
2670
|
core 5.60.1 — the deployment governance window on this run's ledger key is full; NOTHING was
|
|
2569
2671
|
consumed or unpinned, the SAME token with the SAME decision redeems once the window slides) and
|
|
@@ -5232,7 +5334,9 @@ components:
|
|
|
5232
5334
|
type: object
|
|
5233
5335
|
description: >
|
|
5234
5336
|
Common request body. `[additionalProperties]` mirrors the service passthrough — scenario-specific fields
|
|
5235
|
-
(code-review's `repo`/`
|
|
5337
|
+
(code-review's `repo`/`lenses`/`rounds`, etc.) ride here. NOTE (sdk 9.1.0): `council`/`debate` used to be
|
|
5338
|
+
named here as passthrough examples, but the service declares them as TOP-LEVEL typed keys and reads them
|
|
5339
|
+
on two seams outside the scenario builder, so they are declared properties below.
|
|
5236
5340
|
required: [objective]
|
|
5237
5341
|
additionalProperties: true
|
|
5238
5342
|
properties:
|
|
@@ -5318,6 +5422,40 @@ components:
|
|
|
5318
5422
|
(mcpInjectionHonored = requirePrincipal!==true); multi-tenant ignores it (fail-closed). Merge:
|
|
5319
5423
|
deployment/center baseline wins on name collision (caller can ADD, never SHADOW).
|
|
5320
5424
|
items: { $ref: '#/components/schemas/McpServerSpec' }
|
|
5425
|
+
a2aPeers:
|
|
5426
|
+
type: array
|
|
5427
|
+
maxItems: 32
|
|
5428
|
+
description: >
|
|
5429
|
+
Per-request A2A peers — remote agents this task may call. HONORED only on a SINGLE-USER deployment
|
|
5430
|
+
that has neither locked the `a2a` key nor had `a2a_peers` denied by its compliance posture (the same
|
|
5431
|
+
three-veto predicate `capabilities.a2aInjection` advertises); multi-tenant ignores the field, and a
|
|
5432
|
+
LOCKED deployment refuses the whole request with 400 `config.locked_key`.
|
|
5433
|
+
🔴 Declaring a peer declares an OUTBOUND WRITE channel: every skill it advertises mounts with
|
|
5434
|
+
`egress:true` + `effect:"write"` (core's ruling); `toolAxes` is the caller's explicit override face.
|
|
5435
|
+
🔴 A malformed entry drops the WHOLE peer (named in a warn), never "drop the bad key and keep the
|
|
5436
|
+
peer": `allowSkills` is a NARROWING field whose absence means "no restriction", so a half-applied
|
|
5437
|
+
entry would turn a narrowing intent into a widening. The request itself is not rejected.
|
|
5438
|
+
The center/config baseline wins on a name clash (the peer name IS the tool namespace segment). Over
|
|
5439
|
+
the 32-entry cap the surplus entries are DROPPED and named too — same disposition as a malformed
|
|
5440
|
+
entry, not a 400.
|
|
5441
|
+
items: { $ref: '#/components/schemas/A2aServerSpec' }
|
|
5442
|
+
council:
|
|
5443
|
+
type: boolean
|
|
5444
|
+
description: >
|
|
5445
|
+
The `code-review` scenario's EXPENSIVE tier — fan the review out to N parallel lenses plus an
|
|
5446
|
+
arbiter (`run_council`) instead of the lead reviewing in-line. Read on TWO seams and both matter:
|
|
5447
|
+
the scenario builder mounts the council tool, and spec resolution treats it as an EXPLICIT team
|
|
5448
|
+
declaration (widening the task's wall-clock tenancy budget and suppressing the value router's
|
|
5449
|
+
auto-escalation). Only a literal `true` counts on both seams. On other scenarios the first seam is
|
|
5450
|
+
inert while the second still applies.
|
|
5451
|
+
debate:
|
|
5452
|
+
type: boolean
|
|
5453
|
+
description: >
|
|
5454
|
+
Run the L2 peer-debate rounds on top of `council`. 🔴 The two seams are ASYMMETRIC — this is not a
|
|
5455
|
+
standalone switch: the scenario builder reads it only INSIDE the `council === true` branch (sending
|
|
5456
|
+
`debate:true` alone produces no debate rounds), while the explicit-team predicate is
|
|
5457
|
+
`council || debate` (sending it alone still widens the budget and suppresses auto-escalation).
|
|
5458
|
+
Literal `true` only, same as `council`.
|
|
5321
5459
|
resumeAt:
|
|
5322
5460
|
type: string
|
|
5323
5461
|
description: >
|
|
@@ -5503,6 +5641,22 @@ components:
|
|
|
5503
5641
|
items: { type: string }
|
|
5504
5642
|
description: Capability names the caller requires; the worker refuses up front rather than 501-ing mid-run.
|
|
5505
5643
|
memoryWrite: { type: boolean, description: Allow this task to WRITE user memory (read is governed separately). }
|
|
5644
|
+
memoryCapture:
|
|
5645
|
+
type: string
|
|
5646
|
+
enum: [off]
|
|
5647
|
+
description: >
|
|
5648
|
+
server >= 7.70.0 — the SESSION-level memory-capture OPT-OUT declaration: "off" means "this session
|
|
5649
|
+
does not enter long-term memory". A ONE-MEMBER closed set: there is NO "on" spelling, absence is the
|
|
5650
|
+
only way to say "capture as usual".
|
|
5651
|
+
🔴 A DIFFERENT AXIS from `memoryWrite`: that one pauses writes for THIS run and can be flipped back
|
|
5652
|
+
per run; this one is a ONE-WAY, one-shot session record (later resumes never capture, repeat
|
|
5653
|
+
declarations are idempotent, and getting capture back needs a NEW session).
|
|
5654
|
+
🔴 The spelling gate is loud on BOTH legs (no resume downgrade): "OFF" / a boolean / anything else
|
|
5655
|
+
is a 400 `request.field_invalid` — silently dropping a privacy request as a typo is the banned
|
|
5656
|
+
direction. A deployment policy that refuses this principal's opt-out answers 403
|
|
5657
|
+
`memory.capture_optout_denied` (terminal). A worker older than 7.70.0 IGNORES the key silently, so
|
|
5658
|
+
it is not a capability probe. Rides the persisted body onto resume legs.
|
|
5659
|
+
Mid-run flip: POST /v1/runs/{taskId}/memory/capture-optout (the same record, a second ingress).
|
|
5506
5660
|
settings:
|
|
5507
5661
|
type: object
|
|
5508
5662
|
description: >
|
|
@@ -7283,6 +7437,71 @@ components:
|
|
|
7283
7437
|
face drops the whole server.
|
|
7284
7438
|
additionalProperties: { $ref: '#/components/schemas/McpToolFace' }
|
|
7285
7439
|
|
|
7440
|
+
A2aServerSpec:
|
|
7441
|
+
type: object
|
|
7442
|
+
description: >
|
|
7443
|
+
One per-request A2A peer (`TaskRequest.a2aPeers[]`). These six keys are exactly what the service's
|
|
7444
|
+
normalizer copies through — anything else on the entry never reaches the engine. `name`/`url` are
|
|
7445
|
+
required; if ANY present key is malformed the WHOLE peer is dropped (and named in a warn), because a
|
|
7446
|
+
half-applied entry can turn a narrowing intent into a widening.
|
|
7447
|
+
required: [name, url]
|
|
7448
|
+
additionalProperties: false
|
|
7449
|
+
properties:
|
|
7450
|
+
name:
|
|
7451
|
+
type: string
|
|
7452
|
+
minLength: 1
|
|
7453
|
+
maxLength: 128
|
|
7454
|
+
description: 'Stable local name; also the tool-namespace segment (`a2a__<peer>__<skill>`).'
|
|
7455
|
+
url:
|
|
7456
|
+
type: string
|
|
7457
|
+
description: 'The peer service URL; doubles as the origin the well-known agent-card path resolves against. http(s) ONLY.'
|
|
7458
|
+
cardUrl:
|
|
7459
|
+
type: string
|
|
7460
|
+
description: >
|
|
7461
|
+
Explicit agent-card location. When set it is used ALONE (no well-known probing behind the operator's
|
|
7462
|
+
back), so a malformed value drops the peer rather than falling back.
|
|
7463
|
+
headers:
|
|
7464
|
+
type: object
|
|
7465
|
+
additionalProperties: { type: string }
|
|
7466
|
+
description: 'Static headers sent on every request to this peer.'
|
|
7467
|
+
principalHeader:
|
|
7468
|
+
type: string
|
|
7469
|
+
description: >
|
|
7470
|
+
Header name the Runner injects this run's AUTHENTICATED principal into (the model can neither read
|
|
7471
|
+
nor set it). Absent principal => the header is not sent; the peer must then default to deny/public.
|
|
7472
|
+
allowSkills:
|
|
7473
|
+
type: array
|
|
7474
|
+
items: { type: string }
|
|
7475
|
+
description: >
|
|
7476
|
+
Allowlist of remote skill ids to mount. ⚠️ ABSENCE means "no restriction" (core's semantic), so this
|
|
7477
|
+
is a NARROWING key — never express narrowing by omitting it.
|
|
7478
|
+
toolAxes:
|
|
7479
|
+
type: object
|
|
7480
|
+
description: >
|
|
7481
|
+
Per-skill safety-axis overrides keyed by the peer's REMOTE skill id. The caller is the trust root,
|
|
7482
|
+
so this may LOWER the fail-closed default (`egress:true` + `effect:"write"`) as well as raise it.
|
|
7483
|
+
⚠️ Lowering `effect` WITHOUT clearing `egress` is a combination the engine refuses by design.
|
|
7484
|
+
additionalProperties:
|
|
7485
|
+
type: object
|
|
7486
|
+
additionalProperties: false
|
|
7487
|
+
properties:
|
|
7488
|
+
effect: { type: string, enum: [read, write, idempotent] }
|
|
7489
|
+
egress: { type: boolean }
|
|
7490
|
+
irreversibility: { type: string, enum: [always, never] }
|
|
7491
|
+
|
|
7492
|
+
MemoryCaptureOptOutResult:
|
|
7493
|
+
type: object
|
|
7494
|
+
description: >
|
|
7495
|
+
200 body of POST /v1/runs/{taskId}/memory/capture-optout. `outcome` is a closed two-word set:
|
|
7496
|
+
`created` = this call wrote the one-way session record; `existed` = the session had already opted out
|
|
7497
|
+
(idempotent replay).
|
|
7498
|
+
required: [taskId, sessionId, outcome]
|
|
7499
|
+
additionalProperties: false
|
|
7500
|
+
properties:
|
|
7501
|
+
taskId: { type: string }
|
|
7502
|
+
sessionId: { type: string }
|
|
7503
|
+
outcome: { type: string, enum: [created, existed] }
|
|
7504
|
+
|
|
7286
7505
|
MemoryEntryFrontmatter:
|
|
7287
7506
|
type: object
|
|
7288
7507
|
description: >
|
|
@@ -8597,9 +8816,16 @@ components:
|
|
|
8597
8816
|
lane's 200 DO mean the engine committed the decision — one sentence ("approved and in effect") cannot be
|
|
8598
8817
|
used for both lanes.
|
|
8599
8818
|
(2) delivery can still be LOST: if the host run is interrupted before it re-invokes `Workflow`, the
|
|
8600
|
-
decision goes with that invocation (it is not persisted anywhere)
|
|
8601
|
-
|
|
8602
|
-
|
|
8819
|
+
decision goes with that invocation (it is not persisted anywhere); because the card was pending
|
|
8820
|
+
throughout, nothing is forged. Against a server >= 7.72.0 a retry of the SAME decide succeeds — that
|
|
8821
|
+
version gave this lane a second leg that mints a fresh run on the same host session when the host is not
|
|
8822
|
+
currently parked, so the retry either resumes the parked host or starts that new run (byte-identical
|
|
8823
|
+
acceptance shape either way; a host session already busy with another run instead answers the existing
|
|
8824
|
+
`conflict.session_active_run` 409). Against a still-supported server in the [7.69.0, 7.72.0) window
|
|
8825
|
+
(`SUPPORTED_SERVER_FLOOR` is 3.0.0) the retry instead answers 409 `decide.workflow_host_not_parked` —
|
|
8826
|
+
retry once the host parks again, or resume that `runId` yourself. ⚰️ That code is RETIRED at 7.72.0, no
|
|
8827
|
+
alias, and a current server will not send it again — but it remains a live, supported response from an
|
|
8828
|
+
older server in that window, so the SDK still maps it (see `DecideWorkflowHostError`).
|
|
8603
8829
|
The durable approval-queue projection is UNCHANGED — no key marks the workflow origin on any read face.
|
|
8604
8830
|
required: []
|
|
8605
8831
|
additionalProperties: false
|
|
@@ -8940,6 +9166,21 @@ components:
|
|
|
8940
9166
|
one-off question. The value comes WHOLE from core (`summarizeCheckpoint` echoes it only when the
|
|
8941
9167
|
cause is a member of the engine's set), so the server neither recomputes nor re-screens it. See
|
|
8942
9168
|
ClassifierUnavailable for the open-`cause` rule and the three shapes absence covers.
|
|
9169
|
+
RETIRED: server >= 7.72.0 (core 7.14.0 #688) never mints this key on any of the three faces; its
|
|
9170
|
+
successor is `disposition.cause` on the gate record (`unavailable` / `parse_error` — a different
|
|
9171
|
+
question, so an old switch does not port). Kept for servers in [7.69.0, 7.72.0) only (sdk 9.2.0).
|
|
9172
|
+
ruleStoreUnreadable:
|
|
9173
|
+
type: string
|
|
9174
|
+
enum: [store, call]
|
|
9175
|
+
description: >-
|
|
9176
|
+
server >= 7.72.0 (core 7.14.0 #688 C3), ADDITIVE — WHICH HALF of the rule lane could not be read.
|
|
9177
|
+
Present iff `origin === "rule_store_unavailable"`: `store` = the wired rule store could not be read
|
|
9178
|
+
(look at the store / network); `call` = the store was read but THIS command could not be read against
|
|
9179
|
+
the person's deny/ask rows (look at the command spelling). One `origin` word covers both facts, and
|
|
9180
|
+
their recovery verbs live in different places (ops vs prompt). Carried on the live `tool_approval`
|
|
9181
|
+
frame and the inbox row; the `card_json` card deliberately does NOT carry it (it travels with `origin`,
|
|
9182
|
+
which is not on the card). Absence = `origin` is not that word — NOT an assertion that the rule store
|
|
9183
|
+
is healthy.
|
|
8943
9184
|
|
|
8944
9185
|
InboxList:
|
|
8945
9186
|
type: object
|
|
@@ -9681,6 +9922,13 @@ components:
|
|
|
9681
9922
|
- $ref: '#/components/schemas/Event_tool_approval_complete'
|
|
9682
9923
|
- $ref: '#/components/schemas/Event_approval_request'
|
|
9683
9924
|
- $ref: '#/components/schemas/Event_approval_revoke'
|
|
9925
|
+
# sdk 9.1.0: two LIVE-leg arms the service has been emitting while neither this union nor the
|
|
9926
|
+
# SDK's declared them — `text_end` since server 7.66.0 (segment boundary; retires the idle-flush
|
|
9927
|
+
# heuristic) and `tool_roster_delta` since server 7.70.0 (run-time roster change). A generated client
|
|
9928
|
+
# had no arm to switch on and dropped both. Found by the mechanical frame-arm reconciliation gate
|
|
9929
|
+
# (server `routes/tasks.ts` mint points x this union), which now runs on every build.
|
|
9930
|
+
- $ref: '#/components/schemas/Event_text_end'
|
|
9931
|
+
- $ref: '#/components/schemas/Event_tool_roster_delta'
|
|
9684
9932
|
discriminator:
|
|
9685
9933
|
propertyName: type
|
|
9686
9934
|
mapping:
|
|
@@ -9724,6 +9972,8 @@ components:
|
|
|
9724
9972
|
tool_approval_complete: '#/components/schemas/Event_tool_approval_complete'
|
|
9725
9973
|
approval_request: '#/components/schemas/Event_approval_request'
|
|
9726
9974
|
approval_revoke: '#/components/schemas/Event_approval_revoke'
|
|
9975
|
+
text_end: '#/components/schemas/Event_text_end'
|
|
9976
|
+
tool_roster_delta: '#/components/schemas/Event_tool_roster_delta'
|
|
9727
9977
|
|
|
9728
9978
|
# design/99 §E2 (SHIPPED, core TaskEventIdentity) — additive per-event identity on every CONTENT event (NOT on
|
|
9729
9979
|
# the lifecycle arms turn_end/compacted/suspended/done/failed). eventId = uuidv7 dedup/resume handle (the durable
|
|
@@ -9813,6 +10063,27 @@ components:
|
|
|
9813
10063
|
parentToolCallId: { type: string }
|
|
9814
10064
|
sourceTaskId: { type: string }
|
|
9815
10065
|
bgAgentId: { type: string }
|
|
10066
|
+
Event_text_end:
|
|
10067
|
+
type: object
|
|
10068
|
+
description: >
|
|
10069
|
+
LIVE stream only (server >= 7.66.0, core 5.62.0) — the END-OF-SEGMENT signal for one assistant text
|
|
10070
|
+
segment. `content` is the segment's AUTHORITATIVE full text (same trust class as `text_delta`, same
|
|
10071
|
+
zero content transformation). It retires the "no delta for N ms => the segment must be over" idle-flush
|
|
10072
|
+
heuristic: the boundary is now stated by the engine, not guessed by a timer.
|
|
10073
|
+
🔴 A TRUNCATED segment gets NO such frame (core deliberately withholds it) — "no text_end" does NOT
|
|
10074
|
+
mean "the segment is still going". 🔴 The durable leg does not append it (the batched `text` event
|
|
10075
|
+
carries the same final prose), so GET /v1/runs/{id}/events never replays it. Both mint points are in
|
|
10076
|
+
`routes/tasks.ts`: the top stream (all four identity keys) and the forwarded sub-agent leg (first two).
|
|
10077
|
+
allOf: [{ $ref: '#/components/schemas/EventIdentity' }]
|
|
10078
|
+
additionalProperties: false # 封闭 + identity 本地镜像:见 Event_reasoning 处的长注
|
|
10079
|
+
required: [type, content]
|
|
10080
|
+
properties:
|
|
10081
|
+
type: { const: text_end }
|
|
10082
|
+
content: { type: string }
|
|
10083
|
+
eventId: { type: string }
|
|
10084
|
+
parentToolCallId: { type: string }
|
|
10085
|
+
sourceTaskId: { type: string }
|
|
10086
|
+
bgAgentId: { type: string }
|
|
9816
10087
|
Event_tool_start:
|
|
9817
10088
|
type: object
|
|
9818
10089
|
allOf: [{ $ref: '#/components/schemas/EventIdentity' }]
|
|
@@ -9982,6 +10253,18 @@ components:
|
|
|
9982
10253
|
properties:
|
|
9983
10254
|
kind: { const: denied }
|
|
9984
10255
|
deniedBy: { $ref: '#/components/schemas/DeniedBy' }
|
|
10256
|
+
cause:
|
|
10257
|
+
type: string
|
|
10258
|
+
description: >-
|
|
10259
|
+
server >= 7.72.0 (core 7.14.0 #688 C-a) — the SHAPE of this deny when the auto-mode classifier was
|
|
10260
|
+
the refusing layer: `unavailable` (that classifier round could not run: threw / refused / over cap)
|
|
10261
|
+
or `parse_error` (it ran but answered outside the verdict contract, so the call was stopped to be
|
|
10262
|
+
safe). Successor seat of the retired `classifierUnavailable` key (minted once by the engine, carried
|
|
10263
|
+
on both `tool_end.gate` and `permissionDenied.gate`) — but NOT the same question as the old `cause`
|
|
10264
|
+
(`error` / `timeout` answered WHY it was unavailable), so an old switch does not port. The
|
|
10265
|
+
vocabulary's owner is the engine (`CLASSIFIER_DENY_CAUSES`); the server passes it through verbatim
|
|
10266
|
+
— branch the two known words and keep a default arm. Absent = this deny was not a classifier-fault
|
|
10267
|
+
shape (policy / person / rule refused); never read absence as "classifier healthy".
|
|
9985
10268
|
|
|
9986
10269
|
GateOutcome:
|
|
9987
10270
|
type: object
|
|
@@ -10020,7 +10303,7 @@ components:
|
|
|
10020
10303
|
# 服务对缺陷记录是整条不上帧 ⇒ 词表外的值在这条 wire 上到不了消费端。审批帧那一面不判成员,
|
|
10021
10304
|
# 所以 `AskOrigin` 本体保持真开(见该 schema 的长注)。这张 enum 是本 spec 里该词表的**唯一**
|
|
10022
10305
|
# 执法点;core 加词时改这一处。
|
|
10023
|
-
- enum: [content_question,
|
|
10306
|
+
- enum: [content_question, ancestor_marked, org_unavailable, org_rule, rule_store_unavailable, hook, ask_rule, denial_limit_fallback, shell_gate_tighten, safety_tighten, policy]
|
|
10024
10307
|
description: >
|
|
10025
10308
|
WHO ASKED. Same-present/same-absent as `settlement` (I1). CLOSED here (and only here) — see the
|
|
10026
10309
|
enum note above.
|
|
@@ -10585,6 +10868,59 @@ components:
|
|
|
10585
10868
|
parentToolCallId: { type: string }
|
|
10586
10869
|
sourceTaskId: { type: string }
|
|
10587
10870
|
bgAgentId: { type: string }
|
|
10871
|
+
Event_tool_roster_delta:
|
|
10872
|
+
type: object
|
|
10873
|
+
description: >
|
|
10874
|
+
A RUN-TIME roster change (server >= 7.70.0, core 7.8.0; live-only until 7.71.0, see below).
|
|
10875
|
+
`wiring_manifest.tools` is the snapshot taken when this leg started; this frame is the increment after
|
|
10876
|
+
it: one refresh that actually changed the roster emits EXACTLY one frame (ordered after the manifest and
|
|
10877
|
+
before that refresh's own `tool_end`).
|
|
10878
|
+
🔴 A `delta.fromDigest` that does not match what the consumer holds is NOT a rejection: `delta.roster`
|
|
10879
|
+
is the new state regardless — record a skew and re-sync from the whole roster (only `delta.summary`
|
|
10880
|
+
becomes unusable). 🔴 Half a roster never reaches the wire: the service drops the WHOLE frame when
|
|
10881
|
+
core's own typebox check rejects the payload. 🔴 Durable legs (server >= 7.71.0, S-212): BOTH durable legs
|
|
10882
|
+
append it too (the three legs share one mint point), so the raw replay `GET /v1/runs/{id}/events`
|
|
10883
|
+
(`runs.events()`, `AgentEvent`) DOES carry it after a reconnect. What still never carries it is the
|
|
10884
|
+
projected trace stream `GET /v1/tasks/{id}/stream` (`trace.stream()`, `TraceStreamEvent`, `mapTraceEvent`
|
|
10885
|
+
drops it with `wiring_manifest` / `human_input`) — consumers on THAT leg keep re-syncing from the
|
|
10886
|
+
`wiring_manifest.tools` snapshot. (Before 7.71.0 the frame was live-only.)
|
|
10887
|
+
allOf: [{ $ref: '#/components/schemas/EventIdentity' }]
|
|
10888
|
+
additionalProperties: false # 封闭 + identity 本地镜像:见 Event_reasoning 处的长注
|
|
10889
|
+
required: [type, delta]
|
|
10890
|
+
properties:
|
|
10891
|
+
type: { const: tool_roster_delta }
|
|
10892
|
+
delta: { $ref: '#/components/schemas/ToolRosterDelta' }
|
|
10893
|
+
eventId: { type: string }
|
|
10894
|
+
parentToolCallId: { type: string }
|
|
10895
|
+
sourceTaskId: { type: string }
|
|
10896
|
+
bgAgentId: { type: string }
|
|
10897
|
+
ToolRosterDelta:
|
|
10898
|
+
type: object
|
|
10899
|
+
description: >
|
|
10900
|
+
core `ToolRosterDelta` (core 7.8.0) — the payload of `tool_roster_delta`. `roster` is the WHOLE
|
|
10901
|
+
post-change roster and positions come from IT, never from `summary`; the three `summary` lists are
|
|
10902
|
+
pairwise disjoint and a `changed` name's new row lives in `roster`.
|
|
10903
|
+
🔴 OPEN on purpose (`additionalProperties: true`), unlike the frame that carries it. The rule: a schema is
|
|
10904
|
+
CLOSED where the SERVICE builds the object key by key (every `Event_*` arm), and OPEN where the service
|
|
10905
|
+
forwards a CORE-owned payload VERBATIM and keeps no key table of its own. This payload is the latter (the
|
|
10906
|
+
service passes `delta` through after core's own typebox check), so closing it would turn a future core key
|
|
10907
|
+
into "every legitimate frame is a violation". `ToolRoster` is closed despite the same provenance because
|
|
10908
|
+
the service DOES keep a compile-time key table for it.
|
|
10909
|
+
required: [fromDigest, roster, summary]
|
|
10910
|
+
additionalProperties: true
|
|
10911
|
+
properties:
|
|
10912
|
+
fromDigest:
|
|
10913
|
+
type: string
|
|
10914
|
+
description: 'The digest the consumer is expected to hold. A mismatch is a SKEW (re-sync from `roster`), never a rejection.'
|
|
10915
|
+
roster: { $ref: '#/components/schemas/ToolRoster' }
|
|
10916
|
+
summary:
|
|
10917
|
+
type: object
|
|
10918
|
+
required: [added, removed, changed]
|
|
10919
|
+
additionalProperties: true # same rule as the parent — core owns this payload's key table.
|
|
10920
|
+
properties:
|
|
10921
|
+
added: { type: array, items: { type: string } }
|
|
10922
|
+
removed: { type: array, items: { type: string } }
|
|
10923
|
+
changed: { type: array, items: { type: string } }
|
|
10588
10924
|
ToolRoster:
|
|
10589
10925
|
type: object
|
|
10590
10926
|
description: >
|
|
@@ -10625,7 +10961,13 @@ components:
|
|
|
10625
10961
|
capabilityId: { type: string }
|
|
10626
10962
|
effect: { type: string, enum: [read, write, idempotent] }
|
|
10627
10963
|
egress: { type: boolean }
|
|
10628
|
-
irreversibility:
|
|
10964
|
+
irreversibility:
|
|
10965
|
+
type: string
|
|
10966
|
+
enum: [always, maybe, never]
|
|
10967
|
+
description: >
|
|
10968
|
+
core's THREE-word set (`never` / `maybe` / `always`). `maybe` is a real emitted value (e.g. a shell
|
|
10969
|
+
tool under a classifying gate), so a two-word mirror rejects an entire legitimate roster and leaves
|
|
10970
|
+
the consumer on stale state.
|
|
10629
10971
|
contentOrigin: { type: string, enum: [local, execution, external] }
|
|
10630
10972
|
family: { type: string, enum: [shell, file-read, file-write, search, web, delegate, plan, scaffold, memory, protocol, other] }
|
|
10631
10973
|
pathTarget: { $ref: '#/components/schemas/McpToolPathTarget' }
|
|
@@ -11400,6 +11742,21 @@ components:
|
|
|
11400
11742
|
server >= 7.69.0 (core 7.10.0 #616), ADDITIVE, present only when the classifier was consulted and
|
|
11401
11743
|
could not run — WHY this ask reached a human. See ClassifierUnavailable for the open-`cause` rule and
|
|
11402
11744
|
the three shapes absence covers.
|
|
11745
|
+
RETIRED: server >= 7.72.0 (core 7.14.0 #688) never mints this key on any of the three faces; its
|
|
11746
|
+
successor is `disposition.cause` on the gate record (`unavailable` / `parse_error` — a different
|
|
11747
|
+
question, so an old switch does not port). Kept for servers in [7.69.0, 7.72.0) only (sdk 9.2.0).
|
|
11748
|
+
ruleStoreUnreadable:
|
|
11749
|
+
type: string
|
|
11750
|
+
enum: [store, call]
|
|
11751
|
+
description: >-
|
|
11752
|
+
server >= 7.72.0 (core 7.14.0 #688 C3), ADDITIVE — WHICH HALF of the rule lane could not be read.
|
|
11753
|
+
Present iff `origin === "rule_store_unavailable"`: `store` = the wired rule store could not be read
|
|
11754
|
+
(look at the store / network); `call` = the store was read but THIS command could not be read against
|
|
11755
|
+
the person's deny/ask rows (look at the command spelling). One `origin` word covers both facts, and
|
|
11756
|
+
their recovery verbs live in different places (ops vs prompt). Carried on the live `tool_approval`
|
|
11757
|
+
frame and the inbox row; the `card_json` card deliberately does NOT carry it (it travels with `origin`,
|
|
11758
|
+
which is not on the card). Absence = `origin` is not that word — NOT an assertion that the rule store
|
|
11759
|
+
is healthy.
|
|
11403
11760
|
ApprovalRequestFrame:
|
|
11404
11761
|
type: object
|
|
11405
11762
|
description: >
|
|
@@ -11538,6 +11895,9 @@ components:
|
|
|
11538
11895
|
server >= 7.69.0 (core 7.10.0 #616), ADDITIVE — WHY this ask reached a human. Frame and card carry
|
|
11539
11896
|
the SAME value (one narrow-read function server-side). See ClassifierUnavailable for the open-`cause`
|
|
11540
11897
|
rule and the three shapes absence covers.
|
|
11898
|
+
RETIRED: server >= 7.72.0 (core 7.14.0 #688) never mints this key on any of the three faces; its
|
|
11899
|
+
successor is `disposition.cause` on the gate record (`unavailable` / `parse_error` — a different
|
|
11900
|
+
question, so an old switch does not port). Kept for servers in [7.69.0, 7.72.0) only (sdk 9.2.0).
|
|
11541
11901
|
|
|
11542
11902
|
RuleSuggestion:
|
|
11543
11903
|
type: object
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sema-agent/sdk",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.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",
|