@opengeni/sdk 0.57.0 → 2.2.0-canary.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.
Files changed (94) hide show
  1. package/README.md +123 -2
  2. package/dist/artifacts.js +5 -5
  3. package/dist/automations-client.d.ts +17 -0
  4. package/dist/automations.d.ts +3 -0
  5. package/dist/automations.js +78 -0
  6. package/dist/automations.js.map +1 -0
  7. package/dist/{chunk-JDLDDRNE.js → chunk-C2H7HBNP.js} +290 -33
  8. package/dist/chunk-C2H7HBNP.js.map +1 -0
  9. package/dist/{chunk-GU6JF75T.js → chunk-C4DJPZRU.js} +1 -1
  10. package/dist/{chunk-GU6JF75T.js.map → chunk-C4DJPZRU.js.map} +1 -1
  11. package/dist/{chunk-JRPFWI6T.js → chunk-G6LBVWKT.js} +2 -2
  12. package/dist/{chunk-HJ3HHUT5.js → chunk-GLDV5QY7.js} +16 -2
  13. package/dist/chunk-GLDV5QY7.js.map +1 -0
  14. package/dist/{chunk-ST5DDKJP.js → chunk-GW3EJ2GP.js} +52 -1
  15. package/dist/chunk-GW3EJ2GP.js.map +1 -0
  16. package/dist/{chunk-VWE2QIVO.js → chunk-XNG7YGR3.js} +23 -6
  17. package/dist/chunk-XNG7YGR3.js.map +1 -0
  18. package/dist/{chunk-PKQ377ED.js → chunk-YBQTKNTL.js} +696 -57
  19. package/dist/chunk-YBQTKNTL.js.map +1 -0
  20. package/dist/client.d.ts +151 -26
  21. package/dist/codex-realtime-controller.d.ts +3 -0
  22. package/dist/codex-realtime-controller.js +2 -2
  23. package/dist/codex-realtime-v3.d.ts +13 -2
  24. package/dist/company-brain.d.ts +32 -0
  25. package/dist/company-profile.d.ts +1 -1
  26. package/dist/core.js +4 -4
  27. package/dist/editable-artifacts/browser-session.d.ts +7 -3
  28. package/dist/editable-artifacts/controller.d.ts +4 -1
  29. package/dist/editable-artifacts/errors.d.ts +1 -1
  30. package/dist/editable-artifacts/http-live-transport.d.ts +6 -2
  31. package/dist/editable-artifacts/index.d.ts +2 -0
  32. package/dist/editable-artifacts/open-failure.d.ts +9 -0
  33. package/dist/editable-artifacts/types.d.ts +4 -3
  34. package/dist/editable-artifacts/worker/kernel-adapter.d.ts +1 -1
  35. package/dist/editable-artifacts-worker.js +44 -17
  36. package/dist/editable-artifacts-worker.js.map +1 -1
  37. package/dist/editable-artifacts.js +222 -119
  38. package/dist/editable-artifacts.js.map +1 -1
  39. package/dist/errors.d.ts +1 -1
  40. package/dist/index.d.ts +7 -4
  41. package/dist/index.js +61 -12
  42. package/dist/index.js.map +1 -1
  43. package/dist/interaction.d.ts +23 -0
  44. package/dist/interaction.js +4 -1
  45. package/dist/organization-private-session-settings.d.ts +6 -0
  46. package/dist/organization-private-session-settings.js +22 -0
  47. package/dist/organization-private-session-settings.js.map +1 -0
  48. package/dist/pr-review-client.d.ts +15 -0
  49. package/dist/pr-review.d.ts +4 -0
  50. package/dist/pr-review.js +56 -0
  51. package/dist/pr-review.js.map +1 -0
  52. package/dist/preference-registry.d.ts +8 -0
  53. package/dist/realtime.js +2 -2
  54. package/dist/retained-artifacts.d.ts +5 -1
  55. package/dist/types.d.ts +976 -17
  56. package/dist/workspace-instruction-policies.d.ts +22 -0
  57. package/dist/workspace-learning.d.ts +124 -0
  58. package/package.json +14 -2
  59. package/src/automations-client.ts +118 -0
  60. package/src/automations.ts +15 -0
  61. package/src/client.ts +974 -71
  62. package/src/codex-realtime-controller.ts +235 -5
  63. package/src/codex-realtime-v3.ts +162 -31
  64. package/src/company-brain.ts +99 -0
  65. package/src/company-profile.ts +4 -1
  66. package/src/editable-artifacts/browser-session.ts +36 -22
  67. package/src/editable-artifacts/controller.ts +66 -45
  68. package/src/editable-artifacts/errors.ts +2 -0
  69. package/src/editable-artifacts/http-live-transport.ts +62 -37
  70. package/src/editable-artifacts/index.ts +6 -0
  71. package/src/editable-artifacts/open-failure.ts +79 -0
  72. package/src/editable-artifacts/storage.ts +31 -40
  73. package/src/editable-artifacts/types.ts +4 -3
  74. package/src/editable-artifacts/worker/kernel-adapter.ts +23 -7
  75. package/src/editable-artifacts/worker/runtime.ts +26 -13
  76. package/src/editable-artifacts/worker/wire-codec.ts +23 -5
  77. package/src/errors.ts +1 -1
  78. package/src/index.ts +131 -0
  79. package/src/interaction.ts +95 -0
  80. package/src/organization-private-session-settings.ts +33 -0
  81. package/src/pr-review-client.ts +84 -0
  82. package/src/pr-review.ts +15 -0
  83. package/src/preference-registry.ts +9 -0
  84. package/src/retained-artifacts.ts +101 -0
  85. package/src/stream.ts +13 -2
  86. package/src/types.ts +1117 -16
  87. package/src/workspace-instruction-policies.ts +24 -0
  88. package/src/workspace-learning.ts +138 -0
  89. package/dist/chunk-HJ3HHUT5.js.map +0 -1
  90. package/dist/chunk-JDLDDRNE.js.map +0 -1
  91. package/dist/chunk-PKQ377ED.js.map +0 -1
  92. package/dist/chunk-ST5DDKJP.js.map +0 -1
  93. package/dist/chunk-VWE2QIVO.js.map +0 -1
  94. /package/dist/{chunk-JRPFWI6T.js.map → chunk-G6LBVWKT.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  OpenGeniApiError
3
- } from "./chunk-GU6JF75T.js";
3
+ } from "./chunk-C4DJPZRU.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;
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
+ }
324
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) {
@@ -972,7 +1070,29 @@ var OUTBOUND_SYNC_INTERVAL_MS = 1e3;
972
1070
  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];
1073
+ var MAX_BROWSER_TIMEOUT_MS = 2147483647;
975
1074
  var OWNER_RECORD_VERSION = 1;
1075
+ var OWNER_DELEGATION_REPLAY_VERSION = 1;
1076
+ var OWNER_DELEGATION_REPLAY_MAX_CALLS = 4096;
1077
+ var OWNER_DELEGATION_REPLAY_MAX_BYTES = 4 * 1024 * 1024;
1078
+ var SESSION_REALTIME_INBOUND_ENTRY_KEYS = /* @__PURE__ */ new Set([
1079
+ "operationId",
1080
+ "kind",
1081
+ "role",
1082
+ "providerEventId",
1083
+ "delegationItemId",
1084
+ "text",
1085
+ "payload",
1086
+ "modelContext"
1087
+ ]);
1088
+ var SESSION_REALTIME_INBOUND_KINDS = /* @__PURE__ */ new Set([
1089
+ "user_transcript",
1090
+ "assistant_transcript",
1091
+ "delegation_call",
1092
+ "interruption",
1093
+ "error"
1094
+ ]);
1095
+ 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
1096
  function sessionRealtimeOwnerStorageNamespace(model) {
977
1097
  if (model === "gpt-live-1-boulder-alpha") return "codex-realtime-owner";
978
1098
  if (model === "supergrok/grok-voice-think-fast-2.0") return "xai-realtime-owner";
@@ -1001,6 +1121,7 @@ function createCodexRealtimeController(options) {
1001
1121
  );
1002
1122
  const model = options.model ?? "gpt-live-1-boulder-alpha";
1003
1123
  const randomUUID = options.randomUUID ?? defaultRandomUUID2;
1124
+ const now = options.now ?? (() => /* @__PURE__ */ new Date());
1004
1125
  const scheduleInterval = options.setInterval ?? ((callback, delay) => globalThis.setInterval(callback, delay));
1005
1126
  const unscheduleInterval = options.clearInterval ?? ((handle) => globalThis.clearInterval(handle));
1006
1127
  const scheduleTimeout = options.setTimeout ?? ((callback, delay) => globalThis.setTimeout(callback, delay));
@@ -1041,6 +1162,7 @@ function createCodexRealtimeController(options) {
1041
1162
  let rotationTimer = null;
1042
1163
  let reconnectTimer = null;
1043
1164
  let negotiationTimer = null;
1165
+ let lostOwnerExpiryTimer = null;
1044
1166
  let closed = false;
1045
1167
  let stopping = false;
1046
1168
  let generation = 0;
@@ -1048,6 +1170,45 @@ function createCodexRealtimeController(options) {
1048
1170
  let recoveryTerminal = false;
1049
1171
  let mutationTail = Promise.resolve();
1050
1172
  let connectionTask = null;
1173
+ const acceptedDelegationItemIds = new Set(
1174
+ owner?.delegationReplay?.acceptedDelegationItemIds ?? []
1175
+ );
1176
+ const pendingDelegations = new Map(
1177
+ (owner?.delegationReplay?.pendingDelegations ?? []).flatMap(
1178
+ (entry) => entry.delegationItemId ? [[entry.delegationItemId, entry]] : []
1179
+ )
1180
+ );
1181
+ const invalidateStoredOwner = () => {
1182
+ try {
1183
+ storage?.removeItem(storageKey);
1184
+ } catch {
1185
+ }
1186
+ };
1187
+ const persistDelegationReplay = (input) => {
1188
+ if (!owner || !storage) return;
1189
+ const delegationReplay = {
1190
+ version: OWNER_DELEGATION_REPLAY_VERSION,
1191
+ acceptedDelegationItemIds: [...input.acceptedDelegationItemIds],
1192
+ pendingDelegations: [...input.pendingDelegations.values()]
1193
+ };
1194
+ if (delegationReplay.pendingDelegations.length > CODEX_REALTIME_V3_PENDING_MAX_ENTRIES || delegationReplay.acceptedDelegationItemIds.length + delegationReplay.pendingDelegations.length > OWNER_DELEGATION_REPLAY_MAX_CALLS) {
1195
+ invalidateStoredOwner();
1196
+ throw new Error("Realtime delegation replay journal exceeded its call limit");
1197
+ }
1198
+ const next = { ...owner, delegationReplay };
1199
+ const serialized = JSON.stringify(next);
1200
+ if (new TextEncoder().encode(serialized).byteLength > OWNER_DELEGATION_REPLAY_MAX_BYTES) {
1201
+ invalidateStoredOwner();
1202
+ throw new Error("Realtime delegation replay journal exceeded its byte limit");
1203
+ }
1204
+ try {
1205
+ storage.setItem(storageKey, serialized);
1206
+ } catch (error) {
1207
+ invalidateStoredOwner();
1208
+ throw error;
1209
+ }
1210
+ owner = next;
1211
+ };
1051
1212
  const publish = (patch) => {
1052
1213
  state = { ...state, ...patch };
1053
1214
  for (const listener of listeners) listener({ ...state });
@@ -1073,11 +1234,13 @@ function createCodexRealtimeController(options) {
1073
1234
  if (rotationTimer !== null) unscheduleTimeout(rotationTimer);
1074
1235
  if (reconnectTimer !== null) unscheduleTimeout(reconnectTimer);
1075
1236
  if (negotiationTimer !== null) unscheduleTimeout(negotiationTimer);
1237
+ if (lostOwnerExpiryTimer !== null) unscheduleTimeout(lostOwnerExpiryTimer);
1076
1238
  heartbeatTimer = null;
1077
1239
  syncTimer = null;
1078
1240
  rotationTimer = null;
1079
1241
  reconnectTimer = null;
1080
1242
  negotiationTimer = null;
1243
+ lostOwnerExpiryTimer = null;
1081
1244
  };
1082
1245
  const stopNegotiationTimers = () => {
1083
1246
  if (heartbeatTimer !== null) unscheduleInterval(heartbeatTimer);
@@ -1117,6 +1280,8 @@ function createCodexRealtimeController(options) {
1117
1280
  const clearOwner = () => {
1118
1281
  owner = null;
1119
1282
  storage?.removeItem(storageKey);
1283
+ acceptedDelegationItemIds.clear();
1284
+ pendingDelegations.clear();
1120
1285
  };
1121
1286
  const transitionEnded = (message = "Realtime mode ended") => {
1122
1287
  stopping = false;
@@ -1194,7 +1359,10 @@ function createCodexRealtimeController(options) {
1194
1359
  });
1195
1360
  return;
1196
1361
  }
1197
- publish({ audibleOutput: next, ...next === "audible" ? { error: null } : {} });
1362
+ publish({
1363
+ audibleOutput: next,
1364
+ ...next === "audible" ? { error: null } : {}
1365
+ });
1198
1366
  };
1199
1367
  const startActiveIntervals = () => {
1200
1368
  if (heartbeatTimer === null) {
@@ -1511,6 +1679,10 @@ function createCodexRealtimeController(options) {
1511
1679
  listen: false,
1512
1680
  sync: async (request) => await syncForGeneration(targetGeneration, activated.mode.id, request),
1513
1681
  randomUUID,
1682
+ ...options.getModelContext ? { getModelContext: options.getModelContext } : {},
1683
+ acceptedDelegationItemIds,
1684
+ pendingDelegations,
1685
+ onDelegationReplayStateChange: persistDelegationReplay,
1514
1686
  onSnapshot: (nextBridge) => {
1515
1687
  if (active?.generation === targetGeneration) publish({ bridge: nextBridge });
1516
1688
  },
@@ -1676,7 +1848,12 @@ function createCodexRealtimeController(options) {
1676
1848
  await handleConnectionFailure(error, "reconnect", false);
1677
1849
  } else {
1678
1850
  clearOwner();
1679
- publish({ status: "error", realtimeId: null, mode: null, error: safeError2(error) });
1851
+ publish({
1852
+ status: "error",
1853
+ realtimeId: null,
1854
+ mode: null,
1855
+ error: safeError2(error)
1856
+ });
1680
1857
  }
1681
1858
  throw error;
1682
1859
  }
@@ -1730,6 +1907,12 @@ function createCodexRealtimeController(options) {
1730
1907
  if (!record2 || record2.operationId !== lifecycle.operationId) {
1731
1908
  closeBrowserResources();
1732
1909
  owner = null;
1910
+ const leaseExpiresAt = Date.parse(lifecycle.leaseExpiresAt);
1911
+ const remainingLeaseMs = leaseExpiresAt - now().getTime();
1912
+ if (Number.isFinite(remainingLeaseMs) && remainingLeaseMs <= 0) {
1913
+ transitionEnded("Realtime lease expired");
1914
+ return;
1915
+ }
1733
1916
  const message = "Realtime is active in another browser owner. It can resume after that owner stops or its lease expires.";
1734
1917
  publish({
1735
1918
  status: "lost_owner",
@@ -1739,13 +1922,26 @@ function createCodexRealtimeController(options) {
1739
1922
  diagnostic: diagnostic("lost_owner", message, false),
1740
1923
  error: message
1741
1924
  });
1925
+ if (Number.isFinite(remainingLeaseMs) && remainingLeaseMs <= MAX_BROWSER_TIMEOUT_MS) {
1926
+ const observedRealtimeId = lifecycle.realtimeId;
1927
+ lostOwnerExpiryTimer = scheduleTimeout(() => {
1928
+ lostOwnerExpiryTimer = null;
1929
+ if (state.status === "lost_owner" && state.realtimeId === observedRealtimeId) {
1930
+ transitionEnded("Realtime lease expired");
1931
+ }
1932
+ }, remainingLeaseMs);
1933
+ }
1742
1934
  return;
1743
1935
  }
1744
1936
  if (connectionTask || state.status === "starting") return;
1745
1937
  closed = false;
1746
1938
  stopping = false;
1747
1939
  owner = record2;
1748
- publish({ status: "recovering", realtimeId: lifecycle.realtimeId, error: null });
1940
+ publish({
1941
+ status: "recovering",
1942
+ realtimeId: lifecycle.realtimeId,
1943
+ error: null
1944
+ });
1749
1945
  connectionTask = begin(record2, true).then(() => void 0).catch(async (error) => {
1750
1946
  connectionTask = null;
1751
1947
  await handleConnectionFailure(error, "reload", false);
@@ -1912,18 +2108,79 @@ function ownerStorageKey(workspaceId, sessionId, namespace = "codex-realtime-own
1912
2108
  function readOwnerRecord(storage, key, scope) {
1913
2109
  const raw = storage?.getItem(key);
1914
2110
  if (!raw) return null;
2111
+ if (new TextEncoder().encode(raw).byteLength > OWNER_DELEGATION_REPLAY_MAX_BYTES) {
2112
+ storage?.removeItem(key);
2113
+ return null;
2114
+ }
1915
2115
  try {
1916
2116
  const parsed = recordValue2(JSON.parse(raw));
1917
- 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) {
2117
+ const delegationReplay = readOwnerDelegationReplay(parsed?.delegationReplay);
2118
+ 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) {
1918
2119
  storage?.removeItem(key);
1919
2120
  return null;
1920
2121
  }
1921
- return parsed;
2122
+ return {
2123
+ ...parsed,
2124
+ ...delegationReplay ? { delegationReplay } : {}
2125
+ };
1922
2126
  } catch {
1923
2127
  storage?.removeItem(key);
1924
2128
  return null;
1925
2129
  }
1926
2130
  }
2131
+ function readOwnerDelegationReplay(value) {
2132
+ if (value === void 0) return void 0;
2133
+ const record2 = recordValue2(value);
2134
+ 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) {
2135
+ return null;
2136
+ }
2137
+ const acceptedDelegationItemIds = [];
2138
+ const accepted = /* @__PURE__ */ new Set();
2139
+ for (const candidate of record2.acceptedDelegationItemIds) {
2140
+ if (typeof candidate !== "string" || candidate.length < 1 || candidate.length > 1024) {
2141
+ return null;
2142
+ }
2143
+ if (!accepted.has(candidate)) {
2144
+ accepted.add(candidate);
2145
+ acceptedDelegationItemIds.push(candidate);
2146
+ }
2147
+ }
2148
+ const pendingDelegations = [];
2149
+ const pendingIds = /* @__PURE__ */ new Set();
2150
+ for (const candidate of record2.pendingDelegations) {
2151
+ const parsed = readSessionRealtimeInboundEntry(candidate);
2152
+ if (!parsed || parsed.kind !== "delegation_call" || !parsed.delegationItemId || accepted.has(parsed.delegationItemId) || pendingIds.has(parsed.delegationItemId)) {
2153
+ return null;
2154
+ }
2155
+ pendingIds.add(parsed.delegationItemId);
2156
+ pendingDelegations.push(parsed);
2157
+ }
2158
+ const replay = {
2159
+ version: OWNER_DELEGATION_REPLAY_VERSION,
2160
+ acceptedDelegationItemIds,
2161
+ pendingDelegations
2162
+ };
2163
+ if (new TextEncoder().encode(JSON.stringify(replay)).byteLength > OWNER_DELEGATION_REPLAY_MAX_BYTES) {
2164
+ return null;
2165
+ }
2166
+ return replay;
2167
+ }
2168
+ function readSessionRealtimeInboundEntry(value) {
2169
+ const record2 = recordValue2(value);
2170
+ 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)) {
2171
+ return null;
2172
+ }
2173
+ return record2;
2174
+ }
2175
+ function optionalNullableEnum(value, allowed) {
2176
+ return value === void 0 || value === null || typeof value === "string" && allowed.includes(value);
2177
+ }
2178
+ function optionalNullableBoundedString(value, maxLength) {
2179
+ return value === void 0 || value === null || typeof value === "string" && value.length <= maxLength;
2180
+ }
2181
+ function optionalModelContext(value) {
2182
+ return value === void 0 || typeof value === "string" && value.length >= 1 && value.length <= 32768 && value.trim() === value;
2183
+ }
1927
2184
  function defaultStorage() {
1928
2185
  return typeof sessionStorage === "undefined" ? void 0 : sessionStorage;
1929
2186
  }
@@ -2021,4 +2278,4 @@ export {
2021
2278
  hasStoredSessionRealtimeOwnerProof,
2022
2279
  createCodexRealtimeController
2023
2280
  };
2024
- //# sourceMappingURL=chunk-JDLDDRNE.js.map
2281
+ //# sourceMappingURL=chunk-C2H7HBNP.js.map