@opengeni/sdk 0.52.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1078 -33
- package/dist/accounts.d.ts +153 -0
- package/dist/accounts.js +307 -0
- package/dist/accounts.js.map +1 -0
- package/dist/adapters/express.d.ts +31 -0
- package/dist/adapters/express.js +87 -0
- package/dist/adapters/express.js.map +1 -0
- package/dist/adapters/hono.d.ts +16 -0
- package/dist/adapters/hono.js +8 -0
- package/dist/adapters/hono.js.map +1 -0
- package/dist/adapters/next.d.ts +29 -0
- package/dist/adapters/next.js +22 -0
- package/dist/adapters/next.js.map +1 -0
- package/dist/allowance-refusal.d.ts +2 -0
- package/dist/allowance-refusal.js +50 -0
- package/dist/allowance-refusal.js.map +1 -0
- package/dist/artifact-catalog.d.ts +31 -0
- package/dist/artifact-client.d.ts +23 -11
- package/dist/artifacts.d.ts +1 -1
- package/dist/artifacts.js +7 -5
- package/dist/automations-client.d.ts +17 -0
- package/dist/automations.d.ts +3 -0
- package/dist/automations.js +84 -0
- package/dist/automations.js.map +1 -0
- package/dist/browser.d.ts +11 -0
- package/dist/browser.js +47 -0
- package/dist/browser.js.map +1 -0
- package/dist/chat/fold.d.ts +75 -0
- package/dist/chat/handler.d.ts +41 -0
- package/dist/chat/http.d.ts +67 -0
- package/dist/chat/ids.d.ts +34 -0
- package/dist/chat/index.d.ts +9 -0
- package/dist/chat/index.js +1694 -0
- package/dist/chat/index.js.map +1 -0
- package/dist/chat/openai.d.ts +30 -0
- package/dist/chat/opengeni.d.ts +128 -0
- package/dist/chat/types.d.ts +207 -0
- package/dist/chat/vercel.d.ts +49 -0
- package/dist/chats.d.ts +8 -0
- package/dist/{chunk-KIHGPM7H.js → chunk-2UXZUCEZ.js} +309 -46
- package/dist/chunk-2UXZUCEZ.js.map +1 -0
- package/dist/chunk-4SMEOV3P.js +246 -0
- package/dist/chunk-4SMEOV3P.js.map +1 -0
- package/dist/{chunk-FHI4DFIG.js → chunk-AH5D5Q5V.js} +31 -35
- package/dist/chunk-AH5D5Q5V.js.map +1 -0
- package/dist/chunk-APXVSSSY.js +301 -0
- package/dist/chunk-APXVSSSY.js.map +1 -0
- package/dist/chunk-DUVIYER4.js +639 -0
- package/dist/chunk-DUVIYER4.js.map +1 -0
- package/dist/{chunk-ILQZR5N6.js → chunk-FG3OO5LM.js} +3484 -750
- package/dist/chunk-FG3OO5LM.js.map +1 -0
- package/dist/chunk-GZYZT22T.js +260 -0
- package/dist/chunk-GZYZT22T.js.map +1 -0
- package/dist/chunk-HMGADJGZ.js +150 -0
- package/dist/chunk-HMGADJGZ.js.map +1 -0
- package/dist/{chunk-DXDL7EEW.js → chunk-KWADQ227.js} +198 -114
- package/dist/chunk-KWADQ227.js.map +1 -0
- package/dist/chunk-LY2K6ELJ.js +126 -0
- package/dist/chunk-LY2K6ELJ.js.map +1 -0
- package/dist/chunk-MOTJYIYL.js +340 -0
- package/dist/chunk-MOTJYIYL.js.map +1 -0
- package/dist/{chunk-MZWTWOX6.js → chunk-NC57YMUO.js} +447 -3
- package/dist/chunk-NC57YMUO.js.map +1 -0
- package/dist/chunk-RWKB6YZG.js +1270 -0
- package/dist/chunk-RWKB6YZG.js.map +1 -0
- package/dist/chunk-U6CV2SXO.js +195 -0
- package/dist/chunk-U6CV2SXO.js.map +1 -0
- package/dist/chunk-UM4ZXXJR.js +9 -0
- package/dist/chunk-UM4ZXXJR.js.map +1 -0
- package/dist/chunk-V6GIY62B.js +229 -0
- package/dist/chunk-V6GIY62B.js.map +1 -0
- package/dist/chunk-WU6GQG25.js +268 -0
- package/dist/chunk-WU6GQG25.js.map +1 -0
- package/dist/{chunk-VWE2QIVO.js → chunk-XNG7YGR3.js} +23 -6
- package/dist/chunk-XNG7YGR3.js.map +1 -0
- package/dist/{chunk-FRJFNDIR.js → chunk-YIKA2QT4.js} +37 -2
- package/dist/chunk-YIKA2QT4.js.map +1 -0
- package/dist/chunk-ZKPY6YAJ.js +135 -0
- package/dist/chunk-ZKPY6YAJ.js.map +1 -0
- package/dist/client.d.ts +843 -107
- package/dist/codex-realtime-controller.d.ts +6 -0
- package/dist/codex-realtime-controller.js +2 -2
- package/dist/codex-realtime-v3.d.ts +13 -2
- package/dist/company-brain.d.ts +22 -0
- package/dist/company-profile.d.ts +14 -1
- package/dist/core.d.ts +9 -3
- package/dist/core.js +28 -9
- package/dist/deprecation.d.ts +47 -0
- package/dist/desktop.d.ts +8 -0
- package/dist/document-authority-client.d.ts +51 -0
- package/dist/document-authority.d.ts +2 -0
- package/dist/document-authority.js +12 -0
- package/dist/document-authority.js.map +1 -0
- package/dist/editable-artifacts/browser-session.d.ts +7 -3
- package/dist/editable-artifacts/controller.d.ts +4 -1
- package/dist/editable-artifacts/errors.d.ts +1 -1
- package/dist/editable-artifacts/http-live-transport.d.ts +6 -2
- package/dist/editable-artifacts/index.d.ts +2 -0
- package/dist/editable-artifacts/open-failure.d.ts +9 -0
- package/dist/editable-artifacts/types.d.ts +6 -3
- package/dist/editable-artifacts/worker/kernel-adapter.d.ts +1 -1
- package/dist/editable-artifacts-worker.js +44 -17
- package/dist/editable-artifacts-worker.js.map +1 -1
- package/dist/editable-artifacts.js +243 -124
- package/dist/editable-artifacts.js.map +1 -1
- package/dist/embedding-client.d.ts +129 -0
- package/dist/errors.d.ts +36 -1
- package/dist/feedback.d.ts +23 -0
- package/dist/gateway-realtime-transport.d.ts +1 -0
- package/dist/gateway-realtime-transport.js +5 -3
- package/dist/github-repositories.d.ts +10 -0
- package/dist/github-repositories.js +36 -0
- package/dist/github-repositories.js.map +1 -0
- package/dist/index.d.ts +61 -12
- package/dist/index.js +277 -126
- package/dist/index.js.map +1 -1
- package/dist/interaction-revision-stream.d.ts +11 -0
- package/dist/interaction.d.ts +687 -5
- package/dist/interaction.js +32 -1
- package/dist/knowledge.d.ts +7 -0
- package/dist/knowledge.js +20 -0
- package/dist/knowledge.js.map +1 -0
- package/dist/message-links.d.ts +68 -0
- package/dist/model-context.d.ts +68 -0
- package/dist/model-display.d.ts +2 -0
- package/dist/model-display.js +15 -0
- package/dist/model-display.js.map +1 -0
- package/dist/model-picker-order.d.ts +1 -0
- package/dist/model-picker-order.js +10 -0
- package/dist/model-picker-order.js.map +1 -0
- package/dist/organization-integration-policy.d.ts +26 -0
- package/dist/organization-integration-policy.js +26 -0
- package/dist/organization-integration-policy.js.map +1 -0
- package/dist/organization-private-session-settings.d.ts +6 -0
- package/dist/organization-private-session-settings.js +22 -0
- package/dist/organization-private-session-settings.js.map +1 -0
- package/dist/organization-user-setup.d.ts +8 -0
- package/dist/organization-user-setup.js +16 -0
- package/dist/organization-user-setup.js.map +1 -0
- package/dist/pr-review-client.d.ts +16 -0
- package/dist/pr-review.d.ts +4 -0
- package/dist/pr-review.js +62 -0
- package/dist/pr-review.js.map +1 -0
- package/dist/preference-registry.d.ts +9 -1
- package/dist/proxy.d.ts +7 -5
- package/dist/realtime.d.ts +6 -4
- package/dist/realtime.js +10 -6
- package/dist/realtime.js.map +1 -1
- package/dist/retained-artifacts.d.ts +5 -1
- package/dist/session-history-import.d.ts +22 -0
- package/dist/session-history-import.js +36 -0
- package/dist/session-history-import.js.map +1 -0
- package/dist/session-list-entries.d.ts +1 -0
- package/dist/session-list-entries.js +7 -0
- package/dist/session-list-entries.js.map +1 -0
- package/dist/session-message-search.d.ts +53 -0
- package/dist/session-proxy-client.d.ts +24 -0
- package/dist/session-proxy.d.ts +245 -0
- package/dist/session-proxy.js +24 -0
- package/dist/session-proxy.js.map +1 -0
- package/dist/session-titles.d.ts +2 -0
- package/dist/site-browser-entry.d.ts +1 -0
- package/dist/site-browser-runtime.gen.d.ts +1 -0
- package/dist/site-document.d.ts +5 -0
- package/dist/site-document.js +20 -0
- package/dist/site-document.js.map +1 -0
- package/dist/site-document.test.d.ts +1 -0
- package/dist/site-http.d.ts +16 -0
- package/dist/site-tool-bridge.d.ts +44 -0
- package/dist/site.d.ts +101 -0
- package/dist/site.js +49 -0
- package/dist/site.js.map +1 -0
- package/dist/skills.d.ts +75 -0
- package/dist/stream.d.ts +2 -0
- package/dist/tenant-workspaces.d.ts +47 -0
- package/dist/tenant-workspaces.js +8 -0
- package/dist/tenant-workspaces.js.map +1 -0
- package/dist/tool-auth.d.ts +87 -0
- package/dist/tool-auth.js +23 -0
- package/dist/tool-auth.js.map +1 -0
- package/dist/tool-display-metadata.d.ts +3 -0
- package/dist/tools-FXBLUWAE.js +12 -0
- package/dist/tools-FXBLUWAE.js.map +1 -0
- package/dist/tools.d.ts +61 -0
- package/dist/types.d.ts +3048 -406
- package/dist/usage-allowances.d.ts +36 -0
- package/dist/usage-allowances.js +80 -0
- package/dist/usage-allowances.js.map +1 -0
- package/dist/workspace-artifacts.d.ts +33 -5
- package/dist/workspace-instruction-policies.d.ts +24 -2
- package/dist/workspace-integrations.d.ts +74 -0
- package/dist/workspace-integrations.js +65 -0
- package/dist/workspace-integrations.js.map +1 -0
- package/dist/workspace-learning.d.ts +124 -0
- package/dist/workspace-live-stream.d.ts +14 -0
- package/dist/workspace-state.d.ts +8 -71
- package/package.json +108 -3
- package/src/accounts.ts +443 -0
- package/src/adapters/express.ts +136 -0
- package/src/adapters/hono.ts +18 -0
- package/src/adapters/next.ts +42 -0
- package/src/allowance-refusal.ts +5 -0
- package/src/artifact-catalog.ts +41 -0
- package/src/artifact-client.ts +43 -52
- package/src/artifacts.ts +7 -1
- package/src/automations-client.ts +124 -0
- package/src/automations.ts +15 -0
- package/src/browser.ts +54 -0
- package/src/chat/fold.ts +431 -0
- package/src/chat/handler.ts +240 -0
- package/src/chat/http.ts +257 -0
- package/src/chat/ids.ts +85 -0
- package/src/chat/index.ts +87 -0
- package/src/chat/openai.ts +439 -0
- package/src/chat/opengeni.ts +722 -0
- package/src/chat/types.ts +219 -0
- package/src/chat/vercel.ts +204 -0
- package/src/chats.ts +16 -0
- package/src/client.ts +5162 -792
- package/src/codex-realtime-controller.ts +260 -12
- package/src/codex-realtime-lifecycle.ts +1 -0
- package/src/codex-realtime-v3.ts +162 -31
- package/src/codex-realtime.ts +1 -1
- package/src/company-brain.ts +59 -0
- package/src/company-profile.ts +17 -1
- package/src/core.ts +23 -1
- package/src/deprecation.ts +149 -0
- package/src/desktop.ts +11 -1
- package/src/document-authority-client.ts +219 -0
- package/src/document-authority.ts +17 -0
- package/src/editable-artifacts/browser-session.ts +36 -22
- package/src/editable-artifacts/controller.ts +102 -47
- package/src/editable-artifacts/errors.ts +2 -0
- package/src/editable-artifacts/http-live-transport.ts +62 -37
- package/src/editable-artifacts/index.ts +6 -0
- package/src/editable-artifacts/open-failure.ts +79 -0
- package/src/editable-artifacts/storage.ts +31 -40
- package/src/editable-artifacts/types.ts +6 -3
- package/src/editable-artifacts/worker/kernel-adapter.ts +23 -7
- package/src/editable-artifacts/worker/runtime.ts +26 -13
- package/src/editable-artifacts/worker/wire-codec.ts +23 -5
- package/src/embedding-client.ts +519 -0
- package/src/errors.ts +185 -4
- package/src/feedback.ts +20 -0
- package/src/gateway-realtime-transport.ts +253 -110
- package/src/github-repositories.ts +60 -0
- package/src/index.ts +603 -54
- package/src/interaction-revision-stream.ts +117 -0
- package/src/interaction.ts +1367 -51
- package/src/knowledge.ts +72 -0
- package/src/message-links.ts +178 -0
- package/src/model-context.ts +112 -0
- package/src/model-display.ts +10 -0
- package/src/model-picker-order.ts +6 -0
- package/src/organization-integration-policy.ts +54 -0
- package/src/organization-private-session-settings.ts +33 -0
- package/src/organization-user-setup.ts +31 -0
- package/src/pr-review-client.ts +92 -0
- package/src/pr-review.ts +17 -0
- package/src/preference-registry.ts +11 -0
- package/src/proxy.ts +17 -6
- package/src/realtime.ts +15 -4
- package/src/retained-artifacts.ts +101 -0
- package/src/session-history-import.ts +84 -0
- package/src/session-list-entries.ts +1 -0
- package/src/session-message-search.ts +47 -0
- package/src/session-proxy-client.ts +64 -0
- package/src/session-proxy.ts +1473 -0
- package/src/session-titles.ts +10 -0
- package/src/site-browser-entry.ts +6 -0
- package/src/site-browser-runtime.gen.ts +2 -0
- package/src/site-document.test.ts +64 -0
- package/src/site-document.ts +18 -0
- package/src/site-http.ts +162 -0
- package/src/site-tool-bridge.ts +146 -0
- package/src/site.ts +585 -0
- package/src/skills.ts +69 -0
- package/src/sse.ts +8 -2
- package/src/stream.ts +38 -4
- package/src/tenant-workspaces.ts +148 -0
- package/src/tool-auth.ts +301 -0
- package/src/tool-display-metadata.ts +19 -0
- package/src/tools.ts +396 -0
- package/src/types.ts +3607 -493
- package/src/usage-allowances.ts +189 -0
- package/src/workspace-artifacts.ts +40 -6
- package/src/workspace-instruction-policies.ts +26 -1
- package/src/workspace-integrations.ts +402 -0
- package/src/workspace-learning.ts +138 -0
- package/src/workspace-live-stream.ts +137 -0
- package/src/workspace-state.ts +8 -82
- package/dist/chunk-DXDL7EEW.js.map +0 -1
- package/dist/chunk-FHI4DFIG.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 +0 -116
- package/dist/chunk-V5F253OG.js.map +0 -1
- package/dist/chunk-VWE2QIVO.js.map +0 -1
|
@@ -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,
|
|
@@ -49,7 +50,29 @@ export const CODEX_REALTIME_NEGOTIATION_TIMEOUT_MS = 20_000;
|
|
|
49
50
|
// OpenGeni policy: rotate conservatively without asserting an upstream lifetime.
|
|
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;
|
|
53
|
+
const MAX_BROWSER_TIMEOUT_MS = 2_147_483_647;
|
|
52
54
|
const OWNER_RECORD_VERSION = 1;
|
|
55
|
+
const OWNER_DELEGATION_REPLAY_VERSION = 1;
|
|
56
|
+
const OWNER_DELEGATION_REPLAY_MAX_CALLS = 4_096;
|
|
57
|
+
const OWNER_DELEGATION_REPLAY_MAX_BYTES = 4 * 1024 * 1024;
|
|
58
|
+
const SESSION_REALTIME_INBOUND_ENTRY_KEYS = new Set([
|
|
59
|
+
"operationId",
|
|
60
|
+
"kind",
|
|
61
|
+
"role",
|
|
62
|
+
"providerEventId",
|
|
63
|
+
"delegationItemId",
|
|
64
|
+
"text",
|
|
65
|
+
"payload",
|
|
66
|
+
"modelContext",
|
|
67
|
+
]);
|
|
68
|
+
const SESSION_REALTIME_INBOUND_KINDS = new Set([
|
|
69
|
+
"user_transcript",
|
|
70
|
+
"assistant_transcript",
|
|
71
|
+
"delegation_call",
|
|
72
|
+
"interruption",
|
|
73
|
+
"error",
|
|
74
|
+
]);
|
|
75
|
+
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
76
|
|
|
54
77
|
export type CodexRealtimeControllerStatus =
|
|
55
78
|
| "idle"
|
|
@@ -123,6 +146,12 @@ export type CodexRealtimeControllerClient = {
|
|
|
123
146
|
request: GatewayRealtimeConnectRequest,
|
|
124
147
|
options?: { signal?: AbortSignal | undefined },
|
|
125
148
|
): Promise<GatewayRealtimeConnectResponse>;
|
|
149
|
+
negotiateXaiSubscriptionRealtime?(
|
|
150
|
+
workspaceId: string,
|
|
151
|
+
sessionId: string,
|
|
152
|
+
request: GatewayRealtimeConnectRequest,
|
|
153
|
+
options?: { signal?: AbortSignal | undefined },
|
|
154
|
+
): Promise<GatewayRealtimeConnectResponse>;
|
|
126
155
|
activateCodexRealtimeConnection(
|
|
127
156
|
workspaceId: string,
|
|
128
157
|
sessionId: string,
|
|
@@ -149,7 +178,9 @@ export type CodexRealtimeOwnerStorage = Pick<Storage, "getItem" | "setItem" | "r
|
|
|
149
178
|
|
|
150
179
|
/** Canonical browser-owner storage namespace for a public realtime model. */
|
|
151
180
|
export function sessionRealtimeOwnerStorageNamespace(model: SessionRealtimeModel): string {
|
|
152
|
-
|
|
181
|
+
if (model === "gpt-live-1-boulder-alpha") return "codex-realtime-owner";
|
|
182
|
+
if (model === "supergrok/grok-voice-think-fast-2.0") return "xai-realtime-owner";
|
|
183
|
+
return "gateway-realtime-owner";
|
|
153
184
|
}
|
|
154
185
|
|
|
155
186
|
/** Canonical browser-owner storage key shared by the SDK controller and React facade. */
|
|
@@ -194,6 +225,7 @@ export type CreateCodexRealtimeControllerOptions = {
|
|
|
194
225
|
createPeerConnection?: (() => RTCPeerConnection) | undefined;
|
|
195
226
|
getUserMedia?: ((constraints: MediaStreamConstraints) => Promise<MediaStream>) | undefined;
|
|
196
227
|
randomUUID?: (() => string) | undefined;
|
|
228
|
+
now?: (() => Date) | undefined;
|
|
197
229
|
setInterval?: ((callback: () => void, delayMs: number) => unknown) | undefined;
|
|
198
230
|
clearInterval?: ((handle: unknown) => void) | undefined;
|
|
199
231
|
setTimeout?: ((callback: () => void, delayMs: number) => unknown) | undefined;
|
|
@@ -205,6 +237,8 @@ export type CreateCodexRealtimeControllerOptions = {
|
|
|
205
237
|
model?: SessionRealtimeModel | undefined;
|
|
206
238
|
ownerStorageNamespace?: string | undefined;
|
|
207
239
|
startTransport?: RealtimeControllerTransportStarter | undefined;
|
|
240
|
+
/** Model-visible application context captured with each durable realtime message. */
|
|
241
|
+
getModelContext?: (() => string | undefined) | undefined;
|
|
208
242
|
};
|
|
209
243
|
|
|
210
244
|
export type RealtimeControllerTransportStarter = (input: {
|
|
@@ -250,6 +284,13 @@ type OwnerRecord = {
|
|
|
250
284
|
operationId: string;
|
|
251
285
|
browserInstanceId: string;
|
|
252
286
|
ownerKey: string;
|
|
287
|
+
delegationReplay?: OwnerDelegationReplay | undefined;
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
type OwnerDelegationReplay = {
|
|
291
|
+
version: typeof OWNER_DELEGATION_REPLAY_VERSION;
|
|
292
|
+
acceptedDelegationItemIds: string[];
|
|
293
|
+
pendingDelegations: SessionRealtimeInboundEntry[];
|
|
253
294
|
};
|
|
254
295
|
|
|
255
296
|
type ConnectionRuntime = {
|
|
@@ -277,6 +318,7 @@ export function createCodexRealtimeController(
|
|
|
277
318
|
);
|
|
278
319
|
const model = options.model ?? "gpt-live-1-boulder-alpha";
|
|
279
320
|
const randomUUID = options.randomUUID ?? defaultRandomUUID;
|
|
321
|
+
const now = options.now ?? (() => new Date());
|
|
280
322
|
const scheduleInterval =
|
|
281
323
|
options.setInterval ?? ((callback, delay) => globalThis.setInterval(callback, delay));
|
|
282
324
|
const unscheduleInterval =
|
|
@@ -323,6 +365,7 @@ export function createCodexRealtimeController(
|
|
|
323
365
|
let rotationTimer: unknown = null;
|
|
324
366
|
let reconnectTimer: unknown = null;
|
|
325
367
|
let negotiationTimer: unknown = null;
|
|
368
|
+
let lostOwnerExpiryTimer: unknown = null;
|
|
326
369
|
let closed = false;
|
|
327
370
|
let stopping = false;
|
|
328
371
|
let generation = 0;
|
|
@@ -330,6 +373,59 @@ export function createCodexRealtimeController(
|
|
|
330
373
|
let recoveryTerminal = false;
|
|
331
374
|
let mutationTail = Promise.resolve();
|
|
332
375
|
let connectionTask: Promise<void> | null = null;
|
|
376
|
+
const acceptedDelegationItemIds = new Set(
|
|
377
|
+
owner?.delegationReplay?.acceptedDelegationItemIds ?? [],
|
|
378
|
+
);
|
|
379
|
+
const pendingDelegations = new Map(
|
|
380
|
+
(owner?.delegationReplay?.pendingDelegations ?? []).flatMap((entry) =>
|
|
381
|
+
entry.delegationItemId ? [[entry.delegationItemId, entry] as const] : [],
|
|
382
|
+
),
|
|
383
|
+
);
|
|
384
|
+
|
|
385
|
+
const invalidateStoredOwner = (): void => {
|
|
386
|
+
try {
|
|
387
|
+
storage?.removeItem(storageKey);
|
|
388
|
+
} catch {
|
|
389
|
+
// Best effort only. The bridge still fails closed and retains the exact
|
|
390
|
+
// in-memory snapshot for this controller's bounded recovery attempts.
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
const persistDelegationReplay = (input: {
|
|
395
|
+
acceptedDelegationItemIds: ReadonlySet<string>;
|
|
396
|
+
pendingDelegations: ReadonlyMap<string, SessionRealtimeInboundEntry>;
|
|
397
|
+
}): void => {
|
|
398
|
+
if (!owner || !storage) return;
|
|
399
|
+
const delegationReplay: OwnerDelegationReplay = {
|
|
400
|
+
version: OWNER_DELEGATION_REPLAY_VERSION,
|
|
401
|
+
acceptedDelegationItemIds: [...input.acceptedDelegationItemIds],
|
|
402
|
+
pendingDelegations: [...input.pendingDelegations.values()],
|
|
403
|
+
};
|
|
404
|
+
if (
|
|
405
|
+
delegationReplay.pendingDelegations.length > CODEX_REALTIME_V3_PENDING_MAX_ENTRIES ||
|
|
406
|
+
delegationReplay.acceptedDelegationItemIds.length +
|
|
407
|
+
delegationReplay.pendingDelegations.length >
|
|
408
|
+
OWNER_DELEGATION_REPLAY_MAX_CALLS
|
|
409
|
+
) {
|
|
410
|
+
invalidateStoredOwner();
|
|
411
|
+
throw new Error("Realtime delegation replay journal exceeded its call limit");
|
|
412
|
+
}
|
|
413
|
+
const next: OwnerRecord = { ...owner, delegationReplay };
|
|
414
|
+
const serialized = JSON.stringify(next);
|
|
415
|
+
if (new TextEncoder().encode(serialized).byteLength > OWNER_DELEGATION_REPLAY_MAX_BYTES) {
|
|
416
|
+
invalidateStoredOwner();
|
|
417
|
+
throw new Error("Realtime delegation replay journal exceeded its byte limit");
|
|
418
|
+
}
|
|
419
|
+
try {
|
|
420
|
+
storage.setItem(storageKey, serialized);
|
|
421
|
+
} catch (error) {
|
|
422
|
+
// Never leave older ownership proof reloadable without the delegation
|
|
423
|
+
// snapshot that the active bridge just froze.
|
|
424
|
+
invalidateStoredOwner();
|
|
425
|
+
throw error;
|
|
426
|
+
}
|
|
427
|
+
owner = next;
|
|
428
|
+
};
|
|
333
429
|
|
|
334
430
|
const publish = (patch: Partial<CodexRealtimeControllerSnapshot>): void => {
|
|
335
431
|
state = { ...state, ...patch };
|
|
@@ -364,11 +460,13 @@ export function createCodexRealtimeController(
|
|
|
364
460
|
if (rotationTimer !== null) unscheduleTimeout(rotationTimer);
|
|
365
461
|
if (reconnectTimer !== null) unscheduleTimeout(reconnectTimer);
|
|
366
462
|
if (negotiationTimer !== null) unscheduleTimeout(negotiationTimer);
|
|
463
|
+
if (lostOwnerExpiryTimer !== null) unscheduleTimeout(lostOwnerExpiryTimer);
|
|
367
464
|
heartbeatTimer = null;
|
|
368
465
|
syncTimer = null;
|
|
369
466
|
rotationTimer = null;
|
|
370
467
|
reconnectTimer = null;
|
|
371
468
|
negotiationTimer = null;
|
|
469
|
+
lostOwnerExpiryTimer = null;
|
|
372
470
|
};
|
|
373
471
|
|
|
374
472
|
const stopNegotiationTimers = (): void => {
|
|
@@ -414,6 +512,8 @@ export function createCodexRealtimeController(
|
|
|
414
512
|
const clearOwner = (): void => {
|
|
415
513
|
owner = null;
|
|
416
514
|
storage?.removeItem(storageKey);
|
|
515
|
+
acceptedDelegationItemIds.clear();
|
|
516
|
+
pendingDelegations.clear();
|
|
417
517
|
};
|
|
418
518
|
|
|
419
519
|
const transitionEnded = (message = "Realtime mode ended"): void => {
|
|
@@ -454,16 +554,26 @@ export function createCodexRealtimeController(
|
|
|
454
554
|
publish({ microphone: "active" });
|
|
455
555
|
return acquired;
|
|
456
556
|
} catch (error) {
|
|
457
|
-
|
|
458
|
-
|
|
557
|
+
const microphoneError =
|
|
558
|
+
error instanceof CodexRealtimeMicrophoneError
|
|
559
|
+
? error
|
|
560
|
+
: signal.aborted && state.microphone === "acquiring"
|
|
561
|
+
? new CodexRealtimeMicrophoneError(
|
|
562
|
+
"acquisition_failed",
|
|
563
|
+
"Microphone did not become available before voice startup timed out",
|
|
564
|
+
)
|
|
565
|
+
: null;
|
|
566
|
+
if (microphoneError) {
|
|
567
|
+
const kind =
|
|
568
|
+
microphoneError.code === "permission_denied" ? "permission_failure" : "device_failure";
|
|
459
569
|
publish({
|
|
460
|
-
microphone:
|
|
570
|
+
microphone: microphoneError.code,
|
|
461
571
|
status: state.mode?.state === "active" ? "recovering" : "error",
|
|
462
|
-
diagnostic: diagnostic(kind,
|
|
463
|
-
error:
|
|
572
|
+
diagnostic: diagnostic(kind, microphoneError.message, true),
|
|
573
|
+
error: microphoneError.message,
|
|
464
574
|
});
|
|
465
575
|
}
|
|
466
|
-
throw error;
|
|
576
|
+
throw microphoneError ?? error;
|
|
467
577
|
}
|
|
468
578
|
};
|
|
469
579
|
|
|
@@ -506,7 +616,10 @@ export function createCodexRealtimeController(
|
|
|
506
616
|
});
|
|
507
617
|
return;
|
|
508
618
|
}
|
|
509
|
-
publish({
|
|
619
|
+
publish({
|
|
620
|
+
audibleOutput: next,
|
|
621
|
+
...(next === "audible" ? { error: null } : {}),
|
|
622
|
+
});
|
|
510
623
|
};
|
|
511
624
|
|
|
512
625
|
const startActiveIntervals = (): void => {
|
|
@@ -893,6 +1006,10 @@ export function createCodexRealtimeController(
|
|
|
893
1006
|
sync: async (request) =>
|
|
894
1007
|
await syncForGeneration(targetGeneration, activated.mode.id, request),
|
|
895
1008
|
randomUUID,
|
|
1009
|
+
...(options.getModelContext ? { getModelContext: options.getModelContext } : {}),
|
|
1010
|
+
acceptedDelegationItemIds,
|
|
1011
|
+
pendingDelegations,
|
|
1012
|
+
onDelegationReplayStateChange: persistDelegationReplay,
|
|
896
1013
|
onSnapshot: (nextBridge) => {
|
|
897
1014
|
if (active?.generation === targetGeneration) publish({ bridge: nextBridge });
|
|
898
1015
|
},
|
|
@@ -1079,7 +1196,12 @@ export function createCodexRealtimeController(
|
|
|
1079
1196
|
await handleConnectionFailure(error, "reconnect", false);
|
|
1080
1197
|
} else {
|
|
1081
1198
|
clearOwner();
|
|
1082
|
-
publish({
|
|
1199
|
+
publish({
|
|
1200
|
+
status: "error",
|
|
1201
|
+
realtimeId: null,
|
|
1202
|
+
mode: null,
|
|
1203
|
+
error: safeError(error),
|
|
1204
|
+
});
|
|
1083
1205
|
}
|
|
1084
1206
|
throw error;
|
|
1085
1207
|
}
|
|
@@ -1139,6 +1261,12 @@ export function createCodexRealtimeController(
|
|
|
1139
1261
|
if (!record || record.operationId !== lifecycle.operationId) {
|
|
1140
1262
|
closeBrowserResources();
|
|
1141
1263
|
owner = null;
|
|
1264
|
+
const leaseExpiresAt = Date.parse(lifecycle.leaseExpiresAt);
|
|
1265
|
+
const remainingLeaseMs = leaseExpiresAt - now().getTime();
|
|
1266
|
+
if (Number.isFinite(remainingLeaseMs) && remainingLeaseMs <= 0) {
|
|
1267
|
+
transitionEnded("Realtime lease expired");
|
|
1268
|
+
return;
|
|
1269
|
+
}
|
|
1142
1270
|
const message =
|
|
1143
1271
|
"Realtime is active in another browser owner. It can resume after that owner stops or its lease expires.";
|
|
1144
1272
|
publish({
|
|
@@ -1149,13 +1277,26 @@ export function createCodexRealtimeController(
|
|
|
1149
1277
|
diagnostic: diagnostic("lost_owner", message, false),
|
|
1150
1278
|
error: message,
|
|
1151
1279
|
});
|
|
1280
|
+
if (Number.isFinite(remainingLeaseMs) && remainingLeaseMs <= MAX_BROWSER_TIMEOUT_MS) {
|
|
1281
|
+
const observedRealtimeId = lifecycle.realtimeId;
|
|
1282
|
+
lostOwnerExpiryTimer = scheduleTimeout(() => {
|
|
1283
|
+
lostOwnerExpiryTimer = null;
|
|
1284
|
+
if (state.status === "lost_owner" && state.realtimeId === observedRealtimeId) {
|
|
1285
|
+
transitionEnded("Realtime lease expired");
|
|
1286
|
+
}
|
|
1287
|
+
}, remainingLeaseMs);
|
|
1288
|
+
}
|
|
1152
1289
|
return;
|
|
1153
1290
|
}
|
|
1154
1291
|
if (connectionTask || state.status === "starting") return;
|
|
1155
1292
|
closed = false;
|
|
1156
1293
|
stopping = false;
|
|
1157
1294
|
owner = record;
|
|
1158
|
-
publish({
|
|
1295
|
+
publish({
|
|
1296
|
+
status: "recovering",
|
|
1297
|
+
realtimeId: lifecycle.realtimeId,
|
|
1298
|
+
error: null,
|
|
1299
|
+
});
|
|
1159
1300
|
connectionTask = begin(record, true)
|
|
1160
1301
|
.then(() => undefined)
|
|
1161
1302
|
.catch(async (error) => {
|
|
@@ -1359,8 +1500,13 @@ function readOwnerRecord(
|
|
|
1359
1500
|
): OwnerRecord | null {
|
|
1360
1501
|
const raw = storage?.getItem(key);
|
|
1361
1502
|
if (!raw) return null;
|
|
1503
|
+
if (new TextEncoder().encode(raw).byteLength > OWNER_DELEGATION_REPLAY_MAX_BYTES) {
|
|
1504
|
+
storage?.removeItem(key);
|
|
1505
|
+
return null;
|
|
1506
|
+
}
|
|
1362
1507
|
try {
|
|
1363
1508
|
const parsed = recordValue(JSON.parse(raw));
|
|
1509
|
+
const delegationReplay = readOwnerDelegationReplay(parsed?.delegationReplay);
|
|
1364
1510
|
if (
|
|
1365
1511
|
parsed?.version !== OWNER_RECORD_VERSION ||
|
|
1366
1512
|
parsed.workspaceId !== scope.workspaceId ||
|
|
@@ -1368,18 +1514,120 @@ function readOwnerRecord(
|
|
|
1368
1514
|
!stringValue(parsed.operationId) ||
|
|
1369
1515
|
!stringValue(parsed.browserInstanceId) ||
|
|
1370
1516
|
!stringValue(parsed.ownerKey) ||
|
|
1371
|
-
String(parsed.ownerKey).length < 32
|
|
1517
|
+
String(parsed.ownerKey).length < 32 ||
|
|
1518
|
+
delegationReplay === null
|
|
1372
1519
|
) {
|
|
1373
1520
|
storage?.removeItem(key);
|
|
1374
1521
|
return null;
|
|
1375
1522
|
}
|
|
1376
|
-
return
|
|
1523
|
+
return {
|
|
1524
|
+
...(parsed as Omit<OwnerRecord, "delegationReplay">),
|
|
1525
|
+
...(delegationReplay ? { delegationReplay } : {}),
|
|
1526
|
+
};
|
|
1377
1527
|
} catch {
|
|
1378
1528
|
storage?.removeItem(key);
|
|
1379
1529
|
return null;
|
|
1380
1530
|
}
|
|
1381
1531
|
}
|
|
1382
1532
|
|
|
1533
|
+
function readOwnerDelegationReplay(value: unknown): OwnerDelegationReplay | undefined | null {
|
|
1534
|
+
if (value === undefined) return undefined;
|
|
1535
|
+
const record = recordValue(value);
|
|
1536
|
+
if (
|
|
1537
|
+
record?.version !== OWNER_DELEGATION_REPLAY_VERSION ||
|
|
1538
|
+
!Array.isArray(record.acceptedDelegationItemIds) ||
|
|
1539
|
+
!Array.isArray(record.pendingDelegations) ||
|
|
1540
|
+
record.acceptedDelegationItemIds.length + record.pendingDelegations.length >
|
|
1541
|
+
OWNER_DELEGATION_REPLAY_MAX_CALLS ||
|
|
1542
|
+
record.pendingDelegations.length > CODEX_REALTIME_V3_PENDING_MAX_ENTRIES
|
|
1543
|
+
) {
|
|
1544
|
+
return null;
|
|
1545
|
+
}
|
|
1546
|
+
const acceptedDelegationItemIds: string[] = [];
|
|
1547
|
+
const accepted = new Set<string>();
|
|
1548
|
+
for (const candidate of record.acceptedDelegationItemIds) {
|
|
1549
|
+
if (typeof candidate !== "string" || candidate.length < 1 || candidate.length > 1_024) {
|
|
1550
|
+
return null;
|
|
1551
|
+
}
|
|
1552
|
+
if (!accepted.has(candidate)) {
|
|
1553
|
+
accepted.add(candidate);
|
|
1554
|
+
acceptedDelegationItemIds.push(candidate);
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
const pendingDelegations: SessionRealtimeInboundEntry[] = [];
|
|
1558
|
+
const pendingIds = new Set<string>();
|
|
1559
|
+
for (const candidate of record.pendingDelegations) {
|
|
1560
|
+
const parsed = readSessionRealtimeInboundEntry(candidate);
|
|
1561
|
+
if (
|
|
1562
|
+
!parsed ||
|
|
1563
|
+
parsed.kind !== "delegation_call" ||
|
|
1564
|
+
!parsed.delegationItemId ||
|
|
1565
|
+
accepted.has(parsed.delegationItemId) ||
|
|
1566
|
+
pendingIds.has(parsed.delegationItemId)
|
|
1567
|
+
) {
|
|
1568
|
+
return null;
|
|
1569
|
+
}
|
|
1570
|
+
pendingIds.add(parsed.delegationItemId);
|
|
1571
|
+
pendingDelegations.push(parsed);
|
|
1572
|
+
}
|
|
1573
|
+
const replay: OwnerDelegationReplay = {
|
|
1574
|
+
version: OWNER_DELEGATION_REPLAY_VERSION,
|
|
1575
|
+
acceptedDelegationItemIds,
|
|
1576
|
+
pendingDelegations,
|
|
1577
|
+
};
|
|
1578
|
+
if (
|
|
1579
|
+
new TextEncoder().encode(JSON.stringify(replay)).byteLength > OWNER_DELEGATION_REPLAY_MAX_BYTES
|
|
1580
|
+
) {
|
|
1581
|
+
return null;
|
|
1582
|
+
}
|
|
1583
|
+
return replay;
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
function readSessionRealtimeInboundEntry(value: unknown): SessionRealtimeInboundEntry | null {
|
|
1587
|
+
const record = recordValue(value);
|
|
1588
|
+
if (
|
|
1589
|
+
!record ||
|
|
1590
|
+
Object.keys(record).some((key) => !SESSION_REALTIME_INBOUND_ENTRY_KEYS.has(key)) ||
|
|
1591
|
+
typeof record.operationId !== "string" ||
|
|
1592
|
+
!UUID_PATTERN.test(record.operationId) ||
|
|
1593
|
+
typeof record.kind !== "string" ||
|
|
1594
|
+
!SESSION_REALTIME_INBOUND_KINDS.has(record.kind) ||
|
|
1595
|
+
!optionalNullableEnum(record.role, ["user", "assistant"]) ||
|
|
1596
|
+
!optionalNullableBoundedString(record.providerEventId, 1_024) ||
|
|
1597
|
+
!optionalNullableBoundedString(record.delegationItemId, 1_024) ||
|
|
1598
|
+
!optionalNullableBoundedString(record.text, 131_072) ||
|
|
1599
|
+
(record.payload !== undefined && recordValue(record.payload) === null) ||
|
|
1600
|
+
!optionalModelContext(record.modelContext)
|
|
1601
|
+
) {
|
|
1602
|
+
return null;
|
|
1603
|
+
}
|
|
1604
|
+
return record as SessionRealtimeInboundEntry;
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
function optionalNullableEnum(value: unknown, allowed: readonly string[]): boolean {
|
|
1608
|
+
return (
|
|
1609
|
+
value === undefined || value === null || (typeof value === "string" && allowed.includes(value))
|
|
1610
|
+
);
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
function optionalNullableBoundedString(value: unknown, maxLength: number): boolean {
|
|
1614
|
+
return (
|
|
1615
|
+
value === undefined ||
|
|
1616
|
+
value === null ||
|
|
1617
|
+
(typeof value === "string" && value.length <= maxLength)
|
|
1618
|
+
);
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
function optionalModelContext(value: unknown): boolean {
|
|
1622
|
+
return (
|
|
1623
|
+
value === undefined ||
|
|
1624
|
+
(typeof value === "string" &&
|
|
1625
|
+
value.length >= 1 &&
|
|
1626
|
+
value.length <= 32_768 &&
|
|
1627
|
+
value.trim() === value)
|
|
1628
|
+
);
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1383
1631
|
function defaultStorage(): CodexRealtimeOwnerStorage | undefined {
|
|
1384
1632
|
return typeof sessionStorage === "undefined" ? undefined : sessionStorage;
|
|
1385
1633
|
}
|
|
@@ -66,6 +66,7 @@ export function projectSessionRealtimeLifecycle(
|
|
|
66
66
|
|
|
67
67
|
function realtimeModel(value: unknown): SessionRealtimeModel | null {
|
|
68
68
|
return value === "gpt-live-1-boulder-alpha" ||
|
|
69
|
+
value === "supergrok/grok-voice-think-fast-2.0" ||
|
|
69
70
|
value === "opengeni-gateway/openai/gpt-realtime-2.1" ||
|
|
70
71
|
value === "opengeni-gateway/openai/gpt-realtime-mini" ||
|
|
71
72
|
value === "opengeni-gateway/xai/grok-voice-think-fast-2.0" ||
|