@opengeni/sdk 0.52.1 → 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.
Files changed (56) hide show
  1. package/README.md +67 -7
  2. package/dist/artifacts.js +5 -5
  3. package/dist/{chunk-FRJFNDIR.js → chunk-4DV37UUA.js} +6 -2
  4. package/dist/chunk-4DV37UUA.js.map +1 -0
  5. package/dist/{chunk-KIHGPM7H.js → chunk-A5DC5WEM.js} +288 -45
  6. package/dist/chunk-A5DC5WEM.js.map +1 -0
  7. package/dist/{chunk-V5F253OG.js → chunk-GU6JF75T.js} +6 -3
  8. package/dist/chunk-GU6JF75T.js.map +1 -0
  9. package/dist/{chunk-MZWTWOX6.js → chunk-ST5DDKJP.js} +327 -1
  10. package/dist/chunk-ST5DDKJP.js.map +1 -0
  11. package/dist/{chunk-FHI4DFIG.js → chunk-TYZ4JL4J.js} +2 -2
  12. package/dist/{chunk-ILQZR5N6.js → chunk-YGH5P47G.js} +693 -34
  13. package/dist/chunk-YGH5P47G.js.map +1 -0
  14. package/dist/{chunk-DXDL7EEW.js → chunk-YKZME56C.js} +197 -113
  15. package/dist/chunk-YKZME56C.js.map +1 -0
  16. package/dist/client.d.ts +108 -18
  17. package/dist/codex-realtime-controller.d.ts +5 -0
  18. package/dist/codex-realtime-controller.js +2 -2
  19. package/dist/codex-realtime-v3.d.ts +13 -2
  20. package/dist/core.js +7 -7
  21. package/dist/desktop.d.ts +8 -0
  22. package/dist/editable-artifacts.js +4 -4
  23. package/dist/gateway-realtime-transport.d.ts +1 -0
  24. package/dist/gateway-realtime-transport.js +5 -3
  25. package/dist/index.d.ts +6 -2
  26. package/dist/index.js +68 -34
  27. package/dist/index.js.map +1 -1
  28. package/dist/interaction-revision-stream.d.ts +11 -0
  29. package/dist/interaction.d.ts +604 -5
  30. package/dist/interaction.js +27 -1
  31. package/dist/realtime.d.ts +3 -3
  32. package/dist/realtime.js +11 -7
  33. package/dist/realtime.js.map +1 -1
  34. package/dist/types.d.ts +283 -69
  35. package/dist/workspace-live-stream.d.ts +14 -0
  36. package/package.json +2 -2
  37. package/src/client.ts +863 -62
  38. package/src/codex-realtime-controller.ts +239 -12
  39. package/src/codex-realtime-lifecycle.ts +1 -0
  40. package/src/codex-realtime-v3.ts +162 -31
  41. package/src/desktop.ts +11 -1
  42. package/src/errors.ts +16 -2
  43. package/src/gateway-realtime-transport.ts +252 -109
  44. package/src/index.ts +42 -13
  45. package/src/interaction-revision-stream.ts +117 -0
  46. package/src/interaction.ts +1049 -5
  47. package/src/realtime.ts +14 -4
  48. package/src/types.ts +353 -72
  49. package/src/workspace-live-stream.ts +137 -0
  50. package/dist/chunk-DXDL7EEW.js.map +0 -1
  51. package/dist/chunk-FRJFNDIR.js.map +0 -1
  52. package/dist/chunk-ILQZR5N6.js.map +0 -1
  53. package/dist/chunk-KIHGPM7H.js.map +0 -1
  54. package/dist/chunk-MZWTWOX6.js.map +0 -1
  55. package/dist/chunk-V5F253OG.js.map +0 -1
  56. /package/dist/{chunk-FHI4DFIG.js.map → chunk-TYZ4JL4J.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  OpenGeniApiError
3
- } from "./chunk-V5F253OG.js";
3
+ } from "./chunk-GU6JF75T.js";
4
4
 
5
5
  // src/codex-realtime-v3-wire.ts
6
6
  var CODEX_REALTIME_INITIAL_ITEMS_MAX_COUNT = 128;
@@ -231,6 +231,7 @@ var CODEX_REALTIME_V3_PENDING_MAX_ENTRIES = 256;
231
231
  var CODEX_REALTIME_V3_PENDING_MAX_BYTES = 16 * 1024 * 1024;
232
232
  var REALTIME_DELEGATION_TRANSCRIPT_MAX_BYTES = 65536;
233
233
  var REALTIME_DELEGATION_INPUT_MAX_BYTES = 65536;
234
+ var REALTIME_MODEL_CONTEXT_MAX_CHARACTERS = 32768;
234
235
  function createCodexRealtimeV3Bridge(options) {
235
236
  let closed = false;
236
237
  let sealed = false;
@@ -253,9 +254,27 @@ function createCodexRealtimeV3Bridge(options) {
253
254
  const clientReceivedSequences = /* @__PURE__ */ new Set();
254
255
  const sentSequences = /* @__PURE__ */ new Set();
255
256
  const finalizedTurnIds = /* @__PURE__ */ new Set();
257
+ const acceptedDelegationItemIds = options.acceptedDelegationItemIds ?? /* @__PURE__ */ new Set();
258
+ const pendingDelegations = options.pendingDelegations ?? /* @__PURE__ */ new Map();
259
+ const locallyQueuedDelegationItemIds = /* @__PURE__ */ new Set();
256
260
  let transcriptSinceDelegation = [];
257
261
  let pendingDelegationUserTranscript = null;
258
262
  const randomUUID = options.randomUUID ?? defaultRandomUUID;
263
+ const currentModelContext = () => {
264
+ let context;
265
+ try {
266
+ context = options.getModelContext?.()?.trim();
267
+ } catch {
268
+ lastError = "Realtime model context callback failed; the provider message continued without application context";
269
+ return void 0;
270
+ }
271
+ if (!context) return void 0;
272
+ if (context.length > REALTIME_MODEL_CONTEXT_MAX_CHARACTERS) {
273
+ lastError = "Realtime model context exceeded the 32768-character limit; the provider message continued without application context";
274
+ return void 0;
275
+ }
276
+ return context;
277
+ };
259
278
  const snapshot = () => ({
260
279
  connectionId: options.connectionId,
261
280
  connectionEpoch: options.connectionEpoch,
@@ -274,9 +293,9 @@ function createCodexRealtimeV3Bridge(options) {
274
293
  fatal
275
294
  });
276
295
  const publish = () => options.onSnapshot?.(snapshot());
277
- const triggerFatal = (message) => {
296
+ const triggerFatalCode = (code, message) => {
278
297
  if (closed || fatal) return;
279
- fatal = { code: "pending_overflow", message };
298
+ fatal = { code, message };
280
299
  lastError = message;
281
300
  publish();
282
301
  try {
@@ -284,6 +303,9 @@ function createCodexRealtimeV3Bridge(options) {
284
303
  } catch {
285
304
  }
286
305
  };
306
+ const triggerFatal = (message) => {
307
+ triggerFatalCode("pending_overflow", message);
308
+ };
287
309
  const enqueue = (entry) => {
288
310
  if (closed || sealed || fatal) return false;
289
311
  const bytes = utf8ByteLength2(JSON.stringify(entry));
@@ -296,6 +318,9 @@ function createCodexRealtimeV3Bridge(options) {
296
318
  pendingInboundBytes += bytes;
297
319
  return true;
298
320
  };
321
+ for (const [delegationItemId, entry] of pendingDelegations) {
322
+ if (enqueue(entry)) locallyQueuedDelegationItemIds.add(delegationItemId);
323
+ }
299
324
  const hasWork = () => pendingInbound.length > 0 || !providerStartedAccepted && providerStarted !== void 0 || clientAckThroughSequence !== null || forceSync;
300
325
  const runFlush = async () => {
301
326
  while (true) {
@@ -321,7 +346,41 @@ function createCodexRealtimeV3Bridge(options) {
321
346
  pendingInbound = [...batch, ...pendingInbound];
322
347
  throw error;
323
348
  }
349
+ const acceptedAfterSync = new Set(acceptedDelegationItemIds);
350
+ const pendingAfterSync = new Map(pendingDelegations);
351
+ let delegationReplayChanged = false;
324
352
  for (const item of batch) {
353
+ if (item.entry.kind === "delegation_call" && item.entry.delegationItemId) {
354
+ delegationReplayChanged = true;
355
+ acceptedAfterSync.add(item.entry.delegationItemId);
356
+ if (pendingAfterSync.get(item.entry.delegationItemId) === item.entry) {
357
+ pendingAfterSync.delete(item.entry.delegationItemId);
358
+ }
359
+ }
360
+ }
361
+ if (delegationReplayChanged) {
362
+ try {
363
+ options.onDelegationReplayStateChange?.({
364
+ acceptedDelegationItemIds: acceptedAfterSync,
365
+ pendingDelegations: pendingAfterSync
366
+ });
367
+ } catch (error) {
368
+ pendingInbound = [...batch, ...pendingInbound];
369
+ triggerFatalCode(
370
+ "replay_journal_failed",
371
+ `Codex realtime delegation replay journal failed: ${safeError(error)}`
372
+ );
373
+ return;
374
+ }
375
+ }
376
+ for (const item of batch) {
377
+ if (item.entry.kind === "delegation_call" && item.entry.delegationItemId) {
378
+ acceptedDelegationItemIds.add(item.entry.delegationItemId);
379
+ if (pendingDelegations.get(item.entry.delegationItemId) === item.entry) {
380
+ pendingDelegations.delete(item.entry.delegationItemId);
381
+ }
382
+ locallyQueuedDelegationItemIds.delete(item.entry.delegationItemId);
383
+ }
325
384
  pendingInboundCount -= 1;
326
385
  pendingInboundBytes -= item.bytes;
327
386
  }
@@ -423,27 +482,60 @@ function createCodexRealtimeV3Bridge(options) {
423
482
  }
424
483
  } else if (event.type === "input_transcript.added" || event.type === "output_transcript.added") {
425
484
  } else if (event.type === "delegation.created") {
426
- activeDelegationId = event.delegationItemId;
427
- const transcript = delegationTranscript(transcriptSinceDelegation, event.inputTranscript);
428
- const coveredTurnIds = transcriptSinceDelegation.map((entry) => entry.turnId);
429
- durable = enqueue({
430
- operationId: randomUUID(),
431
- kind: "delegation_call",
432
- providerEventId: event.providerEventId,
433
- delegationItemId: event.delegationItemId,
434
- text: renderRealtimeDelegationInput(event.inputTranscript, transcript),
435
- payload: {
436
- offsetMs: event.offsetMs,
437
- inputTranscript: event.inputTranscript,
438
- transcriptFenceTurnIds: coveredTurnIds
485
+ if (acceptedDelegationItemIds.has(event.delegationItemId)) {
486
+ ignoredEventCount += 1;
487
+ lastIgnoredEventType = event.type;
488
+ } else if (locallyQueuedDelegationItemIds.has(event.delegationItemId)) {
489
+ ignoredEventCount += 1;
490
+ lastIgnoredEventType = event.type;
491
+ durable = true;
492
+ } else {
493
+ let entry = pendingDelegations.get(event.delegationItemId);
494
+ if (!entry) {
495
+ const transcript = delegationTranscript(transcriptSinceDelegation, event.inputTranscript);
496
+ const coveredTurnIds = transcriptSinceDelegation.map((item) => item.turnId);
497
+ const modelContext = currentModelContext();
498
+ entry = {
499
+ operationId: randomUUID(),
500
+ kind: "delegation_call",
501
+ providerEventId: event.providerEventId,
502
+ delegationItemId: event.delegationItemId,
503
+ text: renderRealtimeDelegationInput(event.inputTranscript, transcript),
504
+ payload: {
505
+ offsetMs: event.offsetMs,
506
+ inputTranscript: event.inputTranscript,
507
+ transcriptFenceTurnIds: coveredTurnIds
508
+ },
509
+ ...modelContext ? { modelContext } : {}
510
+ };
511
+ pendingDelegations.set(event.delegationItemId, entry);
512
+ }
513
+ try {
514
+ options.onDelegationReplayStateChange?.({
515
+ acceptedDelegationItemIds,
516
+ pendingDelegations
517
+ });
518
+ } catch (error) {
519
+ triggerFatalCode(
520
+ "replay_journal_failed",
521
+ `Codex realtime delegation replay journal failed: ${safeError(error)}`
522
+ );
523
+ return Promise.resolve();
524
+ }
525
+ durable = enqueue(entry);
526
+ if (durable) {
527
+ locallyQueuedDelegationItemIds.add(event.delegationItemId);
528
+ activeDelegationId = event.delegationItemId;
529
+ const frozenInputTranscript = typeof entry.payload.inputTranscript === "string" ? entry.payload.inputTranscript : event.inputTranscript;
530
+ const alreadyFinalized = transcriptSinceDelegation.some(
531
+ (item) => item.role === "user" && normalizedTranscript(item.text) === normalizedTranscript(frozenInputTranscript)
532
+ );
533
+ pendingDelegationUserTranscript = alreadyFinalized ? null : {
534
+ delegationItemId: event.delegationItemId,
535
+ text: frozenInputTranscript
536
+ };
537
+ transcriptSinceDelegation = [];
439
538
  }
440
- });
441
- if (durable) {
442
- const alreadyFinalized = transcriptSinceDelegation.some(
443
- (entry) => entry.role === "user" && normalizedTranscript(entry.text) === normalizedTranscript(event.inputTranscript)
444
- );
445
- pendingDelegationUserTranscript = alreadyFinalized ? null : { delegationItemId: event.delegationItemId, text: event.inputTranscript };
446
- transcriptSinceDelegation = [];
447
539
  }
448
540
  } else if (event.type === "output_audio.delta") {
449
541
  speaking = true;
@@ -451,7 +543,9 @@ function createCodexRealtimeV3Bridge(options) {
451
543
  speaking = false;
452
544
  if (event.transcript.length > 0 && !finalizedTurnIds.has(event.turnId)) {
453
545
  const coveredByDelegationItemId = event.role === "user" && pendingDelegationUserTranscript !== null && normalizedTranscript(event.transcript) === normalizedTranscript(pendingDelegationUserTranscript.text) ? pendingDelegationUserTranscript.delegationItemId : null;
454
- durable = enqueue(finalTranscript(randomUUID, event, coveredByDelegationItemId));
546
+ durable = enqueue(
547
+ finalTranscript(randomUUID, event, coveredByDelegationItemId, currentModelContext())
548
+ );
455
549
  if (durable) {
456
550
  finalizedTurnIds.add(event.turnId);
457
551
  if (coveredByDelegationItemId) {
@@ -508,7 +602,7 @@ function createCodexRealtimeV3Bridge(options) {
508
602
  }
509
603
  };
510
604
  }
511
- function finalTranscript(randomUUID, event, coveredByDelegationItemId) {
605
+ function finalTranscript(randomUUID, event, coveredByDelegationItemId, modelContext) {
512
606
  return {
513
607
  operationId: randomUUID(),
514
608
  kind: event.role === "user" ? "user_transcript" : "assistant_transcript",
@@ -517,7 +611,8 @@ function finalTranscript(randomUUID, event, coveredByDelegationItemId) {
517
611
  payload: {
518
612
  turnId: event.turnId,
519
613
  ...coveredByDelegationItemId ? { coveredByDelegationItemId } : {}
520
- }
614
+ },
615
+ ...modelContext ? { modelContext } : {}
521
616
  };
522
617
  }
523
618
  function delegationTranscript(entries, inputTranscript) {
@@ -573,7 +668,10 @@ function sendOutbound(events, entry) {
573
668
  delegationItemId: entry.delegationItemId,
574
669
  text,
575
670
  channel: payloadChannel ?? "speakable"
576
- }) : encodeCodexRealtimeV3SessionContextAppend({ text, channel: payloadChannel });
671
+ }) : encodeCodexRealtimeV3SessionContextAppend({
672
+ text,
673
+ channel: payloadChannel
674
+ });
577
675
  for (const message of messages) events.send(JSON.stringify(message));
578
676
  }
579
677
  function sendDelegationProgress(events, delegationItemId, entries) {
@@ -951,7 +1049,7 @@ function projectSessionRealtimeLifecycle(events) {
951
1049
  return projected;
952
1050
  }
953
1051
  function realtimeModel(value) {
954
- return value === "gpt-live-1-boulder-alpha" || value === "opengeni-gateway/openai/gpt-realtime-2.1" || value === "opengeni-gateway/openai/gpt-realtime-mini" || value === "opengeni-gateway/xai/grok-voice-think-fast-2.0" || value === "workspace-gateway/openai/gpt-realtime-2.1" || value === "workspace-gateway/openai/gpt-realtime-mini" || value === "workspace-gateway/xai/grok-voice-think-fast-2.0" ? value : null;
1052
+ return value === "gpt-live-1-boulder-alpha" || value === "supergrok/grok-voice-think-fast-2.0" || value === "opengeni-gateway/openai/gpt-realtime-2.1" || value === "opengeni-gateway/openai/gpt-realtime-mini" || value === "opengeni-gateway/xai/grok-voice-think-fast-2.0" || value === "workspace-gateway/openai/gpt-realtime-2.1" || value === "workspace-gateway/openai/gpt-realtime-mini" || value === "workspace-gateway/xai/grok-voice-think-fast-2.0" ? value : null;
955
1053
  }
956
1054
  function recordValue(value) {
957
1055
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
@@ -973,8 +1071,31 @@ var CODEX_REALTIME_NEGOTIATION_TIMEOUT_MS = 2e4;
973
1071
  var DEFAULT_CONNECTION_ROTATION_INTERVAL_MS = 15 * 6e4;
974
1072
  var DEFAULT_RECONNECT_BACKOFF_MS = [250, 1e3, 2e3, 5e3];
975
1073
  var OWNER_RECORD_VERSION = 1;
1074
+ var OWNER_DELEGATION_REPLAY_VERSION = 1;
1075
+ var OWNER_DELEGATION_REPLAY_MAX_CALLS = 4096;
1076
+ var OWNER_DELEGATION_REPLAY_MAX_BYTES = 4 * 1024 * 1024;
1077
+ var SESSION_REALTIME_INBOUND_ENTRY_KEYS = /* @__PURE__ */ new Set([
1078
+ "operationId",
1079
+ "kind",
1080
+ "role",
1081
+ "providerEventId",
1082
+ "delegationItemId",
1083
+ "text",
1084
+ "payload",
1085
+ "modelContext"
1086
+ ]);
1087
+ var SESSION_REALTIME_INBOUND_KINDS = /* @__PURE__ */ new Set([
1088
+ "user_transcript",
1089
+ "assistant_transcript",
1090
+ "delegation_call",
1091
+ "interruption",
1092
+ "error"
1093
+ ]);
1094
+ var 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;
976
1095
  function sessionRealtimeOwnerStorageNamespace(model) {
977
- return model === "gpt-live-1-boulder-alpha" ? "codex-realtime-owner" : "gateway-realtime-owner";
1096
+ if (model === "gpt-live-1-boulder-alpha") return "codex-realtime-owner";
1097
+ if (model === "supergrok/grok-voice-think-fast-2.0") return "xai-realtime-owner";
1098
+ return "gateway-realtime-owner";
978
1099
  }
979
1100
  function sessionRealtimeOwnerStorageKey(workspaceId, sessionId, model) {
980
1101
  return ownerStorageKey(workspaceId, sessionId, sessionRealtimeOwnerStorageNamespace(model));
@@ -1046,6 +1167,45 @@ function createCodexRealtimeController(options) {
1046
1167
  let recoveryTerminal = false;
1047
1168
  let mutationTail = Promise.resolve();
1048
1169
  let connectionTask = null;
1170
+ const acceptedDelegationItemIds = new Set(
1171
+ owner?.delegationReplay?.acceptedDelegationItemIds ?? []
1172
+ );
1173
+ const pendingDelegations = new Map(
1174
+ (owner?.delegationReplay?.pendingDelegations ?? []).flatMap(
1175
+ (entry) => entry.delegationItemId ? [[entry.delegationItemId, entry]] : []
1176
+ )
1177
+ );
1178
+ const invalidateStoredOwner = () => {
1179
+ try {
1180
+ storage?.removeItem(storageKey);
1181
+ } catch {
1182
+ }
1183
+ };
1184
+ const persistDelegationReplay = (input) => {
1185
+ if (!owner || !storage) return;
1186
+ const delegationReplay = {
1187
+ version: OWNER_DELEGATION_REPLAY_VERSION,
1188
+ acceptedDelegationItemIds: [...input.acceptedDelegationItemIds],
1189
+ pendingDelegations: [...input.pendingDelegations.values()]
1190
+ };
1191
+ if (delegationReplay.pendingDelegations.length > CODEX_REALTIME_V3_PENDING_MAX_ENTRIES || delegationReplay.acceptedDelegationItemIds.length + delegationReplay.pendingDelegations.length > OWNER_DELEGATION_REPLAY_MAX_CALLS) {
1192
+ invalidateStoredOwner();
1193
+ throw new Error("Realtime delegation replay journal exceeded its call limit");
1194
+ }
1195
+ const next = { ...owner, delegationReplay };
1196
+ const serialized = JSON.stringify(next);
1197
+ if (new TextEncoder().encode(serialized).byteLength > OWNER_DELEGATION_REPLAY_MAX_BYTES) {
1198
+ invalidateStoredOwner();
1199
+ throw new Error("Realtime delegation replay journal exceeded its byte limit");
1200
+ }
1201
+ try {
1202
+ storage.setItem(storageKey, serialized);
1203
+ } catch (error) {
1204
+ invalidateStoredOwner();
1205
+ throw error;
1206
+ }
1207
+ owner = next;
1208
+ };
1049
1209
  const publish = (patch) => {
1050
1210
  state = { ...state, ...patch };
1051
1211
  for (const listener of listeners) listener({ ...state });
@@ -1115,6 +1275,8 @@ function createCodexRealtimeController(options) {
1115
1275
  const clearOwner = () => {
1116
1276
  owner = null;
1117
1277
  storage?.removeItem(storageKey);
1278
+ acceptedDelegationItemIds.clear();
1279
+ pendingDelegations.clear();
1118
1280
  };
1119
1281
  const transitionEnded = (message = "Realtime mode ended") => {
1120
1282
  stopping = false;
@@ -1153,16 +1315,20 @@ function createCodexRealtimeController(options) {
1153
1315
  publish({ microphone: "active" });
1154
1316
  return acquired;
1155
1317
  } catch (error) {
1156
- if (error instanceof CodexRealtimeMicrophoneError) {
1157
- const kind = error.code === "permission_denied" ? "permission_failure" : "device_failure";
1318
+ const microphoneError = error instanceof CodexRealtimeMicrophoneError ? error : signal.aborted && state.microphone === "acquiring" ? new CodexRealtimeMicrophoneError(
1319
+ "acquisition_failed",
1320
+ "Microphone did not become available before voice startup timed out"
1321
+ ) : null;
1322
+ if (microphoneError) {
1323
+ const kind = microphoneError.code === "permission_denied" ? "permission_failure" : "device_failure";
1158
1324
  publish({
1159
- microphone: error.code,
1325
+ microphone: microphoneError.code,
1160
1326
  status: state.mode?.state === "active" ? "recovering" : "error",
1161
- diagnostic: diagnostic(kind, error.message, true),
1162
- error: error.message
1327
+ diagnostic: diagnostic(kind, microphoneError.message, true),
1328
+ error: microphoneError.message
1163
1329
  });
1164
1330
  }
1165
- throw error;
1331
+ throw microphoneError ?? error;
1166
1332
  }
1167
1333
  };
1168
1334
  const syncForGeneration = async (targetGeneration, realtimeId, request) => await exclusive(async () => {
@@ -1188,7 +1354,10 @@ function createCodexRealtimeController(options) {
1188
1354
  });
1189
1355
  return;
1190
1356
  }
1191
- publish({ audibleOutput: next, ...next === "audible" ? { error: null } : {} });
1357
+ publish({
1358
+ audibleOutput: next,
1359
+ ...next === "audible" ? { error: null } : {}
1360
+ });
1192
1361
  };
1193
1362
  const startActiveIntervals = () => {
1194
1363
  if (heartbeatTimer === null) {
@@ -1505,6 +1674,10 @@ function createCodexRealtimeController(options) {
1505
1674
  listen: false,
1506
1675
  sync: async (request) => await syncForGeneration(targetGeneration, activated.mode.id, request),
1507
1676
  randomUUID,
1677
+ ...options.getModelContext ? { getModelContext: options.getModelContext } : {},
1678
+ acceptedDelegationItemIds,
1679
+ pendingDelegations,
1680
+ onDelegationReplayStateChange: persistDelegationReplay,
1508
1681
  onSnapshot: (nextBridge) => {
1509
1682
  if (active?.generation === targetGeneration) publish({ bridge: nextBridge });
1510
1683
  },
@@ -1670,7 +1843,12 @@ function createCodexRealtimeController(options) {
1670
1843
  await handleConnectionFailure(error, "reconnect", false);
1671
1844
  } else {
1672
1845
  clearOwner();
1673
- publish({ status: "error", realtimeId: null, mode: null, error: safeError2(error) });
1846
+ publish({
1847
+ status: "error",
1848
+ realtimeId: null,
1849
+ mode: null,
1850
+ error: safeError2(error)
1851
+ });
1674
1852
  }
1675
1853
  throw error;
1676
1854
  }
@@ -1739,7 +1917,11 @@ function createCodexRealtimeController(options) {
1739
1917
  closed = false;
1740
1918
  stopping = false;
1741
1919
  owner = record2;
1742
- publish({ status: "recovering", realtimeId: lifecycle.realtimeId, error: null });
1920
+ publish({
1921
+ status: "recovering",
1922
+ realtimeId: lifecycle.realtimeId,
1923
+ error: null
1924
+ });
1743
1925
  connectionTask = begin(record2, true).then(() => void 0).catch(async (error) => {
1744
1926
  connectionTask = null;
1745
1927
  await handleConnectionFailure(error, "reload", false);
@@ -1906,18 +2088,79 @@ function ownerStorageKey(workspaceId, sessionId, namespace = "codex-realtime-own
1906
2088
  function readOwnerRecord(storage, key, scope) {
1907
2089
  const raw = storage?.getItem(key);
1908
2090
  if (!raw) return null;
2091
+ if (new TextEncoder().encode(raw).byteLength > OWNER_DELEGATION_REPLAY_MAX_BYTES) {
2092
+ storage?.removeItem(key);
2093
+ return null;
2094
+ }
1909
2095
  try {
1910
2096
  const parsed = recordValue2(JSON.parse(raw));
1911
- if (parsed?.version !== OWNER_RECORD_VERSION || parsed.workspaceId !== scope.workspaceId || parsed.sessionId !== scope.sessionId || !stringValue2(parsed.operationId) || !stringValue2(parsed.browserInstanceId) || !stringValue2(parsed.ownerKey) || String(parsed.ownerKey).length < 32) {
2097
+ const delegationReplay = readOwnerDelegationReplay(parsed?.delegationReplay);
2098
+ if (parsed?.version !== OWNER_RECORD_VERSION || parsed.workspaceId !== scope.workspaceId || parsed.sessionId !== scope.sessionId || !stringValue2(parsed.operationId) || !stringValue2(parsed.browserInstanceId) || !stringValue2(parsed.ownerKey) || String(parsed.ownerKey).length < 32 || delegationReplay === null) {
1912
2099
  storage?.removeItem(key);
1913
2100
  return null;
1914
2101
  }
1915
- return parsed;
2102
+ return {
2103
+ ...parsed,
2104
+ ...delegationReplay ? { delegationReplay } : {}
2105
+ };
1916
2106
  } catch {
1917
2107
  storage?.removeItem(key);
1918
2108
  return null;
1919
2109
  }
1920
2110
  }
2111
+ function readOwnerDelegationReplay(value) {
2112
+ if (value === void 0) return void 0;
2113
+ const record2 = recordValue2(value);
2114
+ if (record2?.version !== OWNER_DELEGATION_REPLAY_VERSION || !Array.isArray(record2.acceptedDelegationItemIds) || !Array.isArray(record2.pendingDelegations) || record2.acceptedDelegationItemIds.length + record2.pendingDelegations.length > OWNER_DELEGATION_REPLAY_MAX_CALLS || record2.pendingDelegations.length > CODEX_REALTIME_V3_PENDING_MAX_ENTRIES) {
2115
+ return null;
2116
+ }
2117
+ const acceptedDelegationItemIds = [];
2118
+ const accepted = /* @__PURE__ */ new Set();
2119
+ for (const candidate of record2.acceptedDelegationItemIds) {
2120
+ if (typeof candidate !== "string" || candidate.length < 1 || candidate.length > 1024) {
2121
+ return null;
2122
+ }
2123
+ if (!accepted.has(candidate)) {
2124
+ accepted.add(candidate);
2125
+ acceptedDelegationItemIds.push(candidate);
2126
+ }
2127
+ }
2128
+ const pendingDelegations = [];
2129
+ const pendingIds = /* @__PURE__ */ new Set();
2130
+ for (const candidate of record2.pendingDelegations) {
2131
+ const parsed = readSessionRealtimeInboundEntry(candidate);
2132
+ if (!parsed || parsed.kind !== "delegation_call" || !parsed.delegationItemId || accepted.has(parsed.delegationItemId) || pendingIds.has(parsed.delegationItemId)) {
2133
+ return null;
2134
+ }
2135
+ pendingIds.add(parsed.delegationItemId);
2136
+ pendingDelegations.push(parsed);
2137
+ }
2138
+ const replay = {
2139
+ version: OWNER_DELEGATION_REPLAY_VERSION,
2140
+ acceptedDelegationItemIds,
2141
+ pendingDelegations
2142
+ };
2143
+ if (new TextEncoder().encode(JSON.stringify(replay)).byteLength > OWNER_DELEGATION_REPLAY_MAX_BYTES) {
2144
+ return null;
2145
+ }
2146
+ return replay;
2147
+ }
2148
+ function readSessionRealtimeInboundEntry(value) {
2149
+ const record2 = recordValue2(value);
2150
+ if (!record2 || Object.keys(record2).some((key) => !SESSION_REALTIME_INBOUND_ENTRY_KEYS.has(key)) || typeof record2.operationId !== "string" || !UUID_PATTERN.test(record2.operationId) || typeof record2.kind !== "string" || !SESSION_REALTIME_INBOUND_KINDS.has(record2.kind) || !optionalNullableEnum(record2.role, ["user", "assistant"]) || !optionalNullableBoundedString(record2.providerEventId, 1024) || !optionalNullableBoundedString(record2.delegationItemId, 1024) || !optionalNullableBoundedString(record2.text, 131072) || record2.payload !== void 0 && recordValue2(record2.payload) === null || !optionalModelContext(record2.modelContext)) {
2151
+ return null;
2152
+ }
2153
+ return record2;
2154
+ }
2155
+ function optionalNullableEnum(value, allowed) {
2156
+ return value === void 0 || value === null || typeof value === "string" && allowed.includes(value);
2157
+ }
2158
+ function optionalNullableBoundedString(value, maxLength) {
2159
+ return value === void 0 || value === null || typeof value === "string" && value.length <= maxLength;
2160
+ }
2161
+ function optionalModelContext(value) {
2162
+ return value === void 0 || typeof value === "string" && value.length >= 1 && value.length <= 32768 && value.trim() === value;
2163
+ }
1921
2164
  function defaultStorage() {
1922
2165
  return typeof sessionStorage === "undefined" ? void 0 : sessionStorage;
1923
2166
  }
@@ -1990,6 +2233,10 @@ function safeError2(error) {
1990
2233
  }
1991
2234
 
1992
2235
  export {
2236
+ CodexRealtimeMicrophoneError,
2237
+ startCodexRealtimeWebrtc,
2238
+ acquireCodexRealtimeMicrophone,
2239
+ codexRealtimeMicrophoneHealthy,
1993
2240
  CODEX_REALTIME_INITIAL_ITEMS_MAX_COUNT,
1994
2241
  CODEX_REALTIME_INITIAL_ITEMS_MAX_TOKENS,
1995
2242
  CODEX_REALTIME_CONTEXT_APPEND_MAX_BYTES,
@@ -2004,10 +2251,6 @@ export {
2004
2251
  CODEX_REALTIME_V3_PENDING_MAX_ENTRIES,
2005
2252
  CODEX_REALTIME_V3_PENDING_MAX_BYTES,
2006
2253
  createCodexRealtimeV3Bridge,
2007
- CodexRealtimeMicrophoneError,
2008
- startCodexRealtimeWebrtc,
2009
- acquireCodexRealtimeMicrophone,
2010
- codexRealtimeMicrophoneHealthy,
2011
2254
  projectSessionRealtimeLifecycle,
2012
2255
  CODEX_REALTIME_NEGOTIATION_TIMEOUT_MS,
2013
2256
  sessionRealtimeOwnerStorageNamespace,
@@ -2015,4 +2258,4 @@ export {
2015
2258
  hasStoredSessionRealtimeOwnerProof,
2016
2259
  createCodexRealtimeController
2017
2260
  };
2018
- //# sourceMappingURL=chunk-KIHGPM7H.js.map
2261
+ //# sourceMappingURL=chunk-A5DC5WEM.js.map