@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/dist/index.js CHANGED
@@ -319,6 +319,7 @@ var SESSION_EVENT_TYPES = [
319
319
  "agent.reasoning.delta",
320
320
  "agent.toolCall.created",
321
321
  "agent.toolCall.output",
322
+ "agent.model.request",
322
323
  "agent.model.usage",
323
324
  "tool.auth_needed",
324
325
  "credential.auth_needed",
@@ -370,6 +371,7 @@ var SESSION_EVENT_TYPES = [
370
371
  "terminal.pty.output.delta",
371
372
  "terminal.pty.exited",
372
373
  "session.title_set",
374
+ "session.mcp.approval_policy.updated",
373
375
  // Multi-account Codex (P1): the session's inference account changed.
374
376
  "codex.account.switched",
375
377
  // credential allocator metadata-only per-turn credential selection audit.
@@ -449,6 +451,8 @@ var KNOWN_PERMISSIONS = [
449
451
  ];
450
452
  var OPENGENI_API_CONTRACT_REVISION = "2026-07-turn-instructions-v1";
451
453
  var OPENGENI_API_CONTRACT_HEADER = "x-opengeni-api-contract";
454
+ var RETAINED_OUTPUT_DEFAULT_PAGE_BYTES = 256 * 1024;
455
+ var RETAINED_OUTPUT_MAX_PAGE_BYTES = 1024 * 1024;
452
456
  var KNOWN_USAGE_EVENT_TYPES = [
453
457
  "agent_run.created",
454
458
  "agent_run.completed",
@@ -495,6 +499,18 @@ var OpenGeniClient = class {
495
499
  request
496
500
  );
497
501
  }
502
+ /**
503
+ * Replace one attached MCP server's approval policy. The change is captured
504
+ * by the next claimed attempt; already-claimed work keeps its immutable
505
+ * policy snapshot.
506
+ */
507
+ async updateSessionMcpApprovalPolicy(workspaceId, sessionId, serverId, request) {
508
+ return await this.requestJson(
509
+ "PATCH",
510
+ `/v1/workspaces/${workspaceId}/sessions/${sessionId}/mcp-servers/${encodeURIComponent(serverId)}/approval-policy`,
511
+ request
512
+ );
513
+ }
498
514
  async listSessions(workspaceId, options = {}) {
499
515
  return await this.requestJson(
500
516
  "GET",
@@ -673,26 +689,30 @@ var OpenGeniClient = class {
673
689
  async listEvents(workspaceId, sessionId, options = {}) {
674
690
  return (await this.listEventPage(workspaceId, sessionId, options)).events;
675
691
  }
676
- /** Bounded durable/monitoring page plus exact projection and cursor facts. */
677
692
  async listEventPage(workspaceId, sessionId, options = {}) {
678
693
  if (options.latest && ["includeTypes", "excludeTypes", "includeClasses", "excludeClasses"].some(
679
694
  (name) => Object.prototype.hasOwnProperty.call(options, name)
680
695
  )) {
681
696
  throw new TypeError("latest cannot be combined with event filters");
682
697
  }
698
+ if (options.resultMode === "compact" && !options.latest) {
699
+ throw new TypeError("resultMode=compact requires latest");
700
+ }
701
+ const listOptions = options.resultMode === "compact" ? null : options;
683
702
  const response = await this.fetchImpl(
684
703
  this.url(`/v1/workspaces/${workspaceId}/sessions/${sessionId}/events`, {
685
- ...options.after !== void 0 ? { after: String(options.after) } : {},
686
- ...options.before !== void 0 ? { before: String(options.before) } : {},
687
- ...options.limit !== void 0 ? { limit: String(options.limit) } : {},
688
- ...options.compact ? { compact: "1" } : {},
704
+ ...listOptions?.after !== void 0 ? { after: String(listOptions.after) } : {},
705
+ ...listOptions?.before !== void 0 ? { before: String(listOptions.before) } : {},
706
+ ...listOptions?.limit !== void 0 ? { limit: String(listOptions.limit) } : {},
707
+ ...listOptions?.compact ? { compact: "1" } : {},
689
708
  ...options.mode ? { mode: options.mode } : {},
690
- ...options.direction ? { direction: options.direction } : {},
709
+ ...listOptions?.direction ? { direction: listOptions.direction } : {},
691
710
  ...options.payloadMode ? { payloadMode: options.payloadMode } : {},
692
- ...options.includeTypes?.length ? { includeTypes: options.includeTypes.join(",") } : {},
693
- ...options.excludeTypes?.length ? { excludeTypes: options.excludeTypes.join(",") } : {},
694
- ...options.includeClasses?.length ? { includeClasses: options.includeClasses.join(",") } : {},
695
- ...options.excludeClasses?.length ? { excludeClasses: options.excludeClasses.join(",") } : {},
711
+ ...options.resultMode ? { resultMode: options.resultMode } : {},
712
+ ...listOptions?.includeTypes?.length ? { includeTypes: listOptions.includeTypes.join(",") } : {},
713
+ ...listOptions?.excludeTypes?.length ? { excludeTypes: listOptions.excludeTypes.join(",") } : {},
714
+ ...listOptions?.includeClasses?.length ? { includeClasses: listOptions.includeClasses.join(",") } : {},
715
+ ...listOptions?.excludeClasses?.length ? { excludeClasses: listOptions.excludeClasses.join(",") } : {},
696
716
  ...options.latest ? { latest: options.latest } : {}
697
717
  }),
698
718
  {
@@ -702,7 +722,11 @@ var OpenGeniClient = class {
702
722
  );
703
723
  assertApiContractResponse(response);
704
724
  if (!response.ok) throw new OpenGeniApiError(response.status, await safeText(response));
705
- const events = await response.json();
725
+ const body = await response.json();
726
+ if (options.resultMode === "compact") {
727
+ return body;
728
+ }
729
+ const events = body;
706
730
  const integerHeader = (name) => {
707
731
  const raw = response.headers.get(name);
708
732
  if (raw === null) return null;
@@ -735,6 +759,18 @@ var OpenGeniClient = class {
735
759
  forensicExact: response.headers.get("X-OpenGeni-Forensic-Exact") === "true"
736
760
  };
737
761
  }
762
+ /**
763
+ * Fetch the authoritative newest-sequence semantic result directly. This is
764
+ * the callback-loss recovery path: it reads one compact durable result and
765
+ * never creates a model turn. `latest: "receipt"` aliases `tool_receipt`;
766
+ * turn generation remains scoped retry metadata.
767
+ */
768
+ async getLatestEventResult(workspaceId, sessionId, options = { latest: "terminal" }) {
769
+ return await this.listEventPage(workspaceId, sessionId, {
770
+ ...options,
771
+ resultMode: "compact"
772
+ });
773
+ }
738
774
  /** POST a user/control event to the session. Returns the accepted event. */
739
775
  async sendEvent(workspaceId, sessionId, event) {
740
776
  return await this.requestJson(
@@ -1261,6 +1297,13 @@ var OpenGeniClient = class {
1261
1297
  }
1262
1298
  return config;
1263
1299
  }
1300
+ /** Authenticated model definitions plus workspace-specific selectability. */
1301
+ async getWorkspaceModelCatalog(workspaceId) {
1302
+ return await this.requestJson(
1303
+ "GET",
1304
+ `/v1/workspaces/${workspaceId}/model-catalog`
1305
+ );
1306
+ }
1264
1307
  /** The caller's access context: subject, account + workspace grants, defaults. */
1265
1308
  async getAccessContext() {
1266
1309
  return await this.requestJson("GET", "/v1/access/me");
@@ -1591,6 +1634,71 @@ var OpenGeniClient = class {
1591
1634
  `/v1/workspaces/${workspaceId}/files/${fileId}`
1592
1635
  );
1593
1636
  }
1637
+ /** Read provider-neutral retained evidence metadata; never returns a storage location. */
1638
+ async getRetainedArtifact(workspaceId, artifactId) {
1639
+ return await this.requestJson(
1640
+ "GET",
1641
+ `/v1/workspaces/${workspaceId}/artifacts/${artifactId}`
1642
+ );
1643
+ }
1644
+ /**
1645
+ * Read at most one authenticated retained-evidence range from the API. This
1646
+ * deliberately does not use the ordinary signed file-download URL.
1647
+ */
1648
+ async getRetainedArtifactContent(workspaceId, artifactId, options = {}) {
1649
+ if (options.range && (options.range.length > 128 || /[^\x20-\x7e]/.test(options.range))) {
1650
+ throw new RangeError("retained artifact range must be at most 128 printable ASCII bytes");
1651
+ }
1652
+ const response = await this.fetchImpl(
1653
+ this.url(`/v1/workspaces/${workspaceId}/artifacts/${artifactId}/content`),
1654
+ {
1655
+ method: "GET",
1656
+ headers: {
1657
+ ...this.headers(),
1658
+ Accept: "application/octet-stream",
1659
+ ...options.range ? { Range: options.range } : {}
1660
+ },
1661
+ ...options.signal ? { signal: options.signal } : {}
1662
+ }
1663
+ );
1664
+ try {
1665
+ assertApiContractResponse(response);
1666
+ } catch (error) {
1667
+ await cancelResponseBody(response, "retained artifact API contract mismatch");
1668
+ throw error;
1669
+ }
1670
+ if (!response.ok) {
1671
+ throw new OpenGeniApiError(response.status, await safeBoundedText(response));
1672
+ }
1673
+ if (response.status !== 200 && response.status !== 206) {
1674
+ await cancelResponseBody(response, "unexpected retained artifact response status");
1675
+ throw new OpenGeniApiError(response.status, "unexpected retained artifact response status");
1676
+ }
1677
+ if (response.headers.get("accept-ranges") !== "bytes") {
1678
+ await cancelResponseBody(response, "retained artifact response omitted byte-range support");
1679
+ throw new OpenGeniApiError(502, "retained artifact response omitted byte-range support");
1680
+ }
1681
+ let declaredLength;
1682
+ try {
1683
+ declaredLength = parseBoundedContentLength(response.headers.get("content-length"));
1684
+ } catch (error) {
1685
+ await cancelResponseBody(response, "invalid retained artifact content-length");
1686
+ throw error;
1687
+ }
1688
+ const bytes = await readBoundedResponseBytes(
1689
+ response,
1690
+ RETAINED_OUTPUT_MAX_PAGE_BYTES,
1691
+ declaredLength
1692
+ );
1693
+ return {
1694
+ bytes,
1695
+ status: response.status,
1696
+ contentType: response.headers.get("content-type") ?? "application/octet-stream",
1697
+ contentLength: bytes.byteLength,
1698
+ contentRange: response.headers.get("content-range"),
1699
+ acceptRanges: "bytes"
1700
+ };
1701
+ }
1594
1702
  /** Mint a short-lived signed download URL for a ready file. */
1595
1703
  async createFileDownloadUrl(workspaceId, fileId) {
1596
1704
  return await this.requestJson(
@@ -1984,6 +2092,13 @@ var OpenGeniClient = class {
1984
2092
  `/v1/workspaces/${workspaceId}/codex/usage/refresh`
1985
2093
  );
1986
2094
  }
2095
+ /** Live independently-settled quota + reset-credit overview for every account. */
2096
+ async codexOverview(workspaceId) {
2097
+ return await this.requestJson(
2098
+ "GET",
2099
+ `/v1/workspaces/${workspaceId}/codex/overview`
2100
+ );
2101
+ }
1987
2102
  /** Disconnect ALL accounts (legacy workspace-wide). Prefer `disconnectCodexAccount`. */
1988
2103
  async codexDisconnect(workspaceId) {
1989
2104
  return await this.requestJson(
@@ -2013,6 +2128,14 @@ var OpenGeniClient = class {
2013
2128
  patch
2014
2129
  );
2015
2130
  }
2131
+ /** Toggle only NEW automatic allocations under independent allocator OCC. */
2132
+ async setCodexAccountAllocator(workspaceId, accountId, input) {
2133
+ return await this.requestJson(
2134
+ "PATCH",
2135
+ `/v1/workspaces/${workspaceId}/codex/accounts/${accountId}/allocator`,
2136
+ input
2137
+ );
2138
+ }
2016
2139
  /** Disconnect ONE Codex account by id (re-picks active when the removed one was active). */
2017
2140
  async disconnectCodexAccount(workspaceId, accountId) {
2018
2141
  return await this.requestJson(
@@ -2083,6 +2206,62 @@ async function safeText(response) {
2083
2206
  return "";
2084
2207
  }
2085
2208
  }
2209
+ async function safeBoundedText(response) {
2210
+ try {
2211
+ return new TextDecoder().decode(await readBoundedResponseBytes(response, 64 * 1024, null));
2212
+ } catch {
2213
+ return "";
2214
+ }
2215
+ }
2216
+ async function cancelResponseBody(response, reason) {
2217
+ await response.body?.cancel(reason).catch(() => void 0);
2218
+ }
2219
+ function parseBoundedContentLength(value) {
2220
+ if (value === null) return null;
2221
+ if (!/^\d+$/.test(value)) {
2222
+ throw new OpenGeniApiError(502, "invalid retained artifact content-length");
2223
+ }
2224
+ const length = Number(value);
2225
+ if (!Number.isSafeInteger(length) || length > RETAINED_OUTPUT_MAX_PAGE_BYTES) {
2226
+ throw new OpenGeniApiError(502, "retained artifact response exceeds the SDK byte limit");
2227
+ }
2228
+ return length;
2229
+ }
2230
+ async function readBoundedResponseBytes(response, maxBytes, expectedBytes) {
2231
+ if (!response.body) {
2232
+ if (expectedBytes !== null && expectedBytes !== 0) {
2233
+ throw new OpenGeniApiError(502, "retained artifact response length mismatch");
2234
+ }
2235
+ return new Uint8Array();
2236
+ }
2237
+ const reader = response.body.getReader();
2238
+ const chunks = [];
2239
+ let totalBytes = 0;
2240
+ try {
2241
+ while (true) {
2242
+ const { done, value } = await reader.read();
2243
+ if (done) break;
2244
+ totalBytes += value.byteLength;
2245
+ if (totalBytes > maxBytes) {
2246
+ await reader.cancel("retained artifact response exceeded the SDK byte limit").catch(() => void 0);
2247
+ throw new OpenGeniApiError(502, "retained artifact response exceeds the SDK byte limit");
2248
+ }
2249
+ chunks.push(value);
2250
+ }
2251
+ } finally {
2252
+ reader.releaseLock();
2253
+ }
2254
+ if (expectedBytes !== null && totalBytes !== expectedBytes) {
2255
+ throw new OpenGeniApiError(502, "retained artifact response length mismatch");
2256
+ }
2257
+ const bytes = new Uint8Array(totalBytes);
2258
+ let offset = 0;
2259
+ for (const chunk of chunks) {
2260
+ bytes.set(chunk, offset);
2261
+ offset += chunk.byteLength;
2262
+ }
2263
+ return bytes;
2264
+ }
2086
2265
 
2087
2266
  // src/proxy.ts
2088
2267
  function formatSseEvent(event) {
@@ -2489,6 +2668,8 @@ export {
2489
2668
  OpenGeniApiError,
2490
2669
  OpenGeniClient,
2491
2670
  OpenGeniStreamError,
2671
+ RETAINED_OUTPUT_DEFAULT_PAGE_BYTES,
2672
+ RETAINED_OUTPUT_MAX_PAGE_BYTES,
2492
2673
  SESSION_EVENT_TYPES,
2493
2674
  TTYD_SUBPROTOCOL,
2494
2675
  TtydClientCommand,