@opengeni/react 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 +51 -1
- package/dist/artifacts.d.ts +1 -1
- package/dist/artifacts.js +43 -14
- package/dist/artifacts.js.map +1 -1
- package/dist/{chunk-ROIRTM37.js → chunk-5UQPNLIO.js} +6 -6
- package/dist/{chunk-JR3QFY6B.js → chunk-6KLX2RH5.js} +49 -2
- package/dist/chunk-6KLX2RH5.js.map +1 -0
- package/dist/{chunk-FWS3KC3Z.js → chunk-B6WPZSTT.js} +104 -104
- package/dist/{chunk-FWS3KC3Z.js.map → chunk-B6WPZSTT.js.map} +1 -1
- package/dist/{chunk-HDBG7XGO.js → chunk-C5ZPSSS5.js} +50 -1
- package/dist/chunk-C5ZPSSS5.js.map +1 -0
- package/dist/{chunk-X4S56Y2H.js → chunk-HA46CYQK.js} +135 -11
- package/dist/chunk-HA46CYQK.js.map +1 -0
- package/dist/{chunk-724BW4TW.js → chunk-IGC6A2ZI.js} +2 -2
- package/dist/chunk-LLOLUHVG.js +5937 -0
- package/dist/chunk-LLOLUHVG.js.map +1 -0
- package/dist/{chunk-WYA65Y3F.js → chunk-MKPIAGVL.js} +13 -3
- package/dist/chunk-MKPIAGVL.js.map +1 -0
- package/dist/chunk-R3AZOAB5.js +933 -0
- package/dist/chunk-R3AZOAB5.js.map +1 -0
- package/dist/{chunk-23EJ676W.js → chunk-XBZWOM2K.js} +9 -4
- package/dist/chunk-XBZWOM2K.js.map +1 -0
- package/dist/{chunk-JAGDUCZQ.js → chunk-Y7OEDUJ5.js} +17 -13
- package/dist/chunk-Y7OEDUJ5.js.map +1 -0
- package/dist/client.d.ts +6 -4
- package/dist/components/artifacts/index.d.ts +1 -0
- package/dist/components/artifacts/published-html-artifact-frame.d.ts +14 -0
- package/dist/components/browser-input.d.ts +7 -0
- package/dist/components/browser-viewer.d.ts +5 -4
- package/dist/components/computer-viewer.d.ts +2 -1
- package/dist/components/desktop-viewer.d.ts +26 -2
- package/dist/components/interaction-intervention-banner.d.ts +11 -0
- package/dist/components/sandbox-terminal.d.ts +4 -1
- package/dist/components/sandbox-workspace.d.ts +3 -0
- package/dist/composer.js +6 -6
- package/dist/hooks/use-auth-runs.d.ts +32 -0
- package/dist/hooks/use-browser-downloads.d.ts +25 -0
- package/dist/hooks/use-browser-identities.d.ts +5 -1
- package/dist/hooks/use-browser-session.d.ts +2 -1
- package/dist/hooks/use-browser-sessions.d.ts +1 -1
- package/dist/hooks/use-channels.d.ts +26 -0
- package/dist/hooks/use-computer-frame-stream.d.ts +1 -1
- package/dist/hooks/use-computer-session.d.ts +2 -1
- package/dist/hooks/use-computer-sessions.d.ts +1 -1
- package/dist/hooks/use-desktop-stream.d.ts +4 -0
- package/dist/hooks/use-interaction-interventions.d.ts +27 -0
- package/dist/hooks/use-interaction-invalidation.d.ts +19 -0
- package/dist/hooks/use-network-routes.d.ts +25 -0
- package/dist/hooks/use-site-auth-connections.d.ts +25 -0
- package/dist/hooks/use-supergrok-accounts.d.ts +26 -0
- package/dist/hooks/use-terminal-stream.d.ts +3 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1220 -1545
- package/dist/index.js.map +1 -1
- package/dist/interaction.d.ts +13 -3
- package/dist/interaction.js +520 -6
- package/dist/interaction.js.map +1 -1
- package/dist/interactive-workbench-viewers-TOHBXJEE.js +15 -0
- package/dist/lib/host-platform.d.ts +5 -0
- package/dist/lib/relay-wire.d.ts +20 -1
- package/dist/machines.js +3 -3
- package/dist/model-policy.d.ts +1 -1
- package/dist/model-policy.js +1 -1
- package/dist/provider.d.ts +3 -2
- package/dist/realtime/realtime-control.d.ts +6 -2
- package/dist/realtime.js +138 -24
- package/dist/realtime.js.map +1 -1
- package/dist/session-context.d.ts +10 -2
- package/dist/session-ui.js +3 -3
- package/dist/session.js +11 -11
- package/dist/timeline/types.d.ts +5 -0
- package/package.json +2 -2
- package/src/artifacts.ts +3 -0
- package/src/client.ts +73 -3
- package/src/components/artifacts/index.ts +5 -0
- package/src/components/artifacts/published-html-artifact-frame.tsx +38 -0
- package/src/components/browser-input.ts +65 -0
- package/src/components/browser-viewer.tsx +1287 -177
- package/src/components/computer-viewer.tsx +611 -114
- package/src/components/desktop-viewer.tsx +114 -1
- package/src/components/interaction-intervention-banner.tsx +99 -0
- package/src/components/machines/machine-detail.tsx +1 -1
- package/src/components/model-policy-picker.tsx +15 -0
- package/src/components/sandbox-terminal.tsx +24 -7
- package/src/components/sandbox-workspace.tsx +42 -4
- package/src/components/workspace-dock.tsx +59 -5
- package/src/hooks/use-attached-browsers.ts +13 -11
- package/src/hooks/use-auth-runs.ts +278 -0
- package/src/hooks/use-browser-downloads.ts +218 -0
- package/src/hooks/use-browser-frame-stream.ts +168 -59
- package/src/hooks/use-browser-identities.ts +47 -6
- package/src/hooks/use-browser-session.ts +94 -27
- package/src/hooks/use-browser-sessions.ts +19 -14
- package/src/hooks/use-channels.ts +99 -0
- package/src/hooks/use-computer-frame-stream.ts +184 -61
- package/src/hooks/use-computer-session.ts +22 -2
- package/src/hooks/use-computer-sessions.ts +19 -13
- package/src/hooks/use-desktop-stream.ts +39 -7
- package/src/hooks/use-interaction-interventions.ts +242 -0
- package/src/hooks/use-interaction-invalidation.ts +66 -0
- package/src/hooks/use-machine-chip.ts +13 -3
- package/src/hooks/use-network-routes.ts +214 -0
- package/src/hooks/use-site-auth-connections.ts +226 -0
- package/src/hooks/use-supergrok-accounts.ts +81 -0
- package/src/hooks/use-terminal-stream.ts +288 -55
- package/src/index.ts +8 -0
- package/src/interaction.ts +30 -0
- package/src/lib/host-platform.ts +10 -0
- package/src/lib/relay-wire.ts +43 -4
- package/src/lib/terminal-capability.ts +1 -1
- package/src/model-policy.ts +19 -4
- package/src/provider.tsx +133 -1
- package/src/realtime/realtime-control.tsx +181 -26
- package/src/session-context.ts +66 -1
- package/src/timeline/activity-rail.tsx +6 -0
- package/src/timeline/projection.ts +58 -0
- package/src/timeline/types.ts +2 -0
- package/styles/compiled.css +64 -6
- package/dist/chunk-23EJ676W.js.map +0 -1
- package/dist/chunk-6BBWWOOU.js +0 -82
- package/dist/chunk-6BBWWOOU.js.map +0 -1
- package/dist/chunk-7I2KB3OK.js +0 -3895
- package/dist/chunk-7I2KB3OK.js.map +0 -1
- package/dist/chunk-HDBG7XGO.js.map +0 -1
- package/dist/chunk-JAGDUCZQ.js.map +0 -1
- package/dist/chunk-JR3QFY6B.js.map +0 -1
- package/dist/chunk-WYA65Y3F.js.map +0 -1
- package/dist/chunk-X4S56Y2H.js.map +0 -1
- package/dist/interactive-workbench-viewers-KHNOHWQE.js +0 -13
- /package/dist/{chunk-ROIRTM37.js.map → chunk-5UQPNLIO.js.map} +0 -0
- /package/dist/{chunk-724BW4TW.js.map → chunk-IGC6A2ZI.js.map} +0 -0
- /package/dist/{interactive-workbench-viewers-KHNOHWQE.js.map → interactive-workbench-viewers-TOHBXJEE.js.map} +0 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type InteractionHostPlatform = "mac" | "other";
|
|
2
|
+
/** Physical client platform. Remote input adapters use this only to identify
|
|
3
|
+
* the user's primary shortcut modifier; the target platform is resolved
|
|
4
|
+
* separately. */
|
|
5
|
+
export declare function interactionHostPlatform(): InteractionHostPlatform;
|
package/dist/lib/relay-wire.d.ts
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
/** `StreamKind.STREAM_KIND_DESKTOP` (agent-proto enum value). */
|
|
2
2
|
export declare const STREAM_KIND_DESKTOP = 2;
|
|
3
|
+
/** `StreamKind.STREAM_KIND_PTY` (agent-proto enum value). */
|
|
4
|
+
export declare const STREAM_KIND_PTY = 1;
|
|
3
5
|
/** `StreamKind.STREAM_KIND_BROWSER` (agent-proto enum value). */
|
|
4
6
|
export declare const STREAM_KIND_BROWSER = 3;
|
|
5
7
|
/** `StreamKind.STREAM_KIND_COMPUTER` (agent-proto enum value). */
|
|
6
8
|
export declare const STREAM_KIND_COMPUTER = 4;
|
|
7
9
|
/** `StreamRole.STREAM_ROLE_CLIENT` (agent-proto enum value). */
|
|
8
10
|
export declare const STREAM_ROLE_CLIENT = 2;
|
|
11
|
+
/** `StreamCloseReason.STREAM_CLOSE_REASON_NORMAL`. */
|
|
12
|
+
export declare const STREAM_CLOSE_REASON_NORMAL = 1;
|
|
9
13
|
export interface RelayChannel {
|
|
10
14
|
channelId: string;
|
|
11
15
|
workspaceId: string;
|
|
@@ -21,6 +25,20 @@ export interface RelayStreamOpen {
|
|
|
21
25
|
}
|
|
22
26
|
/** Encode a `StreamOpen`, byte-compatible with `StreamOpen.encode(...).finish()`. */
|
|
23
27
|
export declare function encodeStreamOpen(message: RelayStreamOpen): Uint8Array;
|
|
28
|
+
/** Encode an intentional viewer detach. Transport loss omits this message so
|
|
29
|
+
* reconnect/resume remains available. */
|
|
30
|
+
export declare function encodeStreamClose(message: {
|
|
31
|
+
channelId: string;
|
|
32
|
+
reason: number;
|
|
33
|
+
message: string;
|
|
34
|
+
}): Uint8Array;
|
|
35
|
+
/** Encode a viewer→agent PTY input `StreamFrame`. */
|
|
36
|
+
export declare function encodeStreamFrame(message: {
|
|
37
|
+
channelId: string;
|
|
38
|
+
seq: string;
|
|
39
|
+
data: Uint8Array;
|
|
40
|
+
producedAtMs: string;
|
|
41
|
+
}): Uint8Array;
|
|
24
42
|
/** Decode a `StreamOpenAck` (we need `accepted` + the error message). */
|
|
25
43
|
export declare function decodeStreamOpenAck(bytes: Uint8Array): {
|
|
26
44
|
accepted: boolean;
|
|
@@ -28,7 +46,8 @@ export declare function decodeStreamOpenAck(bytes: Uint8Array): {
|
|
|
28
46
|
message?: string;
|
|
29
47
|
};
|
|
30
48
|
};
|
|
31
|
-
/** Decode
|
|
49
|
+
/** Decode the sequence plus `data` from a `StreamFrame`. */
|
|
32
50
|
export declare function decodeStreamFrame(bytes: Uint8Array): {
|
|
51
|
+
seq: string;
|
|
33
52
|
data: Uint8Array;
|
|
34
53
|
};
|
package/dist/machines.js
CHANGED
|
@@ -24,10 +24,10 @@ import {
|
|
|
24
24
|
healthPulses,
|
|
25
25
|
pointsFor,
|
|
26
26
|
useMachines
|
|
27
|
-
} from "./chunk-
|
|
28
|
-
import "./chunk-LAKLF4PA.js";
|
|
27
|
+
} from "./chunk-HA46CYQK.js";
|
|
29
28
|
import "./chunk-KZ73RL76.js";
|
|
30
|
-
import "./chunk-
|
|
29
|
+
import "./chunk-C5ZPSSS5.js";
|
|
30
|
+
import "./chunk-LAKLF4PA.js";
|
|
31
31
|
import "./chunk-22KP6LR5.js";
|
|
32
32
|
export {
|
|
33
33
|
CONNECTION_STATUS_META,
|
package/dist/model-policy.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ClientModel, ReasoningEffort, WorkspaceModelCatalogModel } from "@opengeni/sdk";
|
|
2
|
-
export type PickerBillingClass = "opengeni_credits" | "codex_subscription" | "byok";
|
|
2
|
+
export type PickerBillingClass = "opengeni_credits" | "codex_subscription" | "supergrok_subscription" | "byok";
|
|
3
3
|
export type PickerModelRow<TCatalog extends ClientModel = WorkspaceModelCatalogModel> = {
|
|
4
4
|
id: string;
|
|
5
5
|
label: string;
|
package/dist/model-policy.js
CHANGED
package/dist/provider.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type WorkspaceControlEvent } from "@opengeni/sdk";
|
|
1
|
+
import { type WorkspaceControlEvent, type WorkspaceInteractionRevisionEvent } from "@opengeni/sdk";
|
|
2
2
|
import { type ReactNode } from "react";
|
|
3
3
|
import type { SessionClientLike } from "./client.js";
|
|
4
4
|
export { useOpenGeni, useOpenGeniClient } from "./session-context.js";
|
|
@@ -7,10 +7,11 @@ export type OpenGeniProviderProps = {
|
|
|
7
7
|
client: SessionClientLike;
|
|
8
8
|
workspaceId: string;
|
|
9
9
|
onWorkspaceControlEvent?: ((event: WorkspaceControlEvent) => void) | undefined;
|
|
10
|
+
onWorkspaceInteractionEvent?: ((event: WorkspaceInteractionRevisionEvent) => void) | undefined;
|
|
10
11
|
children?: ReactNode;
|
|
11
12
|
};
|
|
12
13
|
/**
|
|
13
14
|
* Supplies the OpenGeni client + workspace to all hooks below it. Hooks also
|
|
14
15
|
* accept `{ client, workspaceId }` overrides per call for multi-workspace UIs.
|
|
15
16
|
*/
|
|
16
|
-
export declare function OpenGeniProvider({ client, workspaceId, onWorkspaceControlEvent, children, }: OpenGeniProviderProps): import("react").JSX.Element;
|
|
17
|
+
export declare function OpenGeniProvider({ client, workspaceId, onWorkspaceControlEvent, onWorkspaceInteractionEvent, children, }: OpenGeniProviderProps): import("react").JSX.Element;
|
|
@@ -5,13 +5,13 @@ import type { EmbeddedRealtimeSessionClientLike } from "../client.js";
|
|
|
5
5
|
export type RealtimeModelOption = {
|
|
6
6
|
id: SessionRealtimeModel;
|
|
7
7
|
label: string;
|
|
8
|
-
provider: "OpenGeni" | "Connected Codex" | "Your Gateway";
|
|
8
|
+
provider: "OpenGeni" | "Connected Codex" | "Connected SuperGrok" | "Your Gateway";
|
|
9
9
|
description: string;
|
|
10
10
|
available: boolean;
|
|
11
11
|
unavailableReason: string | null;
|
|
12
12
|
recommended: boolean;
|
|
13
13
|
};
|
|
14
|
-
declare const REALTIME_MODEL_PROVIDERS: readonly ["OpenGeni", "Connected Codex", "Your Gateway"];
|
|
14
|
+
declare const REALTIME_MODEL_PROVIDERS: readonly ["OpenGeni", "Connected Codex", "Connected SuperGrok", "Your Gateway"];
|
|
15
15
|
type RealtimeModelProvider = (typeof REALTIME_MODEL_PROVIDERS)[number];
|
|
16
16
|
type RealtimeControllerClient = EmbeddedRealtimeSessionClientLike & SessionRealtimeClientLike;
|
|
17
17
|
export type SessionRealtimeControllerFactory = (options: CreateSessionRealtimeControllerOptions) => SessionRealtimeController;
|
|
@@ -38,6 +38,8 @@ export declare function useSessionRealtime(options: {
|
|
|
38
38
|
model?: SessionRealtimeModel | undefined;
|
|
39
39
|
modelAvailable?: boolean | undefined;
|
|
40
40
|
modelUnavailableReason?: string | null | undefined;
|
|
41
|
+
/** Model-visible application context captured with each durable realtime message. */
|
|
42
|
+
getModelContext?: (() => string | undefined) | undefined;
|
|
41
43
|
/** Deterministic browser-test/demo seam. Production hosts should use the SDK default. */
|
|
42
44
|
controllerFactory?: SessionRealtimeControllerFactory | undefined;
|
|
43
45
|
}): {
|
|
@@ -63,6 +65,8 @@ export declare function SessionRealtimeControl(props: {
|
|
|
63
65
|
events: SessionEvent[];
|
|
64
66
|
eventsReady: boolean;
|
|
65
67
|
codexConnected: boolean;
|
|
68
|
+
/** Model-visible application context captured with each durable realtime message. */
|
|
69
|
+
getModelContext?: (() => string | undefined) | undefined;
|
|
66
70
|
realtimeAutostartModel?: SessionRealtimeModel | undefined;
|
|
67
71
|
onRealtimeAutostartConsumed?: (() => void) | undefined;
|
|
68
72
|
/** Host hides dictate (and can choreograph layout) while realtime voice is live. */
|
package/dist/realtime.js
CHANGED
|
@@ -3,15 +3,15 @@ import {
|
|
|
3
3
|
PickerAnimatedPage,
|
|
4
4
|
PickerBackHeader,
|
|
5
5
|
PickerNavRow
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import "./chunk-
|
|
6
|
+
} from "./chunk-MKPIAGVL.js";
|
|
7
|
+
import "./chunk-XBZWOM2K.js";
|
|
8
8
|
import {
|
|
9
9
|
usePortalTokenSource,
|
|
10
10
|
usePortalTokenStyle
|
|
11
11
|
} from "./chunk-VZTQ73XT.js";
|
|
12
12
|
import {
|
|
13
13
|
useEmbeddedRealtimeSession
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-C5ZPSSS5.js";
|
|
15
15
|
import {
|
|
16
16
|
cn
|
|
17
17
|
} from "./chunk-22KP6LR5.js";
|
|
@@ -187,16 +187,91 @@ var CODEX_LIVE_MODEL = {
|
|
|
187
187
|
unavailableReason: "Connect Codex to use this voice model",
|
|
188
188
|
recommended: false
|
|
189
189
|
};
|
|
190
|
-
var REALTIME_MODEL_PROVIDERS = [
|
|
190
|
+
var REALTIME_MODEL_PROVIDERS = [
|
|
191
|
+
"OpenGeni",
|
|
192
|
+
"Connected Codex",
|
|
193
|
+
"Connected SuperGrok",
|
|
194
|
+
"Your Gateway"
|
|
195
|
+
];
|
|
191
196
|
var REALTIME_PROVIDER_META = {
|
|
192
197
|
OpenGeni: { billingClass: "opengeni_credits", hint: "Will use credits" },
|
|
193
198
|
"Connected Codex": {
|
|
194
199
|
billingClass: "codex_subscription",
|
|
195
200
|
hint: "ChatGPT / Codex plan"
|
|
196
201
|
},
|
|
202
|
+
"Connected SuperGrok": {
|
|
203
|
+
billingClass: "supergrok_subscription",
|
|
204
|
+
hint: "SuperGrok / xAI plan"
|
|
205
|
+
},
|
|
197
206
|
"Your Gateway": { billingClass: "byok", hint: "Billed to your AI Gateway" }
|
|
198
207
|
};
|
|
199
208
|
var REALTIME_MODEL_STORAGE_PREFIX = "opengeni:realtime-model";
|
|
209
|
+
var REALTIME_MODEL_CATALOG_CACHE_TTL_MS = 6e4;
|
|
210
|
+
var REALTIME_MODEL_CATALOG_CACHE_MAX_WORKSPACES = 64;
|
|
211
|
+
var realtimeModelCatalogCache = /* @__PURE__ */ new WeakMap();
|
|
212
|
+
function realtimeModelFallback(codexConnected) {
|
|
213
|
+
return [
|
|
214
|
+
{
|
|
215
|
+
...CODEX_LIVE_MODEL,
|
|
216
|
+
available: codexConnected,
|
|
217
|
+
unavailableReason: codexConnected ? null : CODEX_LIVE_MODEL.unavailableReason
|
|
218
|
+
}
|
|
219
|
+
];
|
|
220
|
+
}
|
|
221
|
+
function realtimeModelCatalogCacheFor(client) {
|
|
222
|
+
const existing = realtimeModelCatalogCache.get(client);
|
|
223
|
+
if (existing) return existing;
|
|
224
|
+
const created = /* @__PURE__ */ new Map();
|
|
225
|
+
realtimeModelCatalogCache.set(client, created);
|
|
226
|
+
return created;
|
|
227
|
+
}
|
|
228
|
+
function readCachedRealtimeModelCatalog(client, workspaceId, now = Date.now()) {
|
|
229
|
+
const cache = realtimeModelCatalogCache.get(client);
|
|
230
|
+
const entry = cache?.get(workspaceId);
|
|
231
|
+
if (!entry || entry.state === "loading") return null;
|
|
232
|
+
if (entry.expiresAt > now) return entry.models;
|
|
233
|
+
cache?.delete(workspaceId);
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
function pruneRealtimeModelCatalogCache(cache, now) {
|
|
237
|
+
for (const [workspaceId, entry] of cache) {
|
|
238
|
+
if (entry.state === "ready" && entry.expiresAt <= now) cache.delete(workspaceId);
|
|
239
|
+
}
|
|
240
|
+
while (cache.size >= REALTIME_MODEL_CATALOG_CACHE_MAX_WORKSPACES) {
|
|
241
|
+
const oldestWorkspaceId = cache.keys().next().value;
|
|
242
|
+
if (oldestWorkspaceId === void 0) return;
|
|
243
|
+
cache.delete(oldestWorkspaceId);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
function loadRealtimeModelCatalog(client, workspaceId) {
|
|
247
|
+
const load = client.getWorkspaceRealtimeModelCatalog;
|
|
248
|
+
if (!load) return null;
|
|
249
|
+
const now = Date.now();
|
|
250
|
+
const cache = realtimeModelCatalogCacheFor(client);
|
|
251
|
+
const entry = cache.get(workspaceId);
|
|
252
|
+
if (entry?.state === "loading") return entry.promise;
|
|
253
|
+
if (entry?.state === "ready" && entry.expiresAt > now) return Promise.resolve(entry.models);
|
|
254
|
+
if (entry) cache.delete(workspaceId);
|
|
255
|
+
pruneRealtimeModelCatalogCache(cache, now);
|
|
256
|
+
const promise = load.call(client, workspaceId).then((response) => response.models.map(toRealtimeModelOption)).then((models) => {
|
|
257
|
+
const current = cache.get(workspaceId);
|
|
258
|
+
if (current?.state === "loading" && current.promise === promise) {
|
|
259
|
+
cache.delete(workspaceId);
|
|
260
|
+
cache.set(workspaceId, {
|
|
261
|
+
state: "ready",
|
|
262
|
+
models,
|
|
263
|
+
expiresAt: Date.now() + REALTIME_MODEL_CATALOG_CACHE_TTL_MS
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
return models;
|
|
267
|
+
}).catch((error) => {
|
|
268
|
+
const current = cache.get(workspaceId);
|
|
269
|
+
if (current?.state === "loading" && current.promise === promise) cache.delete(workspaceId);
|
|
270
|
+
throw error;
|
|
271
|
+
});
|
|
272
|
+
cache.set(workspaceId, { state: "loading", promise });
|
|
273
|
+
return promise;
|
|
274
|
+
}
|
|
200
275
|
function codexRealtimeAdmissionAllowed(input) {
|
|
201
276
|
return codexRealtimeAdmissionBlocker(input) === null;
|
|
202
277
|
}
|
|
@@ -217,8 +292,14 @@ function useSessionRealtime(options) {
|
|
|
217
292
|
const audioRef = useRef(null);
|
|
218
293
|
const controllerRef = useRef(null);
|
|
219
294
|
const controllerModelRef = useRef(null);
|
|
295
|
+
const modelContextProviderRef = useRef(options.getModelContext);
|
|
296
|
+
modelContextProviderRef.current = options.getModelContext;
|
|
220
297
|
const [snapshot, setSnapshot] = useState(() => ({
|
|
221
|
-
status: hasStoredSessionRealtimeOwnerProof({
|
|
298
|
+
status: hasStoredSessionRealtimeOwnerProof({
|
|
299
|
+
workspaceId,
|
|
300
|
+
sessionId: options.sessionId,
|
|
301
|
+
model
|
|
302
|
+
}) ? "recovering" : "idle",
|
|
222
303
|
realtimeId: null,
|
|
223
304
|
mode: null,
|
|
224
305
|
bridge: null,
|
|
@@ -252,7 +333,8 @@ function useSessionRealtime(options) {
|
|
|
252
333
|
workspaceId,
|
|
253
334
|
sessionId: options.sessionId,
|
|
254
335
|
...audioRef.current ? { remoteAudio: audioRef.current } : {},
|
|
255
|
-
model
|
|
336
|
+
model,
|
|
337
|
+
getModelContext: () => modelContextProviderRef.current?.()
|
|
256
338
|
});
|
|
257
339
|
controllerRef.current = controller;
|
|
258
340
|
controllerModelRef.current = model;
|
|
@@ -424,28 +506,46 @@ function useRealtimeModelSelection(options) {
|
|
|
424
506
|
workspaceId: options.workspaceId
|
|
425
507
|
});
|
|
426
508
|
const activeModel = options.activeModel;
|
|
427
|
-
const
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
available: options.codexConnected,
|
|
431
|
-
unavailableReason: options.codexConnected ? null : CODEX_LIVE_MODEL.unavailableReason
|
|
432
|
-
}
|
|
433
|
-
]);
|
|
434
|
-
const [selectedModelId, setSelectedModelId] = useState(
|
|
435
|
-
() => readRealtimeModelPreference(workspaceId) ?? CODEX_LIVE_MODEL.id
|
|
509
|
+
const initialCachedCatalog = readCachedRealtimeModelCatalog(client, workspaceId);
|
|
510
|
+
const [catalog, setCatalog] = useState(
|
|
511
|
+
() => initialCachedCatalog ?? realtimeModelFallback(options.codexConnected)
|
|
436
512
|
);
|
|
513
|
+
const catalogScopeRef = useRef({
|
|
514
|
+
client,
|
|
515
|
+
workspaceId,
|
|
516
|
+
source: initialCachedCatalog ? "cache" : "fallback"
|
|
517
|
+
});
|
|
518
|
+
const [selectedModelId, setSelectedModelId] = useState(() => {
|
|
519
|
+
const preferred = readRealtimeModelPreference(workspaceId) ?? CODEX_LIVE_MODEL.id;
|
|
520
|
+
if (!initialCachedCatalog) return preferred;
|
|
521
|
+
if (initialCachedCatalog.some((model) => model.id === preferred && model.available)) {
|
|
522
|
+
return preferred;
|
|
523
|
+
}
|
|
524
|
+
return initialCachedCatalog.find((model) => model.available)?.id ?? CODEX_LIVE_MODEL.id;
|
|
525
|
+
});
|
|
437
526
|
useEffect(() => {
|
|
438
527
|
let disposed = false;
|
|
439
|
-
const
|
|
440
|
-
|
|
441
|
-
void load.call(client, workspaceId).then((response) => {
|
|
442
|
-
if (disposed) return;
|
|
443
|
-
const models = response.models.map(toRealtimeModelOption);
|
|
528
|
+
const applyCatalog = (models) => {
|
|
529
|
+
catalogScopeRef.current = { client, workspaceId, source: "cache" };
|
|
444
530
|
setCatalog(models);
|
|
445
531
|
setSelectedModelId((current) => {
|
|
446
532
|
if (models.some((model) => model.id === current && model.available)) return current;
|
|
447
533
|
return models.find((model) => model.available)?.id ?? CODEX_LIVE_MODEL.id;
|
|
448
534
|
});
|
|
535
|
+
};
|
|
536
|
+
const cached = readCachedRealtimeModelCatalog(client, workspaceId);
|
|
537
|
+
if (cached) {
|
|
538
|
+
const scope = catalogScopeRef.current;
|
|
539
|
+
if (scope.client !== client || scope.workspaceId !== workspaceId || scope.source !== "cache") {
|
|
540
|
+
applyCatalog(cached);
|
|
541
|
+
}
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
const loading = loadRealtimeModelCatalog(client, workspaceId);
|
|
545
|
+
if (!loading) return;
|
|
546
|
+
void loading.then((models) => {
|
|
547
|
+
if (disposed) return;
|
|
548
|
+
applyCatalog(models);
|
|
449
549
|
}).catch(() => void 0);
|
|
450
550
|
return () => {
|
|
451
551
|
disposed = true;
|
|
@@ -615,7 +715,13 @@ function RealtimeVoiceControl(props) {
|
|
|
615
715
|
animate: {
|
|
616
716
|
x: 0,
|
|
617
717
|
opacity: 1,
|
|
618
|
-
transition: reduceMotion ? { duration: 0 } : {
|
|
718
|
+
transition: reduceMotion ? { duration: 0 } : {
|
|
719
|
+
delay: 0.32,
|
|
720
|
+
type: "spring",
|
|
721
|
+
stiffness: 320,
|
|
722
|
+
damping: 30,
|
|
723
|
+
mass: 0.8
|
|
724
|
+
}
|
|
619
725
|
},
|
|
620
726
|
...reduceMotion ? {} : {
|
|
621
727
|
exit: {
|
|
@@ -1017,7 +1123,11 @@ function statusContent(snapshot, modelAvailable, canStart, admissionBlocker, mod
|
|
|
1017
1123
|
};
|
|
1018
1124
|
}
|
|
1019
1125
|
if (!canStart && admissionBlocker) {
|
|
1020
|
-
return {
|
|
1126
|
+
return {
|
|
1127
|
+
phase: "unavailable",
|
|
1128
|
+
label: "Voice unavailable",
|
|
1129
|
+
detail: admissionBlocker
|
|
1130
|
+
};
|
|
1021
1131
|
}
|
|
1022
1132
|
return {
|
|
1023
1133
|
phase: "idle",
|
|
@@ -1094,7 +1204,11 @@ function RealtimeStatusDot(props) {
|
|
|
1094
1204
|
{
|
|
1095
1205
|
className: "absolute inset-0 rounded-full bg-og-status-running",
|
|
1096
1206
|
animate: { opacity: [0.45, 0], scale: [1, 2.2] },
|
|
1097
|
-
transition: {
|
|
1207
|
+
transition: {
|
|
1208
|
+
duration: 1.4,
|
|
1209
|
+
ease: "easeOut",
|
|
1210
|
+
repeat: Number.POSITIVE_INFINITY
|
|
1211
|
+
}
|
|
1098
1212
|
}
|
|
1099
1213
|
) : null,
|
|
1100
1214
|
/* @__PURE__ */ jsx2(
|
|
@@ -1152,7 +1266,7 @@ function writeRealtimeModelPreference(workspaceId, model) {
|
|
|
1152
1266
|
}
|
|
1153
1267
|
}
|
|
1154
1268
|
function isRealtimeModel(value) {
|
|
1155
|
-
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";
|
|
1269
|
+
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 === "supergrok/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";
|
|
1156
1270
|
}
|
|
1157
1271
|
var useSessionCodexRealtime = useSessionRealtime;
|
|
1158
1272
|
var useWorkspaceRealtimeModelSelection = useRealtimeModelSelection;
|