@opengeni/sdk 0.57.0 → 1.0.1

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/client.d.ts CHANGED
@@ -32,8 +32,8 @@ export type OpenGeniRequestOptions = {
32
32
  export type SendMessageInput = {
33
33
  text: string;
34
34
  annotations?: SubmittedTimelineAnnotation[];
35
- /** System instructions scoped to this exact turn; never visible timeline text. */
36
- turnInstructions?: string;
35
+ /** Model-visible application context attached to this exact user message; omitted by standard timeline rendering. */
36
+ modelContext?: string;
37
37
  resources?: ResourceRef[];
38
38
  tools?: ToolRef[];
39
39
  model?: string;
@@ -83,6 +83,8 @@ export type CreateCodexRealtimeControllerOptions = {
83
83
  model?: SessionRealtimeModel | undefined;
84
84
  ownerStorageNamespace?: string | undefined;
85
85
  startTransport?: RealtimeControllerTransportStarter | undefined;
86
+ /** Model-visible application context captured with each durable realtime message. */
87
+ getModelContext?: (() => string | undefined) | undefined;
86
88
  };
87
89
  export type RealtimeControllerTransportStarter = (input: {
88
90
  client: CodexRealtimeControllerClient;
@@ -5,7 +5,7 @@ import {
5
5
  projectSessionRealtimeLifecycle,
6
6
  sessionRealtimeOwnerStorageKey,
7
7
  sessionRealtimeOwnerStorageNamespace
8
- } from "./chunk-JDLDDRNE.js";
8
+ } from "./chunk-A5DC5WEM.js";
9
9
  import "./chunk-GU6JF75T.js";
10
10
  export {
11
11
  CODEX_REALTIME_NEGOTIATION_TIMEOUT_MS,
@@ -1,11 +1,11 @@
1
- import type { SyncSessionRealtimeLedgerRequest, SyncSessionRealtimeLedgerResponse } from "./types.js";
1
+ import type { SessionRealtimeInboundEntry, SyncSessionRealtimeLedgerRequest, SyncSessionRealtimeLedgerResponse } from "./types.js";
2
2
  export { CODEX_REALTIME_CONTEXT_APPEND_MAX_BYTES, CODEX_REALTIME_V3_MAX_EVENT_BYTES, CODEX_REALTIME_V3_MAX_IDENTIFIER_BYTES, CODEX_REALTIME_V3_MAX_TEXT_BYTES, contextAppendChunks, encodeCodexRealtimeV3DelegationContextAppend, encodeCodexRealtimeV3SessionContextAppend, parseCodexRealtimeV3Event, } from "./codex-realtime-v3-wire.js";
3
3
  export type { CodexRealtimeV3ContextAppendChannel, CodexRealtimeV3DelegationContextAppend, CodexRealtimeV3Event, CodexRealtimeV3ParseFailure, CodexRealtimeV3ParseResult, CodexRealtimeV3SessionContextAppend, } from "./codex-realtime-v3-wire.js";
4
4
  export declare const CODEX_REALTIME_V3_SYNC_MAX_ENTRIES = 64;
5
5
  export declare const CODEX_REALTIME_V3_PENDING_MAX_ENTRIES = 256;
6
6
  export declare const CODEX_REALTIME_V3_PENDING_MAX_BYTES: number;
7
7
  export type CodexRealtimeV3BridgeFatal = {
8
- code: "pending_overflow";
8
+ code: "pending_overflow" | "replay_journal_failed";
9
9
  message: string;
10
10
  };
11
11
  export type CodexRealtimeV3BridgeSnapshot = {
@@ -35,6 +35,17 @@ export type CodexRealtimeV3BridgeOptions = {
35
35
  owner: Pick<SyncSessionRealtimeLedgerRequest, "browserInstanceId" | "ownerKey" | "expectedVersion">;
36
36
  sync(request: SyncSessionRealtimeLedgerRequest): Promise<SyncSessionRealtimeLedgerResponse>;
37
37
  randomUUID?: (() => string) | undefined;
38
+ /** Model-visible application context captured once for each durable message-bearing entry. */
39
+ getModelContext?: (() => string | undefined) | undefined;
40
+ /** Controller-lifetime delegation identities shared across provider connection rotations. */
41
+ acceptedDelegationItemIds?: Set<string> | undefined;
42
+ /** Unsynced delegation snapshots retained exactly across provider connection rotations. */
43
+ pendingDelegations?: Map<string, SessionRealtimeInboundEntry> | undefined;
44
+ /** Persist exact delegation replay state before it becomes browser-reload-sensitive. */
45
+ onDelegationReplayStateChange?: ((state: {
46
+ acceptedDelegationItemIds: ReadonlySet<string>;
47
+ pendingDelegations: ReadonlyMap<string, SessionRealtimeInboundEntry>;
48
+ }) => void) | undefined;
38
49
  /** The controller installs its activation FIFO first, then enables this listener synchronously. */
39
50
  listen?: boolean | undefined;
40
51
  onSnapshot?: ((snapshot: CodexRealtimeV3BridgeSnapshot) => void) | undefined;
package/dist/core.js CHANGED
@@ -3,11 +3,11 @@ import {
3
3
  } from "./chunk-VYCTL62C.js";
4
4
  import {
5
5
  OpenGeniClient
6
- } from "./chunk-PKQ377ED.js";
6
+ } from "./chunk-YGH5P47G.js";
7
7
  import {
8
8
  OPENGENI_API_CONTRACT_HEADER,
9
9
  OPENGENI_API_CONTRACT_REVISION
10
- } from "./chunk-HJ3HHUT5.js";
10
+ } from "./chunk-4DV37UUA.js";
11
11
  import {
12
12
  OpenGeniApiContractMismatchError,
13
13
  OpenGeniApiError,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  OPENGENI_API_CONTRACT_HEADER,
3
3
  OPENGENI_API_CONTRACT_REVISION
4
- } from "./chunk-HJ3HHUT5.js";
4
+ } from "./chunk-4DV37UUA.js";
5
5
  import {
6
6
  DEFAULT_ARTIFACT_WORKER_RPC_LIMITS,
7
7
  decodeArtifactWorkerRpcMessage,
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  OpenGeniClient
3
- } from "./chunk-JRPFWI6T.js";
3
+ } from "./chunk-TYZ4JL4J.js";
4
4
  import {
5
5
  DEFAULT_WORKSPACE_TRANSCRIPTION_POLICY,
6
6
  authorizeTranscriptionAdapter,
@@ -21,7 +21,7 @@ import {
21
21
  streamWorkspaceControlEvents,
22
22
  streamWorkspaceInteractionRevisions,
23
23
  streamWorkspaceLiveEvents
24
- } from "./chunk-PKQ377ED.js";
24
+ } from "./chunk-YGH5P47G.js";
25
25
  import {
26
26
  DEFAULT_FILE_RESOURCE_MOUNT_ROOT,
27
27
  GENERATED_VIDEO_MAX_BYTES,
@@ -33,7 +33,7 @@ import {
33
33
  RETAINED_OUTPUT_DEFAULT_PAGE_BYTES,
34
34
  RETAINED_OUTPUT_MAX_PAGE_BYTES,
35
35
  SESSION_EVENT_TYPES
36
- } from "./chunk-HJ3HHUT5.js";
36
+ } from "./chunk-4DV37UUA.js";
37
37
  import {
38
38
  createGatewayRealtimeTransportStarter,
39
39
  createXaiSubscriptionRealtimeTransportStarter
@@ -51,7 +51,7 @@ import {
51
51
  parseCodexRealtimeV3Event,
52
52
  projectSessionRealtimeLifecycle,
53
53
  startCodexRealtimeWebrtc
54
- } from "./chunk-JDLDDRNE.js";
54
+ } from "./chunk-A5DC5WEM.js";
55
55
  import {
56
56
  OpenGeniApiContractMismatchError,
57
57
  OpenGeniApiError,
package/dist/realtime.js CHANGED
@@ -27,7 +27,7 @@ import {
27
27
  sessionRealtimeOwnerStorageKey,
28
28
  sessionRealtimeOwnerStorageNamespace,
29
29
  startCodexRealtimeWebrtc
30
- } from "./chunk-JDLDDRNE.js";
30
+ } from "./chunk-A5DC5WEM.js";
31
31
  import "./chunk-GU6JF75T.js";
32
32
 
33
33
  // src/realtime.ts
package/dist/types.d.ts CHANGED
@@ -90,6 +90,8 @@ export type SessionRealtimeInboundEntry = {
90
90
  delegationItemId?: string | null | undefined;
91
91
  text?: string | null | undefined;
92
92
  payload?: Record<string, unknown> | undefined;
93
+ /** Model-visible application context attached to this exact realtime message. */
94
+ modelContext?: string | undefined;
93
95
  };
94
96
  export type SyncSessionRealtimeLedgerRequest = {
95
97
  browserInstanceId: string;
@@ -556,16 +558,25 @@ export type GoogleDriveConnectionMetadata = {
556
558
  googleEmail: string;
557
559
  googleDisplayName: string | null;
558
560
  verifiedAt: string;
559
- accessMode: "metadata_readonly" | "readonly";
561
+ accessMode: "file_only" | "metadata_readonly" | "readonly";
560
562
  lifecycle?: GoogleDriveConnectionLifecycle | undefined;
563
+ outputDestination?: GoogleDriveOutputDestination | undefined;
561
564
  documentDestination?: ConnectorDocumentDestination | undefined;
562
565
  selectedSources?: GoogleDriveSelectedSource[] | undefined;
563
566
  /** @deprecated Read selectedSources; retained while existing connections migrate. */
564
567
  selectedSource?: GoogleDriveSelectedSource | null | undefined;
565
568
  [key: string]: unknown;
566
569
  };
570
+ export type GoogleDriveOutputDestination = {
571
+ folderId: string;
572
+ folderName: string;
573
+ driveId: string | null;
574
+ location: "my_drive" | "shared_drive";
575
+ selectedAt: string;
576
+ };
567
577
  export type GoogleDriveOAuthStartRequest = {
568
578
  connectionId?: string | undefined;
579
+ capability?: "source_read" | "publish" | undefined;
569
580
  };
570
581
  export type GoogleDriveOAuthStartResponse = {
571
582
  authorizationUrl: string;
@@ -1823,8 +1834,8 @@ export type CreateSessionRequest = {
1823
1834
  initialMessage?: string | undefined;
1824
1835
  /** Create an idle session shell so realtime voice can be the first interaction. */
1825
1836
  startMode?: "realtime" | undefined;
1826
- /** System instructions scoped to the initial turn; never visible timeline text. */
1827
- turnInstructions?: string | undefined;
1837
+ /** Model-visible application context attached to the initial user message; omitted by standard timeline rendering. */
1838
+ modelContext?: string | undefined;
1828
1839
  instructions?: string | undefined;
1829
1840
  /** Immutable normalized prompt-policy role; distinct from membership roles. */
1830
1841
  policyRole?: string | undefined;
@@ -2288,7 +2299,7 @@ export type ClientAuthConfig = {
2288
2299
  mode: "managedSession";
2289
2300
  session: "cookie";
2290
2301
  };
2291
- export declare const OPENGENI_API_CONTRACT_REVISION: "2026-08-social-provider-tools-v1";
2302
+ export declare const OPENGENI_API_CONTRACT_REVISION: "2026-08-model-context-v1";
2292
2303
  export declare const OPENGENI_API_CONTRACT_HEADER: "x-opengeni-api-contract";
2293
2304
  /** Bounded request/response identifier shared by browser, ingress, and API diagnostics. */
2294
2305
  export declare const OPENGENI_CORRELATION_HEADER: "x-opengeni-correlation-id";
@@ -4784,7 +4795,7 @@ export type UserMessageEventInput = {
4784
4795
  payload: {
4785
4796
  text: string;
4786
4797
  annotations?: SubmittedTimelineAnnotation[] | undefined;
4787
- turnInstructions?: string | undefined;
4798
+ modelContext?: string | undefined;
4788
4799
  resources?: ResourceRef[] | undefined;
4789
4800
  model?: string | undefined;
4790
4801
  reasoningEffort?: ReasoningEffort | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/sdk",
3
- "version": "0.57.0",
3
+ "version": "1.0.1",
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": {
@@ -73,7 +73,7 @@
73
73
  "prepublishOnly": "bash ../../scripts/prepublish-guard"
74
74
  },
75
75
  "dependencies": {
76
- "@opengeni/contracts": "^0.50.0"
76
+ "@opengeni/contracts": "^1.0.1"
77
77
  },
78
78
  "engines": {
79
79
  "node": ">=18"
package/src/client.ts CHANGED
@@ -493,8 +493,8 @@ export type OpenGeniRequestOptions = {
493
493
  export type SendMessageInput = {
494
494
  text: string;
495
495
  annotations?: SubmittedTimelineAnnotation[];
496
- /** System instructions scoped to this exact turn; never visible timeline text. */
497
- turnInstructions?: string;
496
+ /** Model-visible application context attached to this exact user message; omitted by standard timeline rendering. */
497
+ modelContext?: string;
498
498
  resources?: ResourceRef[];
499
499
  tools?: ToolRef[];
500
500
  model?: string;
@@ -33,6 +33,7 @@ import type {
33
33
  GatewayRealtimeConnectResponse,
34
34
  EndSessionRealtimeRequest,
35
35
  RenewSessionRealtimeRequest,
36
+ SessionRealtimeInboundEntry,
36
37
  SessionRealtimeMode,
37
38
  SessionRealtimeModel,
38
39
  SessionRealtimeMutationResponse,
@@ -50,6 +51,27 @@ export const CODEX_REALTIME_NEGOTIATION_TIMEOUT_MS = 20_000;
50
51
  const DEFAULT_CONNECTION_ROTATION_INTERVAL_MS = 15 * 60_000;
51
52
  const DEFAULT_RECONNECT_BACKOFF_MS = [250, 1_000, 2_000, 5_000] as const;
52
53
  const OWNER_RECORD_VERSION = 1;
54
+ const OWNER_DELEGATION_REPLAY_VERSION = 1;
55
+ const OWNER_DELEGATION_REPLAY_MAX_CALLS = 4_096;
56
+ const OWNER_DELEGATION_REPLAY_MAX_BYTES = 4 * 1024 * 1024;
57
+ const SESSION_REALTIME_INBOUND_ENTRY_KEYS = new Set([
58
+ "operationId",
59
+ "kind",
60
+ "role",
61
+ "providerEventId",
62
+ "delegationItemId",
63
+ "text",
64
+ "payload",
65
+ "modelContext",
66
+ ]);
67
+ const SESSION_REALTIME_INBOUND_KINDS = new Set([
68
+ "user_transcript",
69
+ "assistant_transcript",
70
+ "delegation_call",
71
+ "interruption",
72
+ "error",
73
+ ]);
74
+ const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
53
75
 
54
76
  export type CodexRealtimeControllerStatus =
55
77
  | "idle"
@@ -213,6 +235,8 @@ export type CreateCodexRealtimeControllerOptions = {
213
235
  model?: SessionRealtimeModel | undefined;
214
236
  ownerStorageNamespace?: string | undefined;
215
237
  startTransport?: RealtimeControllerTransportStarter | undefined;
238
+ /** Model-visible application context captured with each durable realtime message. */
239
+ getModelContext?: (() => string | undefined) | undefined;
216
240
  };
217
241
 
218
242
  export type RealtimeControllerTransportStarter = (input: {
@@ -258,6 +282,13 @@ type OwnerRecord = {
258
282
  operationId: string;
259
283
  browserInstanceId: string;
260
284
  ownerKey: string;
285
+ delegationReplay?: OwnerDelegationReplay | undefined;
286
+ };
287
+
288
+ type OwnerDelegationReplay = {
289
+ version: typeof OWNER_DELEGATION_REPLAY_VERSION;
290
+ acceptedDelegationItemIds: string[];
291
+ pendingDelegations: SessionRealtimeInboundEntry[];
261
292
  };
262
293
 
263
294
  type ConnectionRuntime = {
@@ -338,6 +369,59 @@ export function createCodexRealtimeController(
338
369
  let recoveryTerminal = false;
339
370
  let mutationTail = Promise.resolve();
340
371
  let connectionTask: Promise<void> | null = null;
372
+ const acceptedDelegationItemIds = new Set(
373
+ owner?.delegationReplay?.acceptedDelegationItemIds ?? [],
374
+ );
375
+ const pendingDelegations = new Map(
376
+ (owner?.delegationReplay?.pendingDelegations ?? []).flatMap((entry) =>
377
+ entry.delegationItemId ? [[entry.delegationItemId, entry] as const] : [],
378
+ ),
379
+ );
380
+
381
+ const invalidateStoredOwner = (): void => {
382
+ try {
383
+ storage?.removeItem(storageKey);
384
+ } catch {
385
+ // Best effort only. The bridge still fails closed and retains the exact
386
+ // in-memory snapshot for this controller's bounded recovery attempts.
387
+ }
388
+ };
389
+
390
+ const persistDelegationReplay = (input: {
391
+ acceptedDelegationItemIds: ReadonlySet<string>;
392
+ pendingDelegations: ReadonlyMap<string, SessionRealtimeInboundEntry>;
393
+ }): void => {
394
+ if (!owner || !storage) return;
395
+ const delegationReplay: OwnerDelegationReplay = {
396
+ version: OWNER_DELEGATION_REPLAY_VERSION,
397
+ acceptedDelegationItemIds: [...input.acceptedDelegationItemIds],
398
+ pendingDelegations: [...input.pendingDelegations.values()],
399
+ };
400
+ if (
401
+ delegationReplay.pendingDelegations.length > CODEX_REALTIME_V3_PENDING_MAX_ENTRIES ||
402
+ delegationReplay.acceptedDelegationItemIds.length +
403
+ delegationReplay.pendingDelegations.length >
404
+ OWNER_DELEGATION_REPLAY_MAX_CALLS
405
+ ) {
406
+ invalidateStoredOwner();
407
+ throw new Error("Realtime delegation replay journal exceeded its call limit");
408
+ }
409
+ const next: OwnerRecord = { ...owner, delegationReplay };
410
+ const serialized = JSON.stringify(next);
411
+ if (new TextEncoder().encode(serialized).byteLength > OWNER_DELEGATION_REPLAY_MAX_BYTES) {
412
+ invalidateStoredOwner();
413
+ throw new Error("Realtime delegation replay journal exceeded its byte limit");
414
+ }
415
+ try {
416
+ storage.setItem(storageKey, serialized);
417
+ } catch (error) {
418
+ // Never leave older ownership proof reloadable without the delegation
419
+ // snapshot that the active bridge just froze.
420
+ invalidateStoredOwner();
421
+ throw error;
422
+ }
423
+ owner = next;
424
+ };
341
425
 
342
426
  const publish = (patch: Partial<CodexRealtimeControllerSnapshot>): void => {
343
427
  state = { ...state, ...patch };
@@ -422,6 +506,8 @@ export function createCodexRealtimeController(
422
506
  const clearOwner = (): void => {
423
507
  owner = null;
424
508
  storage?.removeItem(storageKey);
509
+ acceptedDelegationItemIds.clear();
510
+ pendingDelegations.clear();
425
511
  };
426
512
 
427
513
  const transitionEnded = (message = "Realtime mode ended"): void => {
@@ -524,7 +610,10 @@ export function createCodexRealtimeController(
524
610
  });
525
611
  return;
526
612
  }
527
- publish({ audibleOutput: next, ...(next === "audible" ? { error: null } : {}) });
613
+ publish({
614
+ audibleOutput: next,
615
+ ...(next === "audible" ? { error: null } : {}),
616
+ });
528
617
  };
529
618
 
530
619
  const startActiveIntervals = (): void => {
@@ -911,6 +1000,10 @@ export function createCodexRealtimeController(
911
1000
  sync: async (request) =>
912
1001
  await syncForGeneration(targetGeneration, activated.mode.id, request),
913
1002
  randomUUID,
1003
+ ...(options.getModelContext ? { getModelContext: options.getModelContext } : {}),
1004
+ acceptedDelegationItemIds,
1005
+ pendingDelegations,
1006
+ onDelegationReplayStateChange: persistDelegationReplay,
914
1007
  onSnapshot: (nextBridge) => {
915
1008
  if (active?.generation === targetGeneration) publish({ bridge: nextBridge });
916
1009
  },
@@ -1097,7 +1190,12 @@ export function createCodexRealtimeController(
1097
1190
  await handleConnectionFailure(error, "reconnect", false);
1098
1191
  } else {
1099
1192
  clearOwner();
1100
- publish({ status: "error", realtimeId: null, mode: null, error: safeError(error) });
1193
+ publish({
1194
+ status: "error",
1195
+ realtimeId: null,
1196
+ mode: null,
1197
+ error: safeError(error),
1198
+ });
1101
1199
  }
1102
1200
  throw error;
1103
1201
  }
@@ -1173,7 +1271,11 @@ export function createCodexRealtimeController(
1173
1271
  closed = false;
1174
1272
  stopping = false;
1175
1273
  owner = record;
1176
- publish({ status: "recovering", realtimeId: lifecycle.realtimeId, error: null });
1274
+ publish({
1275
+ status: "recovering",
1276
+ realtimeId: lifecycle.realtimeId,
1277
+ error: null,
1278
+ });
1177
1279
  connectionTask = begin(record, true)
1178
1280
  .then(() => undefined)
1179
1281
  .catch(async (error) => {
@@ -1377,8 +1479,13 @@ function readOwnerRecord(
1377
1479
  ): OwnerRecord | null {
1378
1480
  const raw = storage?.getItem(key);
1379
1481
  if (!raw) return null;
1482
+ if (new TextEncoder().encode(raw).byteLength > OWNER_DELEGATION_REPLAY_MAX_BYTES) {
1483
+ storage?.removeItem(key);
1484
+ return null;
1485
+ }
1380
1486
  try {
1381
1487
  const parsed = recordValue(JSON.parse(raw));
1488
+ const delegationReplay = readOwnerDelegationReplay(parsed?.delegationReplay);
1382
1489
  if (
1383
1490
  parsed?.version !== OWNER_RECORD_VERSION ||
1384
1491
  parsed.workspaceId !== scope.workspaceId ||
@@ -1386,18 +1493,120 @@ function readOwnerRecord(
1386
1493
  !stringValue(parsed.operationId) ||
1387
1494
  !stringValue(parsed.browserInstanceId) ||
1388
1495
  !stringValue(parsed.ownerKey) ||
1389
- String(parsed.ownerKey).length < 32
1496
+ String(parsed.ownerKey).length < 32 ||
1497
+ delegationReplay === null
1390
1498
  ) {
1391
1499
  storage?.removeItem(key);
1392
1500
  return null;
1393
1501
  }
1394
- return parsed as OwnerRecord;
1502
+ return {
1503
+ ...(parsed as Omit<OwnerRecord, "delegationReplay">),
1504
+ ...(delegationReplay ? { delegationReplay } : {}),
1505
+ };
1395
1506
  } catch {
1396
1507
  storage?.removeItem(key);
1397
1508
  return null;
1398
1509
  }
1399
1510
  }
1400
1511
 
1512
+ function readOwnerDelegationReplay(value: unknown): OwnerDelegationReplay | undefined | null {
1513
+ if (value === undefined) return undefined;
1514
+ const record = recordValue(value);
1515
+ if (
1516
+ record?.version !== OWNER_DELEGATION_REPLAY_VERSION ||
1517
+ !Array.isArray(record.acceptedDelegationItemIds) ||
1518
+ !Array.isArray(record.pendingDelegations) ||
1519
+ record.acceptedDelegationItemIds.length + record.pendingDelegations.length >
1520
+ OWNER_DELEGATION_REPLAY_MAX_CALLS ||
1521
+ record.pendingDelegations.length > CODEX_REALTIME_V3_PENDING_MAX_ENTRIES
1522
+ ) {
1523
+ return null;
1524
+ }
1525
+ const acceptedDelegationItemIds: string[] = [];
1526
+ const accepted = new Set<string>();
1527
+ for (const candidate of record.acceptedDelegationItemIds) {
1528
+ if (typeof candidate !== "string" || candidate.length < 1 || candidate.length > 1_024) {
1529
+ return null;
1530
+ }
1531
+ if (!accepted.has(candidate)) {
1532
+ accepted.add(candidate);
1533
+ acceptedDelegationItemIds.push(candidate);
1534
+ }
1535
+ }
1536
+ const pendingDelegations: SessionRealtimeInboundEntry[] = [];
1537
+ const pendingIds = new Set<string>();
1538
+ for (const candidate of record.pendingDelegations) {
1539
+ const parsed = readSessionRealtimeInboundEntry(candidate);
1540
+ if (
1541
+ !parsed ||
1542
+ parsed.kind !== "delegation_call" ||
1543
+ !parsed.delegationItemId ||
1544
+ accepted.has(parsed.delegationItemId) ||
1545
+ pendingIds.has(parsed.delegationItemId)
1546
+ ) {
1547
+ return null;
1548
+ }
1549
+ pendingIds.add(parsed.delegationItemId);
1550
+ pendingDelegations.push(parsed);
1551
+ }
1552
+ const replay: OwnerDelegationReplay = {
1553
+ version: OWNER_DELEGATION_REPLAY_VERSION,
1554
+ acceptedDelegationItemIds,
1555
+ pendingDelegations,
1556
+ };
1557
+ if (
1558
+ new TextEncoder().encode(JSON.stringify(replay)).byteLength > OWNER_DELEGATION_REPLAY_MAX_BYTES
1559
+ ) {
1560
+ return null;
1561
+ }
1562
+ return replay;
1563
+ }
1564
+
1565
+ function readSessionRealtimeInboundEntry(value: unknown): SessionRealtimeInboundEntry | null {
1566
+ const record = recordValue(value);
1567
+ if (
1568
+ !record ||
1569
+ Object.keys(record).some((key) => !SESSION_REALTIME_INBOUND_ENTRY_KEYS.has(key)) ||
1570
+ typeof record.operationId !== "string" ||
1571
+ !UUID_PATTERN.test(record.operationId) ||
1572
+ typeof record.kind !== "string" ||
1573
+ !SESSION_REALTIME_INBOUND_KINDS.has(record.kind) ||
1574
+ !optionalNullableEnum(record.role, ["user", "assistant"]) ||
1575
+ !optionalNullableBoundedString(record.providerEventId, 1_024) ||
1576
+ !optionalNullableBoundedString(record.delegationItemId, 1_024) ||
1577
+ !optionalNullableBoundedString(record.text, 131_072) ||
1578
+ (record.payload !== undefined && recordValue(record.payload) === null) ||
1579
+ !optionalModelContext(record.modelContext)
1580
+ ) {
1581
+ return null;
1582
+ }
1583
+ return record as SessionRealtimeInboundEntry;
1584
+ }
1585
+
1586
+ function optionalNullableEnum(value: unknown, allowed: readonly string[]): boolean {
1587
+ return (
1588
+ value === undefined || value === null || (typeof value === "string" && allowed.includes(value))
1589
+ );
1590
+ }
1591
+
1592
+ function optionalNullableBoundedString(value: unknown, maxLength: number): boolean {
1593
+ return (
1594
+ value === undefined ||
1595
+ value === null ||
1596
+ (typeof value === "string" && value.length <= maxLength)
1597
+ );
1598
+ }
1599
+
1600
+ function optionalModelContext(value: unknown): boolean {
1601
+ return (
1602
+ value === undefined ||
1603
+ (typeof value === "string" &&
1604
+ value.length >= 1 &&
1605
+ value.length <= 32_768 &&
1606
+ value.trim() === value)
1607
+ );
1608
+ }
1609
+
1401
1610
  function defaultStorage(): CodexRealtimeOwnerStorage | undefined {
1402
1611
  return typeof sessionStorage === "undefined" ? undefined : sessionStorage;
1403
1612
  }