@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.
- package/README.md +67 -7
- package/dist/artifacts.js +5 -5
- package/dist/{chunk-FRJFNDIR.js → chunk-4DV37UUA.js} +6 -2
- package/dist/chunk-4DV37UUA.js.map +1 -0
- package/dist/{chunk-KIHGPM7H.js → chunk-A5DC5WEM.js} +288 -45
- package/dist/chunk-A5DC5WEM.js.map +1 -0
- package/dist/{chunk-V5F253OG.js → chunk-GU6JF75T.js} +6 -3
- package/dist/chunk-GU6JF75T.js.map +1 -0
- package/dist/{chunk-MZWTWOX6.js → chunk-ST5DDKJP.js} +327 -1
- package/dist/chunk-ST5DDKJP.js.map +1 -0
- package/dist/{chunk-FHI4DFIG.js → chunk-TYZ4JL4J.js} +2 -2
- package/dist/{chunk-ILQZR5N6.js → chunk-YGH5P47G.js} +693 -34
- package/dist/chunk-YGH5P47G.js.map +1 -0
- package/dist/{chunk-DXDL7EEW.js → chunk-YKZME56C.js} +197 -113
- package/dist/chunk-YKZME56C.js.map +1 -0
- package/dist/client.d.ts +108 -18
- package/dist/codex-realtime-controller.d.ts +5 -0
- package/dist/codex-realtime-controller.js +2 -2
- package/dist/codex-realtime-v3.d.ts +13 -2
- package/dist/core.js +7 -7
- package/dist/desktop.d.ts +8 -0
- package/dist/editable-artifacts.js +4 -4
- package/dist/gateway-realtime-transport.d.ts +1 -0
- package/dist/gateway-realtime-transport.js +5 -3
- package/dist/index.d.ts +6 -2
- package/dist/index.js +68 -34
- package/dist/index.js.map +1 -1
- package/dist/interaction-revision-stream.d.ts +11 -0
- package/dist/interaction.d.ts +604 -5
- package/dist/interaction.js +27 -1
- package/dist/realtime.d.ts +3 -3
- package/dist/realtime.js +11 -7
- package/dist/realtime.js.map +1 -1
- package/dist/types.d.ts +283 -69
- package/dist/workspace-live-stream.d.ts +14 -0
- package/package.json +2 -2
- package/src/client.ts +863 -62
- package/src/codex-realtime-controller.ts +239 -12
- package/src/codex-realtime-lifecycle.ts +1 -0
- package/src/codex-realtime-v3.ts +162 -31
- package/src/desktop.ts +11 -1
- package/src/errors.ts +16 -2
- package/src/gateway-realtime-transport.ts +252 -109
- package/src/index.ts +42 -13
- package/src/interaction-revision-stream.ts +117 -0
- package/src/interaction.ts +1049 -5
- package/src/realtime.ts +14 -4
- package/src/types.ts +353 -72
- package/src/workspace-live-stream.ts +137 -0
- package/dist/chunk-DXDL7EEW.js.map +0 -1
- package/dist/chunk-FRJFNDIR.js.map +0 -1
- package/dist/chunk-ILQZR5N6.js.map +0 -1
- package/dist/chunk-KIHGPM7H.js.map +0 -1
- package/dist/chunk-MZWTWOX6.js.map +0 -1
- package/dist/chunk-V5F253OG.js.map +0 -1
- /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-
|
|
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
|
|
296
|
+
const triggerFatalCode = (code, message) => {
|
|
278
297
|
if (closed || fatal) return;
|
|
279
|
-
fatal = { code
|
|
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
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
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(
|
|
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({
|
|
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
|
-
|
|
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
|
-
|
|
1157
|
-
|
|
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:
|
|
1325
|
+
microphone: microphoneError.code,
|
|
1160
1326
|
status: state.mode?.state === "active" ? "recovering" : "error",
|
|
1161
|
-
diagnostic: diagnostic(kind,
|
|
1162
|
-
error:
|
|
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({
|
|
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({
|
|
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({
|
|
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
|
-
|
|
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
|
|
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-
|
|
2261
|
+
//# sourceMappingURL=chunk-A5DC5WEM.js.map
|