@sema-agent/sdk 0.0.119 → 0.0.121

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 (2) hide show
  1. package/openapi.yaml +267 -7
  2. package/package.json +1 -1
package/openapi.yaml CHANGED
@@ -719,6 +719,263 @@ paths:
719
719
  '404': { $ref: '#/components/responses/NotFound' }
720
720
  '501': { $ref: '#/components/responses/NotImplemented' }
721
721
 
722
+ /v1/sessions/{sessionId}/head:
723
+ parameters:
724
+ - $ref: '#/components/parameters/PrincipalHeader'
725
+ - in: path
726
+ name: sessionId
727
+ required: true
728
+ schema: { type: string }
729
+ get:
730
+ tags: [sessions]
731
+ operationId: sessionsHead
732
+ x-status: live # [1075]② session-follow light probe (server >=1.225).
733
+ summary: Light session-follow probe — the leaf pointer as a natural version number.
734
+ description: >
735
+ [1075]② — `leafId` is the session tree's leaf pointer; ANY append changes it, so it doubles as a
736
+ version number. Serves an ETag (`"<leafId>"`, `"empty"` when the session has no entries); poll with
737
+ `If-None-Match` and a hit is a zero-body 304 (idle-poll cost ≈ 0 — the deliberate alternative to a
738
+ cross-replica session SSE fan-out; the SSE face `/events` exists separately, connection-capped).
739
+ Owner-scoped (non-owner → 404, no existence oracle). 501 without a durable session store
740
+ (SESSION_BACKEND=tidb|pg|local).
741
+ parameters:
742
+ - in: header
743
+ name: If-None-Match
744
+ required: false
745
+ schema: { type: string }
746
+ description: Previous ETag; on match the response is 304 with no body.
747
+ responses:
748
+ '200':
749
+ description: The current leaf pointer (ETag header carries the same value).
750
+ content:
751
+ application/json:
752
+ schema:
753
+ type: object
754
+ required: [sessionId, leafId]
755
+ properties:
756
+ sessionId: { type: string }
757
+ leafId: { type: string, nullable: true, description: "null = session exists but has no entries yet." }
758
+ '304': { description: 'Leaf unchanged since the presented ETag (no body).' }
759
+ '401': { $ref: '#/components/responses/Unauthorized' }
760
+ '404': { $ref: '#/components/responses/NotFound' }
761
+ '501': { $ref: '#/components/responses/NotImplemented' }
762
+
763
+ /v1/sessions/{sessionId}/events:
764
+ parameters:
765
+ - $ref: '#/components/parameters/PrincipalHeader'
766
+ - in: path
767
+ name: sessionId
768
+ required: true
769
+ schema: { type: string }
770
+ get:
771
+ tags: [sessions]
772
+ operationId: sessionsEvents
773
+ x-status: live # [1196] session-level SSE head subscription.
774
+ summary: 'Session-level SSE: `event: head` pushes (latest-wins) when the leaf pointer moves.'
775
+ description: >
776
+ [1196] — the true-subscription face over the same predicate as `/head`: an SSE stream that pushes
777
+ `event: head` frames (data = the `/head` 200 body) whenever the session's leaf pointer changes,
778
+ latest-wins (intermediate leaves may be skipped). `?lastLeafId=` is the cursor — semantically the
779
+ ETag: when it matches the current leaf there is no initial frame; otherwise the current head is
780
+ replayed immediately on subscribe. 25s comment-line heartbeats. Auth and store gates are exactly
781
+ `/head`'s (owner-scoped 404; 501 without a durable session store). Connection cap exceeded →
782
+ 503 + Retry-After — fall back to polling `/head` (advertised via `capabilities.sessionEvents`).
783
+ parameters:
784
+ - in: query
785
+ name: lastLeafId
786
+ required: false
787
+ schema: { type: string }
788
+ description: 'Cursor: the last seen leafId. Matching the current leaf suppresses the initial replay frame.'
789
+ responses:
790
+ '200':
791
+ description: 'SSE stream (`text/event-stream`) of `event: head` frames.'
792
+ content:
793
+ text/event-stream:
794
+ schema: { type: string }
795
+ '401': { $ref: '#/components/responses/Unauthorized' }
796
+ '404': { $ref: '#/components/responses/NotFound' }
797
+ '501': { $ref: '#/components/responses/NotImplemented' }
798
+ '503': { description: 'Subscription connection cap exceeded — Retry-After set; fall back to polling /head.' }
799
+
800
+ /v1/sessions/{sessionId}/init:
801
+ parameters:
802
+ - $ref: '#/components/parameters/PrincipalHeader'
803
+ - in: path
804
+ name: sessionId
805
+ required: true
806
+ schema: { type: string }
807
+ get:
808
+ tags: [sessions]
809
+ operationId: sessionsInit
810
+ x-status: live # E11 shell-host startup bundle.
811
+ summary: One-call startup bundle for the shell banner (model + mode).
812
+ description: >
813
+ E11 (shell-host) — the one-call startup bundle so a shell renders its banner from ONE request instead
814
+ of fanning out to /v1/models + /v1/policy + /v1/capabilities. Worker-global config surface (same
815
+ posture as /v1/policy): principal OPTIONAL, enforced only under REQUIRE_PRINCIPAL. ADDITIVE contract —
816
+ `model` and `mode` are the load-bearing fields today; `tools`/`agents`/`commands`/`cwd` are omitted
817
+ (tolerate-absent; `cwd` is live-only E13 and never durable here).
818
+ responses:
819
+ '200':
820
+ description: The startup bundle.
821
+ content:
822
+ application/json:
823
+ schema:
824
+ type: object
825
+ required: [sessionId, model]
826
+ properties:
827
+ sessionId: { type: string }
828
+ model:
829
+ type: object
830
+ required: [provider, modelId]
831
+ properties:
832
+ provider: { type: string }
833
+ modelId: { type: string }
834
+ mode: { type: string, description: "Worker autonomy mode; absent when unconfigured." }
835
+ '401': { $ref: '#/components/responses/Unauthorized' }
836
+
837
+ /v1/sessions/{sessionId}/settings:
838
+ parameters:
839
+ - $ref: '#/components/parameters/PrincipalHeader'
840
+ - in: path
841
+ name: sessionId
842
+ required: true
843
+ schema: { type: string }
844
+ get:
845
+ tags: [sessions]
846
+ operationId: sessionsSettings
847
+ x-status: live # E24 read side (CC /config read). Write half needs a core seam — not advertised.
848
+ summary: Effective merged settings view (read-only).
849
+ description: >
850
+ E24 (shell-host) — the effective merged settings the run obeys (CC /config read side). Worker-global
851
+ config surface (principal optional unless REQUIRE_PRINCIPAL, same posture as /v1/policy and the E11
852
+ init bundle). The PATCH half (runtime settings write) needs a core seam and is deliberately absent —
853
+ no settings-write capability is advertised (honest read-only route).
854
+ responses:
855
+ '200':
856
+ description: The effective view.
857
+ content:
858
+ application/json:
859
+ schema:
860
+ type: object
861
+ required: [effective, applied]
862
+ properties:
863
+ effective:
864
+ type: object
865
+ description: 'Resolved worker config: model, mode?, approvalRequire, commandPolicy, limits {maxTaskCostUsd, maxTaskTokens}.'
866
+ applied:
867
+ type: object
868
+ description: 'Echo of the resolved model ({ model }).'
869
+ '401': { $ref: '#/components/responses/Unauthorized' }
870
+
871
+ /v1/sessions/{sessionId}/notify:
872
+ parameters:
873
+ - $ref: '#/components/parameters/PrincipalHeader'
874
+ - in: path
875
+ name: sessionId
876
+ required: true
877
+ schema: { type: string }
878
+ post:
879
+ tags: [sessions]
880
+ operationId: sessionsNotify
881
+ x-status: live # External task_notification injection (frame family = [446] bg_notification).
882
+ summary: Inject an EXTERNAL task_notification into a session (live nudge or inbox park).
883
+ description: >
884
+ Inject an external completion/event notice into a session as a `task_notification` frame
885
+ (task_type="external" is minted by core — an external caller can never impersonate an internal frame;
886
+ sanitize/fencing/three-state delivery are core-side). Live half: the session's active stream on THIS
887
+ replica gets a core notify verb → `delivery: "live"` (200). Idle half: parked into the session inbox
888
+ (external key domain) and drained as a `task_notification` on the next stream open → `delivery:
889
+ "parked"` (202). Owner-scoped fail-closed (unknown or foreign session → 404, no oracle); core contract
890
+ rejections (`notify.*`) surface as 400 with `errorCode`, never silently parked. 501 without the
891
+ session-ownership face or (park path) the workflow completion inbox.
892
+ requestBody:
893
+ required: true
894
+ content:
895
+ application/json:
896
+ schema:
897
+ type: object
898
+ required: [task_id, status, summary]
899
+ properties:
900
+ task_id: { type: string, maxLength: 190 }
901
+ status: { type: string, enum: [completed, failed, killed, cancelled, event] }
902
+ summary: { type: string }
903
+ result: { type: string }
904
+ seq: { type: integer, minimum: 1 }
905
+ source: { type: string, maxLength: 190 }
906
+ responses:
907
+ '200':
908
+ description: Delivered onto the live stream.
909
+ content:
910
+ application/json:
911
+ schema:
912
+ type: object
913
+ required: [sessionId, delivery]
914
+ properties:
915
+ sessionId: { type: string }
916
+ delivery: { type: string, enum: [live] }
917
+ '202':
918
+ description: No live stream — parked in the session inbox, drained on the next stream open.
919
+ content:
920
+ application/json:
921
+ schema:
922
+ type: object
923
+ required: [sessionId, delivery]
924
+ properties:
925
+ sessionId: { type: string }
926
+ delivery: { type: string, enum: [parked] }
927
+ note: { type: string }
928
+ '400': { $ref: '#/components/responses/BadRequest' }
929
+ '401': { $ref: '#/components/responses/Unauthorized' }
930
+ '404': { $ref: '#/components/responses/NotFound' }
931
+ '501': { $ref: '#/components/responses/NotImplemented' }
932
+
933
+ /v1/sessions/{sessionId}/wake:
934
+ parameters:
935
+ - $ref: '#/components/parameters/PrincipalHeader'
936
+ - in: path
937
+ name: sessionId
938
+ required: true
939
+ schema: { type: string }
940
+ post:
941
+ tags: [sessions]
942
+ operationId: sessionsWake
943
+ x-status: live # design/144 §3 wake arm.
944
+ summary: Wake a task_done-parked session (message delivery, NOT a gate decision).
945
+ description: >
946
+ design/144 §3 — deliver a message (or an already-parked pendingSteer) to a session parked on a
947
+ `task_done` checkpoint and resume it as the next turn's input. This is NOT a gate decision: it never
948
+ allows/denies a pending action — a pending gate ⇒ 409 `wake.gate_pending` (resolve through that gate's
949
+ own decide entry; approvals are never bypassed). Empty park + no message ⇒ nothing to deliver.
950
+ Owner-scoped; operator principals may carry trusted (`<system-reminder>`-bearing) messages. Resume
951
+ burns model budget — rate/quota/lease gates apply. 501 without the checkpoint store.
952
+ requestBody:
953
+ required: false
954
+ content:
955
+ application/json:
956
+ schema:
957
+ type: object
958
+ properties:
959
+ message: { type: string, minLength: 1 }
960
+ responses:
961
+ '202':
962
+ description: Resumed — the woken leg is driving into the durable run log.
963
+ content:
964
+ application/json:
965
+ schema:
966
+ type: object
967
+ required: [taskId, sessionId, status]
968
+ properties:
969
+ taskId: { type: string }
970
+ sessionId: { type: string }
971
+ status: { type: string }
972
+ '400': { $ref: '#/components/responses/BadRequest' }
973
+ '401': { $ref: '#/components/responses/Unauthorized' }
974
+ '404': { description: 'No parked checkpoint for this session (nothing to wake), or session not visible to the caller.' }
975
+ '409': { description: 'Pending gate (`wake.gate_pending` — decide it through its own entry) or resume context missing.' }
976
+ '422': { description: '`steering.invalid_content` — the message failed the steering content gate.' }
977
+ '501': { $ref: '#/components/responses/NotImplemented' }
978
+
722
979
  /v1/sessions/{sessionId}/policy:
723
980
  parameters:
724
981
  - $ref: '#/components/parameters/PrincipalHeader'
@@ -2569,13 +2826,16 @@ components:
2569
2826
  the user wants only files reverted. Target = a user-message SessionTreeEntry.id.
2570
2827
  permissionMode:
2571
2828
  type: string
2572
- enum: [default, plan, acceptEdits, bypassPermissions]
2829
+ enum: [default, plan, acceptEdits, bypassPermissions, auto]
2573
2830
  description: >
2574
- CC permission-mode INTENT. The frontend (TUI shell / web portal) carries the RAW mode; the SERVICE
2575
- INTERPRETS it (axis-aware, tighten-only): `plan` ⇒ mount present_plan (core enablePlanMode) + read-only
2576
- hands (handsReadOnly) = CC EnterPlanMode read-only research; `acceptEdits`/`bypassPermissions` are
2577
- loosening, not honorable remotely (coerced to default engine-side, enforced client-side). Carrying the
2578
- intent (not pre-interpreted core fields) = one interpretation across frontends + service-owned governance.
2831
+ CC permission-mode INTENT (the five CC modes verbatim, post-[816]/[820]/[822]). The frontend (TUI shell /
2832
+ web portal) carries the RAW mode; the SERVICE interprets it TIGHTEN-ONLY vs the deployment baseline:
2833
+ `plan` ⇒ mount present_plan (core enablePlanMode) + read-only hands (CC EnterPlanMode research);
2834
+ `default` adds the manual ask gate; `auto` = same ask gate with core's auto-mode classifier screening
2835
+ asks upstream (entitlement-gated in core); `acceptEdits`/`bypassPermissions` are honored as
2836
+ "add less/no mode-derived gating" — they can never subtract from the deployment/operator policy
2837
+ (deny-wins). An unknown string coerces to `default` (the most-asking mode). Carrying the intent
2838
+ (not pre-interpreted core fields) = one interpretation across frontends + service-owned governance.
2579
2839
  attachmentIds:
2580
2840
  type: array
2581
2841
  maxItems: 16
@@ -3186,7 +3446,7 @@ components:
3186
3446
  sessionDelete: { type: boolean, description: "Session delete verb." }
3187
3447
  sessionInit: { type: boolean, description: "Session pre-initialization verb." }
3188
3448
  sessionPolicy: { type: boolean, description: "E6 per-session operator-tightened tool rules are durable." }
3189
- usage: { type: boolean, description: "Usage analytics face." }
3449
+ usage: { type: boolean, description: "QUOTA face wired (server costQuota dep — cost/token budget enforcement + per-principal accounting). NOT an analytics-availability probe ([1871] B15): per-turn analytics (turn_end.usage, model_usage frames) are engine-side and unconditional, and GET /v1/usage always answers 200 (with `enabled: false` when the quota face is off). Gate quota UI on this key; never gate analytics on it." }
3190
3450
  policy: { type: boolean, description: "`GET /v1/policy` (autonomy/permission READ side)." }
3191
3451
  permissionModeWrite: { type: boolean, description: "Runtime permission-mode WRITE. Advertised false by design — autonomy is CONFIG, not steer; the READ side is `policy`." }
3192
3452
  modelSelection: { type: boolean, description: "`model` accepted per request." }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/sdk",
3
- "version": "0.0.119",
3
+ "version": "0.0.121",
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",