@opengeni/sdk 0.20.0 → 0.23.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/sdk",
3
- "version": "0.20.0",
3
+ "version": "0.23.0",
4
4
  "description": "Framework-agnostic TypeScript SDK for the OpenGeni API: typed client, session lifecycle, SSE event streaming with reconnect + replay-by-sequence, and proxy re-streaming helpers.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
package/src/client.ts CHANGED
@@ -16,6 +16,8 @@ import type {
16
16
  CodexAccount,
17
17
  CodexAccountsResponse,
18
18
  CodexRotationSettings,
19
+ CodexOverviewResponse,
20
+ CodexAllocatorUpdate,
19
21
  CodexConnectionStatus,
20
22
  CodexConnectPoll,
21
23
  CodexConnectStart,
@@ -28,6 +30,7 @@ import type {
28
30
  CapabilityInstallation,
29
31
  AddDocumentRequest,
30
32
  ClientConfig,
33
+ WorkspaceModelCatalogResponse,
31
34
  ClientSessionEventInput,
32
35
  CompactSessionContextResult,
33
36
  CompleteFileUploadResponse,
@@ -82,6 +85,9 @@ import type {
82
85
  ListWorkspaceMembersResponse,
83
86
  PackInstallation,
84
87
  ReasoningEffort,
88
+ RetainedArtifactContent,
89
+ RetainedArtifactContentOptions,
90
+ RetainedArtifactMetadata,
85
91
  RegisterCapabilityPackRequest,
86
92
  ResourceRef,
87
93
  ScheduledTask,
@@ -90,12 +96,16 @@ import type {
90
96
  SessionListResponse,
91
97
  UpdateSessionPinRequest,
92
98
  SessionEvent,
99
+ SessionEventCompactResult,
100
+ SessionEventCompactResultOptions,
93
101
  SessionEventListOptions,
94
102
  SessionEventPage,
95
103
  SessionGoal,
96
104
  SessionHumanInputRequest,
97
105
  SessionLineageResponse,
98
106
  SessionMcpCredentialUpdateInput,
107
+ UpdateSessionMcpApprovalPolicyRequest,
108
+ UpdateSessionMcpApprovalPolicyResponse,
99
109
  SessionQueueSnapshot,
100
110
  SessionQueueMutationResponse,
101
111
  ComposerDraft,
@@ -177,7 +187,11 @@ import type {
177
187
  OAuthStartRequest,
178
188
  OAuthStartResponse,
179
189
  } from "./types";
180
- import { OPENGENI_API_CONTRACT_HEADER, OPENGENI_API_CONTRACT_REVISION } from "./types";
190
+ import {
191
+ OPENGENI_API_CONTRACT_HEADER,
192
+ OPENGENI_API_CONTRACT_REVISION,
193
+ RETAINED_OUTPUT_MAX_PAGE_BYTES,
194
+ } from "./types";
181
195
 
182
196
  export type FetchLike = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
183
197
 
@@ -274,6 +288,24 @@ export class OpenGeniClient {
274
288
  );
275
289
  }
276
290
 
291
+ /**
292
+ * Replace one attached MCP server's approval policy. The change is captured
293
+ * by the next claimed attempt; already-claimed work keeps its immutable
294
+ * policy snapshot.
295
+ */
296
+ async updateSessionMcpApprovalPolicy(
297
+ workspaceId: string,
298
+ sessionId: string,
299
+ serverId: string,
300
+ request: UpdateSessionMcpApprovalPolicyRequest,
301
+ ): Promise<UpdateSessionMcpApprovalPolicyResponse> {
302
+ return await this.requestJson<UpdateSessionMcpApprovalPolicyResponse>(
303
+ "PATCH",
304
+ `/v1/workspaces/${workspaceId}/sessions/${sessionId}/mcp-servers/${encodeURIComponent(serverId)}/approval-policy`,
305
+ request,
306
+ );
307
+ }
308
+
277
309
  async listSessions(
278
310
  workspaceId: string,
279
311
  options: {
@@ -533,8 +565,18 @@ export class OpenGeniClient {
533
565
  async listEventPage(
534
566
  workspaceId: string,
535
567
  sessionId: string,
536
- options: SessionEventListOptions = {},
537
- ): Promise<SessionEventPage> {
568
+ options: SessionEventCompactResultOptions,
569
+ ): Promise<SessionEventCompactResult | null>;
570
+ async listEventPage(
571
+ workspaceId: string,
572
+ sessionId: string,
573
+ options?: SessionEventListOptions,
574
+ ): Promise<SessionEventPage>;
575
+ async listEventPage(
576
+ workspaceId: string,
577
+ sessionId: string,
578
+ options: SessionEventListOptions | SessionEventCompactResultOptions = {},
579
+ ): Promise<SessionEventPage | SessionEventCompactResult | null> {
538
580
  if (
539
581
  options.latest &&
540
582
  ["includeTypes", "excludeTypes", "includeClasses", "excludeClasses"].some((name) =>
@@ -543,22 +585,32 @@ export class OpenGeniClient {
543
585
  ) {
544
586
  throw new TypeError("latest cannot be combined with event filters");
545
587
  }
588
+ if (options.resultMode === "compact" && !options.latest) {
589
+ throw new TypeError("resultMode=compact requires latest");
590
+ }
591
+ const listOptions: SessionEventListOptions | null =
592
+ options.resultMode === "compact" ? null : options;
546
593
  const response = await this.fetchImpl(
547
594
  this.url(`/v1/workspaces/${workspaceId}/sessions/${sessionId}/events`, {
548
- ...(options.after !== undefined ? { after: String(options.after) } : {}),
549
- ...(options.before !== undefined ? { before: String(options.before) } : {}),
550
- ...(options.limit !== undefined ? { limit: String(options.limit) } : {}),
551
- ...(options.compact ? { compact: "1" } : {}),
595
+ ...(listOptions?.after !== undefined ? { after: String(listOptions.after) } : {}),
596
+ ...(listOptions?.before !== undefined ? { before: String(listOptions.before) } : {}),
597
+ ...(listOptions?.limit !== undefined ? { limit: String(listOptions.limit) } : {}),
598
+ ...(listOptions?.compact ? { compact: "1" } : {}),
552
599
  ...(options.mode ? { mode: options.mode } : {}),
553
- ...(options.direction ? { direction: options.direction } : {}),
600
+ ...(listOptions?.direction ? { direction: listOptions.direction } : {}),
554
601
  ...(options.payloadMode ? { payloadMode: options.payloadMode } : {}),
555
- ...(options.includeTypes?.length ? { includeTypes: options.includeTypes.join(",") } : {}),
556
- ...(options.excludeTypes?.length ? { excludeTypes: options.excludeTypes.join(",") } : {}),
557
- ...(options.includeClasses?.length
558
- ? { includeClasses: options.includeClasses.join(",") }
602
+ ...(options.resultMode ? { resultMode: options.resultMode } : {}),
603
+ ...(listOptions?.includeTypes?.length
604
+ ? { includeTypes: listOptions.includeTypes.join(",") }
559
605
  : {}),
560
- ...(options.excludeClasses?.length
561
- ? { excludeClasses: options.excludeClasses.join(",") }
606
+ ...(listOptions?.excludeTypes?.length
607
+ ? { excludeTypes: listOptions.excludeTypes.join(",") }
608
+ : {}),
609
+ ...(listOptions?.includeClasses?.length
610
+ ? { includeClasses: listOptions.includeClasses.join(",") }
611
+ : {}),
612
+ ...(listOptions?.excludeClasses?.length
613
+ ? { excludeClasses: listOptions.excludeClasses.join(",") }
562
614
  : {}),
563
615
  ...(options.latest ? { latest: options.latest } : {}),
564
616
  }),
@@ -569,7 +621,11 @@ export class OpenGeniClient {
569
621
  );
570
622
  assertApiContractResponse(response);
571
623
  if (!response.ok) throw new OpenGeniApiError(response.status, await safeText(response));
572
- const events = (await response.json()) as SessionEvent[];
624
+ const body = await response.json();
625
+ if (options.resultMode === "compact") {
626
+ return body as SessionEventCompactResult;
627
+ }
628
+ const events = body as SessionEvent[];
573
629
  const integerHeader = (name: string): number | null => {
574
630
  const raw = response.headers.get(name);
575
631
  if (raw === null) return null;
@@ -613,6 +669,23 @@ export class OpenGeniClient {
613
669
  };
614
670
  }
615
671
 
672
+ /**
673
+ * Fetch the authoritative newest-sequence semantic result directly. This is
674
+ * the callback-loss recovery path: it reads one compact durable result and
675
+ * never creates a model turn. `latest: "receipt"` aliases `tool_receipt`;
676
+ * turn generation remains scoped retry metadata.
677
+ */
678
+ async getLatestEventResult(
679
+ workspaceId: string,
680
+ sessionId: string,
681
+ options: Omit<SessionEventCompactResultOptions, "resultMode"> = { latest: "terminal" },
682
+ ): Promise<SessionEventCompactResult | null> {
683
+ return await this.listEventPage(workspaceId, sessionId, {
684
+ ...options,
685
+ resultMode: "compact",
686
+ });
687
+ }
688
+
616
689
  /** POST a user/control event to the session. Returns the accepted event. */
617
690
  async sendEvent(
618
691
  workspaceId: string,
@@ -1418,6 +1491,14 @@ export class OpenGeniClient {
1418
1491
  return config;
1419
1492
  }
1420
1493
 
1494
+ /** Authenticated model definitions plus workspace-specific selectability. */
1495
+ async getWorkspaceModelCatalog(workspaceId: string): Promise<WorkspaceModelCatalogResponse> {
1496
+ return await this.requestJson<WorkspaceModelCatalogResponse>(
1497
+ "GET",
1498
+ `/v1/workspaces/${workspaceId}/model-catalog`,
1499
+ );
1500
+ }
1501
+
1421
1502
  /** The caller's access context: subject, account + workspace grants, defaults. */
1422
1503
  async getAccessContext(): Promise<AccessContext> {
1423
1504
  return await this.requestJson<AccessContext>("GET", "/v1/access/me");
@@ -1878,6 +1959,80 @@ export class OpenGeniClient {
1878
1959
  );
1879
1960
  }
1880
1961
 
1962
+ /** Read provider-neutral retained evidence metadata; never returns a storage location. */
1963
+ async getRetainedArtifact(
1964
+ workspaceId: string,
1965
+ artifactId: string,
1966
+ ): Promise<RetainedArtifactMetadata> {
1967
+ return await this.requestJson<RetainedArtifactMetadata>(
1968
+ "GET",
1969
+ `/v1/workspaces/${workspaceId}/artifacts/${artifactId}`,
1970
+ );
1971
+ }
1972
+
1973
+ /**
1974
+ * Read at most one authenticated retained-evidence range from the API. This
1975
+ * deliberately does not use the ordinary signed file-download URL.
1976
+ */
1977
+ async getRetainedArtifactContent(
1978
+ workspaceId: string,
1979
+ artifactId: string,
1980
+ options: RetainedArtifactContentOptions = {},
1981
+ ): Promise<RetainedArtifactContent> {
1982
+ if (options.range && (options.range.length > 128 || /[^\x20-\x7e]/.test(options.range))) {
1983
+ throw new RangeError("retained artifact range must be at most 128 printable ASCII bytes");
1984
+ }
1985
+ const response = await this.fetchImpl(
1986
+ this.url(`/v1/workspaces/${workspaceId}/artifacts/${artifactId}/content`),
1987
+ {
1988
+ method: "GET",
1989
+ headers: {
1990
+ ...this.headers(),
1991
+ Accept: "application/octet-stream",
1992
+ ...(options.range ? { Range: options.range } : {}),
1993
+ },
1994
+ ...(options.signal ? { signal: options.signal } : {}),
1995
+ },
1996
+ );
1997
+ try {
1998
+ assertApiContractResponse(response);
1999
+ } catch (error) {
2000
+ await cancelResponseBody(response, "retained artifact API contract mismatch");
2001
+ throw error;
2002
+ }
2003
+ if (!response.ok) {
2004
+ throw new OpenGeniApiError(response.status, await safeBoundedText(response));
2005
+ }
2006
+ if (response.status !== 200 && response.status !== 206) {
2007
+ await cancelResponseBody(response, "unexpected retained artifact response status");
2008
+ throw new OpenGeniApiError(response.status, "unexpected retained artifact response status");
2009
+ }
2010
+ if (response.headers.get("accept-ranges") !== "bytes") {
2011
+ await cancelResponseBody(response, "retained artifact response omitted byte-range support");
2012
+ throw new OpenGeniApiError(502, "retained artifact response omitted byte-range support");
2013
+ }
2014
+ let declaredLength: number | null;
2015
+ try {
2016
+ declaredLength = parseBoundedContentLength(response.headers.get("content-length"));
2017
+ } catch (error) {
2018
+ await cancelResponseBody(response, "invalid retained artifact content-length");
2019
+ throw error;
2020
+ }
2021
+ const bytes = await readBoundedResponseBytes(
2022
+ response,
2023
+ RETAINED_OUTPUT_MAX_PAGE_BYTES,
2024
+ declaredLength,
2025
+ );
2026
+ return {
2027
+ bytes,
2028
+ status: response.status,
2029
+ contentType: response.headers.get("content-type") ?? "application/octet-stream",
2030
+ contentLength: bytes.byteLength,
2031
+ contentRange: response.headers.get("content-range"),
2032
+ acceptRanges: "bytes",
2033
+ };
2034
+ }
2035
+
1881
2036
  /** Mint a short-lived signed download URL for a ready file. */
1882
2037
  async createFileDownloadUrl(
1883
2038
  workspaceId: string,
@@ -2416,6 +2571,14 @@ export class OpenGeniClient {
2416
2571
  );
2417
2572
  }
2418
2573
 
2574
+ /** Live independently-settled quota + reset-credit overview for every account. */
2575
+ async codexOverview(workspaceId: string): Promise<CodexOverviewResponse> {
2576
+ return await this.requestJson<CodexOverviewResponse>(
2577
+ "GET",
2578
+ `/v1/workspaces/${workspaceId}/codex/overview`,
2579
+ );
2580
+ }
2581
+
2419
2582
  /** Disconnect ALL accounts (legacy workspace-wide). Prefer `disconnectCodexAccount`. */
2420
2583
  async codexDisconnect(workspaceId: string): Promise<{ disconnected: boolean }> {
2421
2584
  return await this.requestJson<{ disconnected: boolean }>(
@@ -2458,6 +2621,19 @@ export class OpenGeniClient {
2458
2621
  );
2459
2622
  }
2460
2623
 
2624
+ /** Toggle only NEW automatic allocations under independent allocator OCC. */
2625
+ async setCodexAccountAllocator(
2626
+ workspaceId: string,
2627
+ accountId: string,
2628
+ input: { enabled: boolean; expectedVersion: number },
2629
+ ): Promise<CodexAllocatorUpdate> {
2630
+ return await this.requestJson<CodexAllocatorUpdate>(
2631
+ "PATCH",
2632
+ `/v1/workspaces/${workspaceId}/codex/accounts/${accountId}/allocator`,
2633
+ input,
2634
+ );
2635
+ }
2636
+
2461
2637
  /** Disconnect ONE Codex account by id (re-picks active when the removed one was active). */
2462
2638
  async disconnectCodexAccount(
2463
2639
  workspaceId: string,
@@ -2551,3 +2727,69 @@ async function safeText(response: Response): Promise<string> {
2551
2727
  return "";
2552
2728
  }
2553
2729
  }
2730
+
2731
+ async function safeBoundedText(response: Response): Promise<string> {
2732
+ try {
2733
+ return new TextDecoder().decode(await readBoundedResponseBytes(response, 64 * 1024, null));
2734
+ } catch {
2735
+ return "";
2736
+ }
2737
+ }
2738
+
2739
+ async function cancelResponseBody(response: Response, reason: string): Promise<void> {
2740
+ await response.body?.cancel(reason).catch(() => undefined);
2741
+ }
2742
+
2743
+ function parseBoundedContentLength(value: string | null): number | null {
2744
+ if (value === null) return null;
2745
+ if (!/^\d+$/.test(value)) {
2746
+ throw new OpenGeniApiError(502, "invalid retained artifact content-length");
2747
+ }
2748
+ const length = Number(value);
2749
+ if (!Number.isSafeInteger(length) || length > RETAINED_OUTPUT_MAX_PAGE_BYTES) {
2750
+ throw new OpenGeniApiError(502, "retained artifact response exceeds the SDK byte limit");
2751
+ }
2752
+ return length;
2753
+ }
2754
+
2755
+ async function readBoundedResponseBytes(
2756
+ response: Response,
2757
+ maxBytes: number,
2758
+ expectedBytes: number | null,
2759
+ ): Promise<Uint8Array> {
2760
+ if (!response.body) {
2761
+ if (expectedBytes !== null && expectedBytes !== 0) {
2762
+ throw new OpenGeniApiError(502, "retained artifact response length mismatch");
2763
+ }
2764
+ return new Uint8Array();
2765
+ }
2766
+ const reader = response.body.getReader();
2767
+ const chunks: Uint8Array[] = [];
2768
+ let totalBytes = 0;
2769
+ try {
2770
+ while (true) {
2771
+ const { done, value } = await reader.read();
2772
+ if (done) break;
2773
+ totalBytes += value.byteLength;
2774
+ if (totalBytes > maxBytes) {
2775
+ await reader
2776
+ .cancel("retained artifact response exceeded the SDK byte limit")
2777
+ .catch(() => undefined);
2778
+ throw new OpenGeniApiError(502, "retained artifact response exceeds the SDK byte limit");
2779
+ }
2780
+ chunks.push(value);
2781
+ }
2782
+ } finally {
2783
+ reader.releaseLock();
2784
+ }
2785
+ if (expectedBytes !== null && totalBytes !== expectedBytes) {
2786
+ throw new OpenGeniApiError(502, "retained artifact response length mismatch");
2787
+ }
2788
+ const bytes = new Uint8Array(totalBytes);
2789
+ let offset = 0;
2790
+ for (const chunk of chunks) {
2791
+ bytes.set(chunk, offset);
2792
+ offset += chunk.byteLength;
2793
+ }
2794
+ return bytes;
2795
+ }
package/src/index.ts CHANGED
@@ -85,6 +85,8 @@ export {
85
85
  KNOWN_USAGE_EVENT_TYPES,
86
86
  OPENGENI_API_CONTRACT_HEADER,
87
87
  OPENGENI_API_CONTRACT_REVISION,
88
+ RETAINED_OUTPUT_DEFAULT_PAGE_BYTES,
89
+ RETAINED_OUTPUT_MAX_PAGE_BYTES,
88
90
  SESSION_EVENT_TYPES,
89
91
  } from "./types";
90
92
  export type {
@@ -121,12 +123,28 @@ export type {
121
123
  CapabilityUnavailableReason,
122
124
  ClientConfig,
123
125
  ClientModel,
126
+ ModelAvailabilityV1,
127
+ ModelBillingAttributionV1,
128
+ ModelCapabilitiesV1,
129
+ ModelCapabilityStateV1,
130
+ ModelCapabilitySupportV1,
131
+ ModelCredentialReadinessV1,
132
+ ModelCredentialSourceV1,
133
+ ModelPricingScheduleV1,
134
+ ModelPricingV1,
135
+ WorkspaceModelCatalogModel,
136
+ WorkspaceModelCatalogResponse,
124
137
  CodexAccount,
138
+ CodexAccountOverview,
125
139
  CodexAccountsResponse,
140
+ CodexAllocatorUpdate,
126
141
  CodexAccountSwitchedPayload,
127
142
  CodexConnectionStatus,
128
143
  CodexConnectStart,
129
144
  CodexConnectPoll,
145
+ CodexOverviewResponse,
146
+ CodexResetCredit,
147
+ CodexResetRedemptionRecovery,
130
148
  CodexRotationSettings,
131
149
  CodexUsage,
132
150
  CodexUsageMap,
@@ -212,6 +230,13 @@ export type {
212
230
  Permission,
213
231
  ProductAccessMode,
214
232
  ReasoningEffort,
233
+ RetainedArtifactContent,
234
+ RetainedArtifactContentOptions,
235
+ RetainedArtifactMetadata,
236
+ RetainedArtifactReference,
237
+ RetainedArtifactUnavailable,
238
+ RetainedOutputKind,
239
+ RetainedOutputUnavailableReason,
215
240
  RecordingAvailablePayload,
216
241
  RecordingCodec,
217
242
  RecordingContentType,
@@ -240,6 +265,7 @@ export type {
240
265
  SessionCapabilities,
241
266
  SessionListResponse,
242
267
  SessionLineageResponse,
268
+ SessionEffectiveToolPolicy,
243
269
  SessionQueueMutationResponse,
244
270
  SessionQueueSnapshot,
245
271
  SessionControlResponse,
@@ -260,8 +286,10 @@ export type {
260
286
  SessionSummary,
261
287
  LineageNode,
262
288
  SessionMcpCredentialUpdateInput,
289
+ SessionMcpApprovalPolicy,
263
290
  SessionMcpServerInput,
264
291
  SessionMcpServerMetadata,
292
+ SessionToolPolicy,
265
293
  // Per-surface capability cell aliases (views of SessionCapabilities).
266
294
  FileSystemCapability,
267
295
  TerminalCapability,
@@ -283,11 +311,15 @@ export type {
283
311
  ViewerHeartbeatRequest,
284
312
  ViewerHeartbeatResponse,
285
313
  SessionEvent,
314
+ SessionEventCompactResult,
315
+ SessionEventCompactResultOptions,
286
316
  SessionEventListOptions,
317
+ SessionEventLatestClass,
287
318
  SessionEventPage,
288
319
  SessionEventPayloadMode,
289
320
  SessionEventReadDirection,
290
321
  SessionEventReadMode,
322
+ SessionEventResultMode,
291
323
  SessionEventSemanticClass,
292
324
  SessionEventType,
293
325
  SessionGoal,
@@ -366,6 +398,8 @@ export type {
366
398
  UpdateKnowledgeMemoryRequest,
367
399
  UpdateScheduledTaskRequest,
368
400
  UpdateSessionGoalRequest,
401
+ UpdateSessionMcpApprovalPolicyRequest,
402
+ UpdateSessionMcpApprovalPolicyResponse,
369
403
  UpdateSessionPinRequest,
370
404
  UpdateSessionRequest,
371
405
  UpdateVariableSetRequest,