@sema-agent/sdk 4.1.0 → 4.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.
Files changed (58) hide show
  1. package/README.md +22 -1
  2. package/dist/client.d.ts +10 -1
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +7 -2
  5. package/dist/client.js.map +1 -1
  6. package/dist/errors.d.ts +42 -5
  7. package/dist/errors.d.ts.map +1 -1
  8. package/dist/errors.js +81 -7
  9. package/dist/errors.js.map +1 -1
  10. package/dist/events.d.ts +63 -1
  11. package/dist/events.d.ts.map +1 -1
  12. package/dist/events.js.map +1 -1
  13. package/dist/health.d.ts +2 -2
  14. package/dist/health.js +1 -1
  15. package/dist/idempotency.d.ts +11 -1
  16. package/dist/idempotency.d.ts.map +1 -1
  17. package/dist/idempotency.js +11 -1
  18. package/dist/idempotency.js.map +1 -1
  19. package/dist/index.d.ts +8 -2
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +7 -1
  22. package/dist/index.js.map +1 -1
  23. package/dist/resources/approvals.d.ts +43 -13
  24. package/dist/resources/approvals.d.ts.map +1 -1
  25. package/dist/resources/approvals.js +35 -12
  26. package/dist/resources/approvals.js.map +1 -1
  27. package/dist/resources/assistant.d.ts +21 -4
  28. package/dist/resources/assistant.d.ts.map +1 -1
  29. package/dist/resources/assistant.js +10 -3
  30. package/dist/resources/assistant.js.map +1 -1
  31. package/dist/resources/fleet.d.ts +8 -3
  32. package/dist/resources/fleet.d.ts.map +1 -1
  33. package/dist/resources/fleet.js +2 -1
  34. package/dist/resources/fleet.js.map +1 -1
  35. package/dist/resources/runs.d.ts +89 -18
  36. package/dist/resources/runs.d.ts.map +1 -1
  37. package/dist/resources/runs.js +53 -17
  38. package/dist/resources/runs.js.map +1 -1
  39. package/dist/resources/sessions.d.ts +10 -1
  40. package/dist/resources/sessions.d.ts.map +1 -1
  41. package/dist/resources/sessions.js +10 -1
  42. package/dist/resources/sessions.js.map +1 -1
  43. package/dist/resources/tool-approvals.d.ts +8 -5
  44. package/dist/resources/tool-approvals.d.ts.map +1 -1
  45. package/dist/resources/tool-approvals.js +2 -1
  46. package/dist/resources/tool-approvals.js.map +1 -1
  47. package/dist/sse.d.ts +58 -14
  48. package/dist/sse.d.ts.map +1 -1
  49. package/dist/sse.js +88 -15
  50. package/dist/sse.js.map +1 -1
  51. package/dist/transport.d.ts +14 -1
  52. package/dist/transport.d.ts.map +1 -1
  53. package/dist/transport.js +20 -5
  54. package/dist/transport.js.map +1 -1
  55. package/dist/types.d.ts +70 -42
  56. package/dist/types.d.ts.map +1 -1
  57. package/openapi.yaml +205 -5
  58. package/package.json +1 -1
package/openapi.yaml CHANGED
@@ -494,12 +494,20 @@ paths:
494
494
  turn (FIFO), spread across turns. FORWARD-DRAFT: core's steer is harness-level today, not
495
495
  per-call; the per-call mapping is pending D-A core.
496
496
  responses:
497
- '200': { description: Steer accepted and applied. }
497
+ '200':
498
+ description: Steer accepted and APPLIED to the live run on this replica (`delivery:"applied"`).
499
+ content:
500
+ application/json:
501
+ schema: { $ref: '#/components/schemas/SteerReceipt' }
498
502
  '202':
499
503
  description: >-
500
- Steer accepted and QUEUED. Two shapes share this code: a live run queues to the next turn-boundary
501
- drain; a durable-`suspended` run parks on its pending checkpoint
502
- (`{status:"suspended", delivery:"queued"}`) and drains on resume.
504
+ Steer accepted and PARKED. Two shapes share this code — branch on `delivery`, not the status:
505
+ a durable-`suspended` run parks on its pending checkpoint (`delivery:"queued"`) and drains on resume;
506
+ an ALREADY-ENDED run gets a freshly-minted `task_done` checkpoint (`delivery:"parked_for_wake"`) and
507
+ the message is delivered only by POST /v1/sessions/{sessionId}/wake.
508
+ content:
509
+ application/json:
510
+ schema: { $ref: '#/components/schemas/SteerReceipt' }
503
511
  '401': { $ref: '#/components/responses/Unauthorized' }
504
512
  '404': { $ref: '#/components/responses/NotFound' }
505
513
  '409':
@@ -2070,7 +2078,17 @@ paths:
2070
2078
  application/json:
2071
2079
  schema: { $ref: '#/components/schemas/ErrorResponse' }
2072
2080
  '401': { $ref: '#/components/responses/Unauthorized' }
2073
- '404': { $ref: '#/components/responses/NotFound' }
2081
+ '404':
2082
+ description: >
2083
+ Owner-gate / unknown session (no existence oracle), OR — [2400] CB-2, declared 2026-08-02 — the core
2084
+ code `checkpoint.not_found`: the pending checkpoint this decide addressed is gone. It is the ONE
2085
+ member of the mirrored `checkpoint.*` family the server sends as a 404 rather than a 409
2086
+ (`src/http/server.ts:2199`: `e.code === "checkpoint.not_found" ? 404 : 409`), so the SDK maps it to
2087
+ NotFoundError while the rest of the family maps to ConflictError. Client action: refetch the inbox —
2088
+ do not retry this decide.
2089
+ content:
2090
+ application/json:
2091
+ schema: { $ref: '#/components/schemas/ErrorResponse' }
2074
2092
  '409':
2075
2093
  description: >
2076
2094
  Either a session-CAS conflict (`ErrorResponse.activeTaskId`), OR a design/80 D-1
@@ -2078,6 +2096,20 @@ paths:
2078
2096
  NOT match the current pending action (TOCTOU/swap). The SDK splits these by `errorCode` into
2079
2097
  ConflictError vs ApprovalBindingMismatchError. binding_mismatch = SAFETY signal: refetch + re-present
2080
2098
  to the human, NEVER auto-retry.
2099
+ FOURTH member ([2400] CB-2, declared 2026-08-02): `gate_not_tool_approval` — the suspension this
2100
+ sessionId is parked on is NOT a tool-approval gate (`src/http/server.ts:1581` rejects pre-CAS when the
2101
+ gate kind is neither `human` nor `irreversible_ask`: nothing is consumed, no model leg burns). It is
2102
+ the THIRD member of the wrong-door guard family alongside `gate_not_resumable` (§4b) and
2103
+ `gate_not_plan_review` (§4c) → SDK `GateNotToolApprovalError`. Client action: route by the row's
2104
+ `gateKind` — `plan_review` → `POST /v1/assistant/tasks/{taskId}/plan_review`, `resource_limit` →
2105
+ `POST /v1/assistant/tasks/{taskId}/resume`. Retrying the same body never succeeds.
2106
+ FIFTH group ([2400] CB-2): the core `checkpoint.*` family the server mirrors verbatim
2107
+ (`src/http/server.ts:2199-2206`) — `checkpoint.gate_mismatch` / `checkpoint.reopen_failed` /
2108
+ `checkpoint.reopen_revote` / `checkpoint.already_exists` / `checkpoint.resume_aborted` /
2109
+ `checkpoint.unsupported_version` all arrive as 409 and fall on the SDK's `checkpoint.` PREFIX family
2110
+ (→ ConflictError, `.errorCode` carried verbatim; an OPEN set, so a future core code degrades with
2111
+ information instead of collapsing anonymously). The one non-409 member is `checkpoint.not_found`,
2112
+ which the same mint point sends as a 404 (see below).
2081
2113
  THIRD member (moved here from a documented-but-nonexistent 410, 2026-07-31): `approval_stale`
2082
2114
  (`errorCode`; `terminal:"resolved"` when attributable, else the key is absent) — the checkpoint is
2083
2115
  already terminal (someone resolved it / abandonment-TTL GC / SLA resolve-deny). Client action:
@@ -3981,6 +4013,17 @@ components:
3981
4013
  objective:
3982
4014
  type: string
3983
4015
  description: The task. Put per-request context here (keep `systemPrompt` stable/cacheable).
4016
+ taskId:
4017
+ type: string
4018
+ description: >-
4019
+ [2400] TR-16 (declared 2026-08-02) — CALLER-MINTED uuidv7 task id: the DURABLE second tier of
4020
+ idempotency on POST /v1/runs (`src/http/routes/runs.ts:196-217`). The `Idempotency-Key` header's
4021
+ cache is in-memory and PER-POD, so a dispatch gateway that re-routes a retry to ANOTHER instance
4022
+ after a network error would start a SECOND run; THIS replay reads the durable run store, so it
4023
+ survives the re-route and a restart — it is the prerequisite for gateway failover. A hit replays the
4024
+ original 202 receipt (`{taskId, sessionId, status}`); nothing re-runs, nothing re-bills.
4025
+ Shape-gated: a non-uuidv7 value is 400 `request.id_invalid`. Owner-gated: a taskId owned by another
4026
+ principal answers 409 `conflict.run_exists` (no cross-tenant id oracle). Omit ⇒ the server mints one.
3984
4027
  scenario: { $ref: '#/components/schemas/Scenario' }
3985
4028
  sessionId:
3986
4029
  type: string
@@ -4776,6 +4819,20 @@ components:
4776
4819
  description: >
4777
4820
  Approve-with-edit (design/37 last-wins): operator's rewritten tool args, applied AFTER the binding
4778
4821
  check. `boundInputHash` STILL binds the ORIGINAL input the human saw — never hash updatedInput.
4822
+ remember:
4823
+ type: string
4824
+ enum: [session]
4825
+ description: >-
4826
+ [2400] HITL-4 (declared 2026-08-02) — the "don't ask again in this session" grant: lands a
4827
+ per-session, per-toolName approval EXEMPTION alongside the decision (server
4828
+ `routes/approvals-assistant.ts` reads it; the SDK has typed it since the facade audit, the spec had
4829
+ not). It is an approval MEMORY, not a policy loosen — a deny / neverAuto always outranks it.
4830
+ Constraints (all server-enforced): only with `decision:"approve"` (else 400
4831
+ `request.field_conflict`); requires the D-1 binding echo in the same body (else 400
4832
+ `remember_requires_binding`); REFUSED on a direct-door worker (400 `remember_not_in_proof` — it is
4833
+ not inside the HMAC payload, so accepting it unsigned would be tamperable); 501 without an exemption
4834
+ store. On the parked-background-agent leg the grant lands on the child's ROOT/HOST session (the whole
4835
+ session tree shares it). The 200 body echoes `rememberApplied` when a store is wired.
4779
4836
 
4780
4837
  ApprovalRow:
4781
4838
  type: object
@@ -6779,6 +6836,13 @@ components:
6779
6836
  - $ref: '#/components/schemas/Event_message_committed'
6780
6837
  # [2373]A-2(2026-08-03,server 5.0.0):compaction_outcome 三腿同源批的 spec 半场(SDK 臂 20867e1 同批)。
6781
6838
  - $ref: '#/components/schemas/Event_compaction_outcome'
6839
+ # [2400] ch2(SDK 4.2.0):CB-1 流控帽帧 + TR-7 durable 五臂 —— 两侧同缺,见各 schema 处的注。
6840
+ - $ref: '#/components/schemas/Event_error'
6841
+ - $ref: '#/components/schemas/Event_question'
6842
+ - $ref: '#/components/schemas/Event_question_complete'
6843
+ - $ref: '#/components/schemas/Event_elicitation'
6844
+ - $ref: '#/components/schemas/Event_elicitation_complete'
6845
+ - $ref: '#/components/schemas/Event_workflow_complete'
6782
6846
  discriminator:
6783
6847
  propertyName: type
6784
6848
  mapping:
@@ -6809,6 +6873,12 @@ components:
6809
6873
  needs_review: '#/components/schemas/Event_needs_review'
6810
6874
  message_committed: '#/components/schemas/Event_message_committed'
6811
6875
  compaction_outcome: '#/components/schemas/Event_compaction_outcome'
6876
+ error: '#/components/schemas/Event_error'
6877
+ question: '#/components/schemas/Event_question'
6878
+ question_complete: '#/components/schemas/Event_question_complete'
6879
+ elicitation: '#/components/schemas/Event_elicitation'
6880
+ elicitation_complete: '#/components/schemas/Event_elicitation_complete'
6881
+ workflow_complete: '#/components/schemas/Event_workflow_complete'
6812
6882
 
6813
6883
  # design/99 §E2 (SHIPPED, core TaskEventIdentity) — additive per-event identity on every CONTENT event (NOT on
6814
6884
  # the lifecycle arms turn_end/compacted/suspended/done/failed). eventId = uuidv7 dedup/resume handle (the durable
@@ -7728,6 +7798,102 @@ components:
7728
7798
  sourceTaskId: { type: string }
7729
7799
  bgAgentId: { type: string }
7730
7800
 
7801
+ # ══════════════════════════════════════════════════════════════════════════════════════════════
7802
+ # [2400] 说明书审计 ch2(SDK 4.2.0)补的**六个未登记臂**:一个流控帧(CB-1/TR-6)+ 五个 HITL/workflow
7803
+ # 帧(TR-7)。同一个盲区:`spec-union-arm-gate` 比的是 spec ↔ SDK 两侧的臂集,这六个两侧同缺 ⇒ 那道门
7804
+ # 对它们结构性失明;抓到它们靠的是拿 server 的 `res.write("event: …")` / `append("…")` 铸造点第三方对账。
7805
+ # ══════════════════════════════════════════════════════════════════════════════════════════════
7806
+ Event_error:
7807
+ type: object
7808
+ description: >
7809
+ STREAM-CONTROL frame, NOT a run failure (server src/http/sse-log.ts:86; the trace leg emits the same
7810
+ shape at routes/trace-usage.ts:294). The server writes it as a NAMED frame (`event: error`) whose payload
7811
+ echoes `type`, so both an `event:`-dispatching client and a payload-dispatching one see it.
7812
+ 🔴 Its arrival means the RUN IS STILL ALIVE — the 15-minute stream cap fired. The correct handling is to
7813
+ RECONNECT with `Last-Event-ID` and keep reading (the durable leg stamps `id:` on every frame); rendering
7814
+ it as a terminal would declare a live task dead. `done` / `failed` are the terminal arms; this one is not.
7815
+ Known `errorCode`: `STREAM_MAX_DURATION` (open set — branch on the code, degrade unknown codes to the
7816
+ generic "reconnectable stream-control signal").
7817
+ additionalProperties: false
7818
+ required: [type, errorCode]
7819
+ properties:
7820
+ type: { const: error }
7821
+ errorCode: { type: string, description: 'STREAM_MAX_DURATION (open set).' }
7822
+ message: { type: string }
7823
+ Event_question:
7824
+ type: object
7825
+ description: >
7826
+ AskUserQuestion OPEN frame (server src/question.ts:38 `QuestionFrame`). The live leg dispatches it by SSE
7827
+ event name (routes/tasks.ts:677, the same out-of-band channel as `elicitation`/`tool_approval`); the
7828
+ DURABLE leg persists it via `append(type, rest)` (src/runs.ts:498), so the same frame also replays on
7829
+ GET /v1/runs/:id/events — that half is what this schema registers.
7830
+ 🔴 UNTRUSTED-for-display: `questions` is secret-redacted, render only, NEVER re-feed to a model.
7831
+ `questions` absent ⇒ the payload exceeded the 16 KiB cap and was dropped (the ask headless-defaults).
7832
+ additionalProperties: false
7833
+ required: [type, questionId]
7834
+ properties:
7835
+ type: { const: question }
7836
+ questionId: { type: string }
7837
+ questions:
7838
+ type: array
7839
+ items: { $ref: '#/components/schemas/AskQuestion' }
7840
+ Event_question_complete:
7841
+ type: object
7842
+ description: >
7843
+ AskUserQuestion CLOSE frame (dialog-dismiss signal). `answered` = a human responded; `unanswered` =
7844
+ ttl / abort / throttle released it and the model got the headless default. Cosmetic — it does not change
7845
+ the run's status.
7846
+ additionalProperties: false
7847
+ required: [type, questionId]
7848
+ properties:
7849
+ type: { const: question_complete }
7850
+ questionId: { type: string }
7851
+ outcome: { type: string, enum: [answered, unanswered] }
7852
+ Event_elicitation:
7853
+ type: object
7854
+ description: >
7855
+ Inbound-MCP elicitation OPEN frame (server src/elicitation.ts:42 `ElicitationFrame`). Same two legs as
7856
+ `question`: live dispatches by event name, the durable leg persists + replays it.
7857
+ 🔴 UNTRUSTED: `message` is fenced + secret-redacted; `requestedSchema` is an OPAQUE passthrough (never
7858
+ interpreted/validated) and must still be fenced on display. v1 is always `mode: "form"` (url-mode is
7859
+ rejected upstream as a phishing surface).
7860
+ additionalProperties: false
7861
+ required: [type, elicitationId, mcpServerName]
7862
+ properties:
7863
+ type: { const: elicitation }
7864
+ elicitationId: { type: string }
7865
+ mcpServerName: { type: string }
7866
+ message: { type: string }
7867
+ requestedSchema: {}
7868
+ mode: { type: string, enum: [form] }
7869
+ Event_elicitation_complete:
7870
+ type: object
7871
+ description: 'Inbound-MCP elicitation CLOSE frame; `action` is how it settled (the dialog-dismiss reason).'
7872
+ additionalProperties: false
7873
+ required: [type, elicitationId, mcpServerName]
7874
+ properties:
7875
+ type: { const: elicitation_complete }
7876
+ elicitationId: { type: string }
7877
+ mcpServerName: { type: string }
7878
+ action: { type: string, enum: [accept, decline, cancel] }
7879
+ Event_workflow_complete:
7880
+ type: object
7881
+ description: >
7882
+ Out-of-band delivery of an async workflow's completion (server
7883
+ src/orchestration/workflow-completion-inbox.ts:522). Delivery is STREAM-OPEN driven: the session's inbox
7884
+ is drained on its NEXT leg — the sync leg writes a live frame, the bg/resume legs `append` it as a durable
7885
+ event the tailing client replays.
7886
+ 🔴 AT-LEAST-ONCE (two-phase: the entry is acked only after a successful emit, and two legs racing the same
7887
+ session may double-emit) — consumers MUST dedup on `runId`. `summary` is redacted free text
7888
+ (UNTRUSTED-for-display).
7889
+ additionalProperties: false
7890
+ required: [type, runId, status, summary]
7891
+ properties:
7892
+ type: { const: workflow_complete }
7893
+ runId: { type: string }
7894
+ status: { type: string }
7895
+ summary: { type: string }
7896
+
7731
7897
  # ── resources/*.ts schema backfill, batch 2 (2026-07-28) — the 28-item WIRE_PENDING ratchet zeroed.
7732
7898
  # Each schema below is cross-checked against the server source (file:line cited in its description
7733
7899
  # or in the SDK resource JSDoc it mirrors). Wire objects are OPEN sets (additionalProperties: true).
@@ -8048,6 +8214,40 @@ components:
8048
8214
  taskId: { type: string, description: 'Issuing task, when recorded. Additive / tolerate-absent.' }
8049
8215
  sessionId: { type: string, description: 'Issuing session, when recorded. Additive / tolerate-absent.' }
8050
8216
 
8217
+ SteerPriority:
8218
+ type: string
8219
+ enum: [now, next, later]
8220
+ description: >-
8221
+ [2400] TR-4 — per-message queue priority on POST /v1/runs/{taskId}/steer. ACCEPTED + ENUM-VALIDATED
8222
+ FAIL-LOUD (`routes/runs.ts:603`; anything else is 400 `request.field_invalid`) and echoed back on the
8223
+ receipt, but ADVISORY today: core's steer is a single-slot last-writer-wins with no per-message priority
8224
+ or addressable drop, so a faithful priority queue (and DELETE /v1/runs/{taskId}/queue/{messageId}) waits
8225
+ on a core seam.
8226
+
8227
+ SteerReceipt:
8228
+ type: object
8229
+ description: >
8230
+ [2400] TR-4 — the POST /v1/runs/{taskId}/steer receipt, DISCRIMINATED on `delivery` (three server mint
8231
+ points meaning three different things; branch on this, NOT on the status code):
8232
+ `applied` (200, `routes/runs.ts:648`) — injected into the run LIVE on this replica, drains at the next
8233
+ turn boundary (`status:"running"`);
8234
+ `queued` (202, `:641`) — the run is durably SUSPENDED, so the steer was PARKED on its pending checkpoint
8235
+ and is injected on resume (`status:"suspended"`);
8236
+ `parked_for_wake` (202, `:734`) — the run already ENDED; the server minted a `task_done` checkpoint and
8237
+ parked the message on it, delivered ONLY by POST /v1/sessions/{sessionId}/wake — nothing happens until
8238
+ the session is woken.
8239
+ `messageId` is server-minted and stable across all three (dedup / correlation handle).
8240
+ required: [taskId, status, delivery, messageId]
8241
+ # 封闭:三个铸造点是逐字面量拼出来的对象(routes/runs.ts:641/648/734),不是引擎透传形。
8242
+ additionalProperties: false
8243
+ properties:
8244
+ taskId: { type: string }
8245
+ status: { type: string, description: 'The run status the server saw at delivery time (running | suspended | a terminal status).' }
8246
+ delivery: { type: string, enum: [applied, queued, parked_for_wake] }
8247
+ messageId: { type: string, description: 'Server-minted, stable across all three legs.' }
8248
+ priority: { $ref: '#/components/schemas/SteerPriority' }
8249
+ note: { type: string, description: 'Human-readable note on the two parked legs; absent on `applied`.' }
8250
+
8051
8251
  SubagentSteerReceipt:
8052
8252
  type: object
8053
8253
  description: >
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/sdk",
3
- "version": "4.1.0",
3
+ "version": "4.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",