@opengeni/sdk 0.57.0 → 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 +1017 -26
- 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-JDLDDRNE.js → chunk-2UXZUCEZ.js} +291 -34
- 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-JRPFWI6T.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-PKQ377ED.js → chunk-FG3OO5LM.js} +2686 -611
- 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-YKZME56C.js → chunk-KWADQ227.js} +3 -3
- package/dist/{chunk-YKZME56C.js.map → chunk-KWADQ227.js.map} +1 -1
- 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-ST5DDKJP.js → chunk-NC57YMUO.js} +121 -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-HJ3HHUT5.js → chunk-YIKA2QT4.js} +33 -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 +740 -94
- package/dist/codex-realtime-controller.d.ts +3 -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 +25 -6
- package/dist/deprecation.d.ts +47 -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 +240 -121
- 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.js +1 -1
- 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 +56 -11
- package/dist/index.js +242 -125
- package/dist/index.js.map +1 -1
- package/dist/interaction.d.ts +84 -1
- package/dist/interaction.js +6 -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 +3 -1
- package/dist/realtime.js +6 -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 +2863 -424
- 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-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 +4084 -515
- package/src/codex-realtime-controller.ts +235 -5
- 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/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 +169 -2
- package/src/feedback.ts +20 -0
- package/src/gateway-realtime-transport.ts +3 -3
- package/src/github-repositories.ts +60 -0
- package/src/index.ts +561 -41
- package/src/interaction.ts +276 -4
- 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 +1 -0
- 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 +3346 -501
- 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-state.ts +8 -82
- package/dist/chunk-GU6JF75T.js +0 -119
- package/dist/chunk-GU6JF75T.js.map +0 -1
- package/dist/chunk-HJ3HHUT5.js.map +0 -1
- package/dist/chunk-JDLDDRNE.js.map +0 -1
- package/dist/chunk-JRPFWI6T.js.map +0 -1
- package/dist/chunk-PKQ377ED.js.map +0 -1
- package/dist/chunk-ST5DDKJP.js.map +0 -1
- package/dist/chunk-VWE2QIVO.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/gateway-realtime-transport.ts"],"sourcesContent":["import type { CodexRealtimeAudibleOutputState, CodexRealtimeWebrtcSession } from \"./codex-realtime\";\nimport type {\n CodexRealtimeControllerClient,\n RealtimeControllerTransportStarter,\n} from \"./codex-realtime-controller\";\n\ntype GatewayClientEvent = Record<string, unknown> & { type: string };\ntype GatewayServerEvent = Record<string, unknown> & { type: string };\n\nconst AUDIO_SAMPLE_RATE = 24_000;\nconst DELEGATION_TOOL = \"delegate_to_session\";\ntype RealtimeDialect = \"gateway\" | \"xai\";\n\nexport function createGatewayRealtimeTransportStarter(): RealtimeControllerTransportStarter {\n return createWebsocketRealtimeTransportStarter(\"gateway\");\n}\n\nexport function createXaiSubscriptionRealtimeTransportStarter(): RealtimeControllerTransportStarter {\n return createWebsocketRealtimeTransportStarter(\"xai\");\n}\n\nfunction createWebsocketRealtimeTransportStarter(\n dialect: RealtimeDialect,\n): RealtimeControllerTransportStarter {\n return async (input) => {\n const client = input.client as CodexRealtimeControllerClient;\n const negotiate =\n dialect === \"xai\"\n ? client.negotiateXaiSubscriptionRealtime?.bind(client)\n : client.negotiateGatewayRealtime?.bind(client);\n if (!negotiate) {\n throw new Error(\n dialect === \"xai\"\n ? \"The OpenGeni client does not support connected SuperGrok realtime\"\n : \"The OpenGeni client does not support AI Gateway realtime\",\n );\n }\n const answer = await negotiate(\n input.workspaceId,\n input.sessionId,\n {\n realtimeId: input.realtimeId,\n operationId: input.operationId,\n browserInstanceId: input.browserInstanceId,\n ownerKey: input.ownerKey,\n expectedVersion: input.expectedVersion,\n expectedConnectionEpoch: input.expectedConnectionEpoch,\n rotate: input.rotate,\n },\n { signal: input.signal },\n );\n throwIfAborted(input.signal);\n\n const websocket = new WebSocket(\n answer.url,\n dialect === \"xai\"\n ? [`xai-client-secret.${answer.token}`]\n : [\"ai-gateway-realtime.v1\", `ai-gateway-auth.${answer.token}`],\n );\n const channel = new GatewayRealtimeDataChannel((payload) =>\n handleBridgeOutbound(websocket, payload, dialect),\n );\n input.onEventsCreated(channel.asRtcDataChannel());\n const audio = new GatewayRealtimeAudio({\n onAudio: (encoded) =>\n send(websocket, {\n type: dialect === \"xai\" ? \"input_audio_buffer.append\" : \"input-audio-append\",\n audio: encoded,\n }),\n onAudibleOutputState: input.onAudibleOutputState,\n });\n let stopped = false;\n let currentOutputItemId: string | null = null;\n const finalizedAssistantItems = new Set<string>();\n const microphoneTracks = input.media.getAudioTracks();\n const onMicrophoneEnded = (): void => {\n if (!stopped) input.onMicrophoneEnded();\n };\n for (const track of microphoneTracks) track.addEventListener?.(\"ended\", onMicrophoneEnded);\n\n const onMessage = (event: MessageEvent): void => {\n if (typeof event.data !== \"string\") return;\n let parsed: unknown;\n try {\n parsed = JSON.parse(event.data);\n } catch {\n return;\n }\n if (!isRecord(parsed) || typeof parsed.type !== \"string\") return;\n handleRealtimeEvent({\n event: parsed as GatewayServerEvent,\n dialect,\n channel,\n websocket,\n audio,\n finalizedAssistantItems,\n getCurrentOutputItemId: () => currentOutputItemId,\n setCurrentOutputItemId: (value) => {\n currentOutputItemId = value;\n },\n });\n };\n const onClose = (): void => {\n if (!stopped) input.onConnectionHealth(\"closed\");\n };\n const onError = (): void => {\n if (!stopped) input.onConnectionHealth(\"failed\");\n };\n websocket.addEventListener(\"message\", onMessage);\n websocket.addEventListener(\"close\", onClose);\n websocket.addEventListener(\"error\", onError);\n\n const stop = (): void => {\n if (stopped) return;\n stopped = true;\n input.signal.removeEventListener(\"abort\", stop);\n websocket.removeEventListener(\"message\", onMessage);\n websocket.removeEventListener(\"close\", onClose);\n websocket.removeEventListener(\"error\", onError);\n for (const track of microphoneTracks) track.removeEventListener?.(\"ended\", onMicrophoneEnded);\n channel.close();\n audio.dispose();\n if (\n websocket.readyState === WebSocket.OPEN ||\n websocket.readyState === WebSocket.CONNECTING\n ) {\n websocket.close(1000, \"OpenGeni realtime connection retired\");\n }\n };\n input.signal.addEventListener(\"abort\", stop, { once: true });\n\n try {\n await waitForWebSocketOpen(websocket, input.signal);\n channel.open();\n send(\n websocket,\n dialect === \"xai\"\n ? xaiSessionUpdate(answer.instructions)\n : gatewaySessionUpdate(answer.instructions),\n );\n for (const item of answer.initialItems) {\n const text = `<session_initial_item role=\"${item.role}\">\\n${item.text}\\n</session_initial_item>`;\n send(\n websocket,\n dialect === \"xai\"\n ? {\n type: \"conversation.item.create\",\n item: {\n type: \"message\",\n role: \"user\",\n content: [{ type: \"input_text\", text }],\n },\n }\n : {\n type: \"conversation-item-create\",\n item: { type: \"text-message\", role: \"user\", text },\n },\n );\n }\n await audio.startCapture(input.media);\n input.onConnectionHealth(\"connected\");\n } catch (error) {\n stop();\n throw error;\n }\n\n return {\n peerConnection: null as unknown as RTCPeerConnection,\n events: channel.asRtcDataChannel(),\n media: input.media,\n operationId: input.operationId,\n connectionId: answer.connectionId,\n connectionEpoch: answer.connectionEpoch,\n startupFenceSequence: answer.startupFenceSequence,\n modeVersion: answer.modeVersion,\n microphoneHealthy: () =>\n microphoneTracks.length > 0 &&\n microphoneTracks.every((track) => track.readyState !== \"ended\"),\n audibleOutputState: () => audio.audibleOutputState(),\n setOutputMuted: (muted) => audio.setMuted(muted),\n activateRemoteAudio: () => void audio.resume(),\n retryAudibleOutput: () => audio.resume(),\n stop,\n } satisfies CodexRealtimeWebrtcSession;\n };\n}\n\nfunction delegationTool(): Record<string, unknown> {\n return {\n type: \"function\",\n name: DELEGATION_TOOL,\n description:\n \"Pass execution work, actions, and session tasks to the underlying session agent. Include the complete standalone request and relevant conversational context.\",\n parameters: {\n type: \"object\",\n properties: {\n request: {\n type: \"string\",\n description: \"Complete standalone task for the session agent\",\n },\n },\n required: [\"request\"],\n additionalProperties: false,\n },\n };\n}\n\nfunction gatewaySessionUpdate(instructions: string): GatewayClientEvent {\n return {\n type: \"session-update\",\n config: {\n instructions,\n outputModalities: [\"audio\"],\n inputAudioFormat: { type: \"audio/pcm\", rate: AUDIO_SAMPLE_RATE },\n outputAudioFormat: { type: \"audio/pcm\", rate: AUDIO_SAMPLE_RATE },\n inputAudioTranscription: {},\n outputAudioTranscription: {},\n turnDetection: {\n type: \"server-vad\",\n prefixPaddingMs: 300,\n silenceDurationMs: 500,\n },\n tools: [delegationTool()],\n },\n };\n}\n\nfunction xaiSessionUpdate(instructions: string): GatewayClientEvent {\n return {\n type: \"session.update\",\n session: {\n instructions,\n voice: \"eve\",\n reasoning: { effort: \"high\" },\n turn_detection: {\n type: \"server_vad\",\n prefix_padding_ms: 300,\n silence_duration_ms: 500,\n },\n audio: {\n input: {\n format: { type: \"audio/pcm\", rate: AUDIO_SAMPLE_RATE },\n transcription: { model: \"grok-transcribe\" },\n },\n output: { format: { type: \"audio/pcm\", rate: AUDIO_SAMPLE_RATE } },\n },\n tools: [delegationTool()],\n },\n };\n}\n\nfunction handleRealtimeEvent(input: {\n event: GatewayServerEvent;\n dialect: RealtimeDialect;\n channel: GatewayRealtimeDataChannel;\n websocket: WebSocket;\n audio: GatewayRealtimeAudio;\n finalizedAssistantItems: Set<string>;\n getCurrentOutputItemId(): string | null;\n setCurrentOutputItemId(value: string | null): void;\n}): void {\n const event = input.event;\n const eventId = providerEventId(event);\n if (event.type === \"session-created\" || event.type === \"session.created\") {\n const session = isRecord(event.session) ? event.session : null;\n const sessionId =\n stringValue(event.sessionId) ?? stringValue(session?.id) ?? `realtime-${crypto.randomUUID()}`;\n input.channel.providerEvent({\n type: \"session.started\",\n event_id: eventId,\n session: { id: sessionId },\n });\n return;\n }\n if (event.type === \"speech-started\" || event.type === \"input_audio_buffer.speech_started\") {\n const itemId = input.getCurrentOutputItemId();\n if (itemId && input.audio.isPlaying()) {\n const audioEndMs = input.audio.playbackOffsetMs();\n input.audio.stopPlayback();\n send(\n input.websocket,\n input.dialect === \"xai\"\n ? {\n type: \"conversation.item.truncate\",\n item_id: itemId,\n content_index: 0,\n audio_end_ms: Math.max(0, Math.round(audioEndMs)),\n }\n : {\n type: \"conversation-item-truncate\",\n itemId,\n contentIndex: 0,\n audioEndMs: Math.max(0, Math.round(audioEndMs)),\n },\n );\n }\n return;\n }\n if (\n event.type === \"input-transcription-completed\" ||\n event.type === \"conversation.item.input_audio_transcription.completed\"\n ) {\n const transcript = stringValue(event.transcript) ?? \"\";\n const itemId = stringValue(event.itemId) ?? stringValue(event.item_id) ?? crypto.randomUUID();\n if (transcript.trim()) {\n input.channel.providerEvent({\n type: \"turn.done\",\n event_id: eventId,\n turn: { id: itemId, role: \"user\", transcript },\n });\n }\n return;\n }\n if (\n event.type === \"audio-delta\" ||\n event.type === \"response.output_audio.delta\" ||\n event.type === \"response.audio.delta\"\n ) {\n const delta = stringValue(event.delta);\n if (!delta) return;\n const itemId = stringValue(event.itemId) ?? stringValue(event.item_id);\n if (itemId) input.setCurrentOutputItemId(itemId);\n input.audio.play(delta);\n input.channel.providerEvent({ type: \"output_audio.delta\", event_id: eventId, audio: delta });\n return;\n }\n if (\n event.type === \"audio-transcript-done\" ||\n event.type === \"text-done\" ||\n event.type === \"response.output_audio_transcript.done\" ||\n event.type === \"response.audio_transcript.done\" ||\n event.type === \"response.output_text.done\"\n ) {\n const itemId = stringValue(event.itemId) ?? stringValue(event.item_id) ?? crypto.randomUUID();\n const transcript = stringValue(event.transcript) ?? stringValue(event.text) ?? \"\";\n if (transcript.trim() && !input.finalizedAssistantItems.has(itemId)) {\n input.finalizedAssistantItems.add(itemId);\n input.channel.providerEvent({\n type: \"turn.done\",\n event_id: eventId,\n turn: { id: itemId, role: \"assistant\", transcript },\n });\n }\n return;\n }\n if (event.type === \"audio-done\" || event.type === \"response.output_audio.done\") return;\n if (\n event.type === \"function-call-arguments-done\" ||\n event.type === \"response.function_call_arguments.done\"\n ) {\n const callId =\n stringValue(event.callId) ??\n stringValue(event.call_id) ??\n stringValue(event.itemId) ??\n stringValue(event.item_id) ??\n crypto.randomUUID();\n const name = stringValue(event.name);\n if (name !== DELEGATION_TOOL) {\n sendFunctionOutput(\n input.websocket,\n input.dialect,\n callId,\n name,\n JSON.stringify({ error: \"Unsupported realtime tool\" }),\n );\n sendResponseCreate(input.websocket, input.dialect);\n return;\n }\n const request = delegationRequest(stringValue(event.arguments) ?? \"\");\n input.channel.providerEvent({\n type: \"delegation.created\",\n event_id: eventId,\n item: {\n id: callId,\n type: \"delegation\",\n target: \"client\",\n content: [{ type: \"input_text\", text: request }],\n },\n });\n return;\n }\n if (event.type === \"error\") {\n const nested = isRecord(event.error) ? event.error : null;\n input.channel.providerEvent({\n type: \"error\",\n event_id: eventId,\n message:\n stringValue(event.message) ?? stringValue(nested?.message) ?? \"Realtime provider error\",\n });\n }\n}\n\nclass GatewayRealtimeDataChannel extends EventTarget {\n readyState: RTCDataChannelState = \"connecting\";\n private pendingOutbound: Array<Record<string, unknown>> = [];\n private outboundScheduled = false;\n\n constructor(private readonly outbound: (messages: Array<Record<string, unknown>>) => void) {\n super();\n }\n\n asRtcDataChannel(): RTCDataChannel {\n return this as unknown as RTCDataChannel;\n }\n\n open(): void {\n this.readyState = \"open\";\n this.dispatchEvent(new Event(\"open\"));\n }\n\n send(payload: string): void {\n if (this.readyState !== \"open\") throw new Error(\"Gateway realtime channel is not open\");\n let parsed: unknown;\n try {\n parsed = JSON.parse(payload);\n } catch {\n return;\n }\n if (!isRecord(parsed)) return;\n this.pendingOutbound.push(parsed);\n if (this.outboundScheduled) return;\n this.outboundScheduled = true;\n queueMicrotask(() => {\n this.outboundScheduled = false;\n const messages = this.pendingOutbound;\n this.pendingOutbound = [];\n if (messages.length > 0 && this.readyState === \"open\") this.outbound(messages);\n });\n }\n\n providerEvent(event: Record<string, unknown>): void {\n if (this.readyState === \"closed\") return;\n this.dispatchEvent(new MessageEvent(\"message\", { data: JSON.stringify(event) }));\n }\n\n close(): void {\n if (this.readyState === \"closed\") return;\n this.readyState = \"closed\";\n this.pendingOutbound = [];\n this.dispatchEvent(new Event(\"close\"));\n }\n}\n\nfunction handleBridgeOutbound(\n websocket: WebSocket,\n messages: Array<Record<string, unknown>>,\n dialect: RealtimeDialect,\n): void {\n const groups = new Map<\n string,\n { type: string; id: string | null; channel: string; text: string }\n >();\n for (const message of messages) {\n const type = stringValue(message.type);\n if (type !== \"session.context.append\" && type !== \"delegation.context.append\") continue;\n const id = stringValue(message.delegation_item_id) ?? null;\n const channel = stringValue(message.channel) ?? \"commentary\";\n const key = `${type}:${id ?? \"session\"}:${channel}`;\n const content = Array.isArray(message.content) ? message.content : [];\n const text = content\n .filter(isRecord)\n .map((part) => stringValue(part.text) ?? \"\")\n .join(\"\");\n const existing = groups.get(key);\n groups.set(key, {\n type,\n id,\n channel,\n text: `${existing?.text ?? \"\"}${text}`,\n });\n }\n for (const group of groups.values()) {\n if (group.type === \"delegation.context.append\" && group.id && group.channel === \"speakable\") {\n sendFunctionOutput(\n websocket,\n dialect,\n group.id,\n DELEGATION_TOOL,\n JSON.stringify({ result: group.text }),\n );\n sendResponseCreate(websocket, dialect);\n continue;\n }\n const wrapper =\n group.type === \"delegation.context.append\"\n ? group.channel === \"commentary\"\n ? \"execution_progress\"\n : \"execution_result\"\n : \"session_update\";\n const text = `<${wrapper}>\\n${group.text}\\n</${wrapper}>`;\n send(\n websocket,\n dialect === \"xai\"\n ? {\n type: \"conversation.item.create\",\n item: {\n type: \"message\",\n role: \"user\",\n content: [{ type: \"input_text\", text }],\n },\n }\n : {\n type: \"conversation-item-create\",\n item: { type: \"text-message\", role: \"user\", text },\n },\n );\n if (group.channel === \"speakable\") sendResponseCreate(websocket, dialect);\n }\n}\n\nfunction sendFunctionOutput(\n websocket: WebSocket,\n dialect: RealtimeDialect,\n callId: string,\n name: string | null,\n output: string,\n): void {\n send(\n websocket,\n dialect === \"xai\"\n ? {\n type: \"conversation.item.create\",\n item: { type: \"function_call_output\", call_id: callId, output },\n }\n : {\n type: \"conversation-item-create\",\n item: { type: \"function-call-output\", callId, name, output },\n },\n );\n}\n\nfunction sendResponseCreate(websocket: WebSocket, dialect: RealtimeDialect): void {\n send(websocket, { type: dialect === \"xai\" ? \"response.create\" : \"response-create\" });\n}\n\nclass GatewayRealtimeAudio {\n private captureContext: AudioContext | null = null;\n private captureSource: MediaStreamAudioSourceNode | null = null;\n private captureProcessor: ScriptProcessorNode | null = null;\n private playbackContext: AudioContext | null = null;\n private playbackGain: GainNode | null = null;\n private playbackTime = 0;\n private playbackStartedAt = 0;\n private activeSources = new Set<AudioBufferSourceNode>();\n private outputState: CodexRealtimeAudibleOutputState = \"inactive\";\n private muted = false;\n\n constructor(\n private readonly options: {\n onAudio(audio: string): void;\n onAudibleOutputState(state: CodexRealtimeAudibleOutputState): void;\n },\n ) {}\n\n async startCapture(media: MediaStream): Promise<void> {\n const context = new AudioContext({ sampleRate: AUDIO_SAMPLE_RATE });\n this.captureContext = context;\n const source = context.createMediaStreamSource(media);\n const processor = context.createScriptProcessor(4096, 1, 1);\n this.captureSource = source;\n this.captureProcessor = processor;\n processor.onaudioprocess = (event) => {\n const samples = resample(\n new Float32Array(event.inputBuffer.getChannelData(0)),\n context.sampleRate,\n AUDIO_SAMPLE_RATE,\n );\n this.options.onAudio(encodePcm16(samples));\n };\n source.connect(processor);\n processor.connect(context.destination);\n await context.resume();\n }\n\n play(encoded: string): void {\n const context = (this.playbackContext ??= new AudioContext({ sampleRate: AUDIO_SAMPLE_RATE }));\n if (context.state !== \"running\") {\n void this.resume().then((resumed) => {\n if (resumed) this.schedule(encoded);\n });\n return;\n }\n this.schedule(encoded);\n }\n\n private schedule(encoded: string): void {\n const context = this.playbackContext;\n if (!context) return;\n const samples = decodePcm16(encoded);\n const buffer = context.createBuffer(1, samples.length, AUDIO_SAMPLE_RATE);\n buffer.getChannelData(0).set(samples);\n const source = context.createBufferSource();\n source.buffer = buffer;\n source.connect(this.outputNode(context));\n const startAt = Math.max(context.currentTime, this.playbackTime);\n if (this.activeSources.size === 0) this.playbackStartedAt = startAt;\n source.start(startAt);\n this.playbackTime = startAt + buffer.duration;\n this.activeSources.add(source);\n this.publish(\"audible\");\n source.onended = () => {\n this.activeSources.delete(source);\n if (this.activeSources.size === 0) this.publish(\"inactive\");\n };\n }\n\n stopPlayback(): void {\n for (const source of this.activeSources) {\n try {\n source.stop();\n } catch {\n // Already stopped.\n }\n }\n this.activeSources.clear();\n if (this.playbackContext) this.playbackTime = this.playbackContext.currentTime;\n this.publish(\"inactive\");\n }\n\n playbackOffsetMs(): number {\n return this.playbackContext\n ? Math.max(0, (this.playbackContext.currentTime - this.playbackStartedAt) * 1000)\n : 0;\n }\n\n audibleOutputState(): CodexRealtimeAudibleOutputState {\n return this.outputState;\n }\n\n setMuted(muted: boolean): void {\n this.muted = muted;\n const context = this.playbackContext;\n const gain = this.playbackGain;\n if (context && gain) gain.gain.setValueAtTime(muted ? 0 : 1, context.currentTime);\n }\n\n isPlaying(): boolean {\n return this.activeSources.size > 0;\n }\n\n async resume(): Promise<boolean> {\n const context = (this.playbackContext ??= new AudioContext({ sampleRate: AUDIO_SAMPLE_RATE }));\n this.publish(\"pending\");\n try {\n await context.resume();\n this.publish(this.activeSources.size > 0 ? \"audible\" : \"inactive\");\n return true;\n } catch {\n this.publish(\"blocked\");\n return false;\n }\n }\n\n dispose(): void {\n this.captureProcessor?.disconnect();\n this.captureSource?.disconnect();\n void this.captureContext?.close();\n this.captureProcessor = null;\n this.captureSource = null;\n this.captureContext = null;\n this.stopPlayback();\n this.playbackGain?.disconnect();\n void this.playbackContext?.close();\n this.playbackGain = null;\n this.playbackContext = null;\n }\n\n private outputNode(context: AudioContext): GainNode {\n if (!this.playbackGain) {\n this.playbackGain = context.createGain();\n this.playbackGain.gain.value = this.muted ? 0 : 1;\n this.playbackGain.connect(context.destination);\n }\n return this.playbackGain;\n }\n\n private publish(state: CodexRealtimeAudibleOutputState): void {\n if (state === this.outputState) return;\n this.outputState = state;\n this.options.onAudibleOutputState(state);\n }\n}\n\nfunction send(websocket: WebSocket, event: GatewayClientEvent): void {\n if (websocket.readyState !== WebSocket.OPEN) return;\n websocket.send(JSON.stringify(event));\n}\n\nfunction delegationRequest(argumentsJson: string): string {\n try {\n const parsed = JSON.parse(argumentsJson) as unknown;\n if (isRecord(parsed) && typeof parsed.request === \"string\" && parsed.request.trim()) {\n return parsed.request.trim();\n }\n } catch {\n // Fall through to the provider's raw argument string.\n }\n return argumentsJson.trim() || \"Continue the user's current request.\";\n}\n\nfunction providerEventId(event: Record<string, unknown>): string {\n const raw = isRecord(event.raw) ? event.raw : null;\n return (\n stringValue(event.eventId) ??\n stringValue(event.event_id) ??\n stringValue(raw?.event_id) ??\n stringValue(raw?.id) ??\n crypto.randomUUID()\n );\n}\n\nfunction encodePcm16(samples: Float32Array): string {\n const bytes = new Uint8Array(samples.length * 2);\n const view = new DataView(bytes.buffer);\n for (let index = 0; index < samples.length; index += 1) {\n const sample = Math.max(-1, Math.min(1, samples[index] ?? 0));\n view.setInt16(index * 2, sample < 0 ? sample * 0x8000 : sample * 0x7fff, true);\n }\n let binary = \"\";\n for (let start = 0; start < bytes.length; start += 0x8000) {\n binary += String.fromCharCode(...bytes.subarray(start, start + 0x8000));\n }\n return btoa(binary);\n}\n\nfunction decodePcm16(encoded: string): Float32Array {\n const binary = atob(encoded);\n const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n const samples = new Float32Array(Math.floor(bytes.byteLength / 2));\n for (let index = 0; index < samples.length; index += 1) {\n samples[index] = view.getInt16(index * 2, true) / 32768;\n }\n return samples;\n}\n\nfunction resample(input: Float32Array, inputRate: number, outputRate: number): Float32Array {\n if (inputRate === outputRate) return input;\n const ratio = inputRate / outputRate;\n const output = new Float32Array(Math.round(input.length / ratio));\n for (let index = 0; index < output.length; index += 1) {\n const source = index * ratio;\n const floor = Math.floor(source);\n const ceil = Math.min(floor + 1, input.length - 1);\n const fraction = source - floor;\n output[index] = (input[floor] ?? 0) * (1 - fraction) + (input[ceil] ?? 0) * fraction;\n }\n return output;\n}\n\nasync function waitForWebSocketOpen(websocket: WebSocket, signal: AbortSignal): Promise<void> {\n if (websocket.readyState === WebSocket.OPEN) return;\n await new Promise<void>((resolve, reject) => {\n const cleanup = (): void => {\n websocket.removeEventListener(\"open\", onOpen);\n websocket.removeEventListener(\"error\", onError);\n websocket.removeEventListener(\"close\", onClose);\n signal.removeEventListener(\"abort\", onAbort);\n };\n const onOpen = (): void => {\n cleanup();\n resolve();\n };\n const onError = (): void => {\n cleanup();\n reject(new Error(\"AI Gateway realtime WebSocket failed to open\"));\n };\n const onClose = (): void => {\n cleanup();\n reject(new Error(\"AI Gateway realtime WebSocket closed before opening\"));\n };\n const onAbort = (): void => {\n cleanup();\n reject(signal.reason ?? new DOMException(\"Aborted\", \"AbortError\"));\n };\n websocket.addEventListener(\"open\", onOpen, { once: true });\n websocket.addEventListener(\"error\", onError, { once: true });\n websocket.addEventListener(\"close\", onClose, { once: true });\n signal.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction stringValue(value: unknown): string | null {\n return typeof value === \"string\" ? value : null;\n}\n\nfunction throwIfAborted(signal: AbortSignal): void {\n if (signal.aborted) throw signal.reason ?? new DOMException(\"Aborted\", \"AbortError\");\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/gateway-realtime-transport.ts"],"sourcesContent":["import type { CodexRealtimeAudibleOutputState, CodexRealtimeWebrtcSession } from \"./codex-realtime\";\nimport type {\n CodexRealtimeControllerClient,\n RealtimeControllerTransportStarter,\n} from \"./codex-realtime-controller\";\n\ntype GatewayClientEvent = Record<string, unknown> & { type: string };\ntype GatewayServerEvent = Record<string, unknown> & { type: string };\n\nconst AUDIO_SAMPLE_RATE = 24_000;\nconst DELEGATION_TOOL = \"delegate_to_session\";\ntype RealtimeDialect = \"gateway\" | \"xai\";\n\nexport function createGatewayRealtimeTransportStarter(): RealtimeControllerTransportStarter {\n return createWebsocketRealtimeTransportStarter(\"gateway\");\n}\n\nexport function createXaiSubscriptionRealtimeTransportStarter(): RealtimeControllerTransportStarter {\n return createWebsocketRealtimeTransportStarter(\"xai\");\n}\n\nfunction createWebsocketRealtimeTransportStarter(\n dialect: RealtimeDialect,\n): RealtimeControllerTransportStarter {\n return async (input) => {\n const client = input.client as CodexRealtimeControllerClient;\n const negotiate =\n dialect === \"xai\"\n ? client.negotiateXaiSubscriptionRealtime?.bind(client)\n : client.negotiateGatewayRealtime?.bind(client);\n if (!negotiate) {\n throw new Error(\n dialect === \"xai\"\n ? \"The Opengeni client does not support connected SuperGrok realtime\"\n : \"The Opengeni client does not support AI Gateway realtime\",\n );\n }\n const answer = await negotiate(\n input.workspaceId,\n input.sessionId,\n {\n realtimeId: input.realtimeId,\n operationId: input.operationId,\n browserInstanceId: input.browserInstanceId,\n ownerKey: input.ownerKey,\n expectedVersion: input.expectedVersion,\n expectedConnectionEpoch: input.expectedConnectionEpoch,\n rotate: input.rotate,\n },\n { signal: input.signal },\n );\n throwIfAborted(input.signal);\n\n const websocket = new WebSocket(\n answer.url,\n dialect === \"xai\"\n ? [`xai-client-secret.${answer.token}`]\n : [\"ai-gateway-realtime.v1\", `ai-gateway-auth.${answer.token}`],\n );\n const channel = new GatewayRealtimeDataChannel((payload) =>\n handleBridgeOutbound(websocket, payload, dialect),\n );\n input.onEventsCreated(channel.asRtcDataChannel());\n const audio = new GatewayRealtimeAudio({\n onAudio: (encoded) =>\n send(websocket, {\n type: dialect === \"xai\" ? \"input_audio_buffer.append\" : \"input-audio-append\",\n audio: encoded,\n }),\n onAudibleOutputState: input.onAudibleOutputState,\n });\n let stopped = false;\n let currentOutputItemId: string | null = null;\n const finalizedAssistantItems = new Set<string>();\n const microphoneTracks = input.media.getAudioTracks();\n const onMicrophoneEnded = (): void => {\n if (!stopped) input.onMicrophoneEnded();\n };\n for (const track of microphoneTracks) track.addEventListener?.(\"ended\", onMicrophoneEnded);\n\n const onMessage = (event: MessageEvent): void => {\n if (typeof event.data !== \"string\") return;\n let parsed: unknown;\n try {\n parsed = JSON.parse(event.data);\n } catch {\n return;\n }\n if (!isRecord(parsed) || typeof parsed.type !== \"string\") return;\n handleRealtimeEvent({\n event: parsed as GatewayServerEvent,\n dialect,\n channel,\n websocket,\n audio,\n finalizedAssistantItems,\n getCurrentOutputItemId: () => currentOutputItemId,\n setCurrentOutputItemId: (value) => {\n currentOutputItemId = value;\n },\n });\n };\n const onClose = (): void => {\n if (!stopped) input.onConnectionHealth(\"closed\");\n };\n const onError = (): void => {\n if (!stopped) input.onConnectionHealth(\"failed\");\n };\n websocket.addEventListener(\"message\", onMessage);\n websocket.addEventListener(\"close\", onClose);\n websocket.addEventListener(\"error\", onError);\n\n const stop = (): void => {\n if (stopped) return;\n stopped = true;\n input.signal.removeEventListener(\"abort\", stop);\n websocket.removeEventListener(\"message\", onMessage);\n websocket.removeEventListener(\"close\", onClose);\n websocket.removeEventListener(\"error\", onError);\n for (const track of microphoneTracks) track.removeEventListener?.(\"ended\", onMicrophoneEnded);\n channel.close();\n audio.dispose();\n if (\n websocket.readyState === WebSocket.OPEN ||\n websocket.readyState === WebSocket.CONNECTING\n ) {\n websocket.close(1000, \"Opengeni realtime connection retired\");\n }\n };\n input.signal.addEventListener(\"abort\", stop, { once: true });\n\n try {\n await waitForWebSocketOpen(websocket, input.signal);\n channel.open();\n send(\n websocket,\n dialect === \"xai\"\n ? xaiSessionUpdate(answer.instructions)\n : gatewaySessionUpdate(answer.instructions),\n );\n for (const item of answer.initialItems) {\n const text = `<session_initial_item role=\"${item.role}\">\\n${item.text}\\n</session_initial_item>`;\n send(\n websocket,\n dialect === \"xai\"\n ? {\n type: \"conversation.item.create\",\n item: {\n type: \"message\",\n role: \"user\",\n content: [{ type: \"input_text\", text }],\n },\n }\n : {\n type: \"conversation-item-create\",\n item: { type: \"text-message\", role: \"user\", text },\n },\n );\n }\n await audio.startCapture(input.media);\n input.onConnectionHealth(\"connected\");\n } catch (error) {\n stop();\n throw error;\n }\n\n return {\n peerConnection: null as unknown as RTCPeerConnection,\n events: channel.asRtcDataChannel(),\n media: input.media,\n operationId: input.operationId,\n connectionId: answer.connectionId,\n connectionEpoch: answer.connectionEpoch,\n startupFenceSequence: answer.startupFenceSequence,\n modeVersion: answer.modeVersion,\n microphoneHealthy: () =>\n microphoneTracks.length > 0 &&\n microphoneTracks.every((track) => track.readyState !== \"ended\"),\n audibleOutputState: () => audio.audibleOutputState(),\n setOutputMuted: (muted) => audio.setMuted(muted),\n activateRemoteAudio: () => void audio.resume(),\n retryAudibleOutput: () => audio.resume(),\n stop,\n } satisfies CodexRealtimeWebrtcSession;\n };\n}\n\nfunction delegationTool(): Record<string, unknown> {\n return {\n type: \"function\",\n name: DELEGATION_TOOL,\n description:\n \"Pass execution work, actions, and session tasks to the underlying session agent. Include the complete standalone request and relevant conversational context.\",\n parameters: {\n type: \"object\",\n properties: {\n request: {\n type: \"string\",\n description: \"Complete standalone task for the session agent\",\n },\n },\n required: [\"request\"],\n additionalProperties: false,\n },\n };\n}\n\nfunction gatewaySessionUpdate(instructions: string): GatewayClientEvent {\n return {\n type: \"session-update\",\n config: {\n instructions,\n outputModalities: [\"audio\"],\n inputAudioFormat: { type: \"audio/pcm\", rate: AUDIO_SAMPLE_RATE },\n outputAudioFormat: { type: \"audio/pcm\", rate: AUDIO_SAMPLE_RATE },\n inputAudioTranscription: {},\n outputAudioTranscription: {},\n turnDetection: {\n type: \"server-vad\",\n prefixPaddingMs: 300,\n silenceDurationMs: 500,\n },\n tools: [delegationTool()],\n },\n };\n}\n\nfunction xaiSessionUpdate(instructions: string): GatewayClientEvent {\n return {\n type: \"session.update\",\n session: {\n instructions,\n voice: \"eve\",\n reasoning: { effort: \"high\" },\n turn_detection: {\n type: \"server_vad\",\n prefix_padding_ms: 300,\n silence_duration_ms: 500,\n },\n audio: {\n input: {\n format: { type: \"audio/pcm\", rate: AUDIO_SAMPLE_RATE },\n transcription: { model: \"grok-transcribe\" },\n },\n output: { format: { type: \"audio/pcm\", rate: AUDIO_SAMPLE_RATE } },\n },\n tools: [delegationTool()],\n },\n };\n}\n\nfunction handleRealtimeEvent(input: {\n event: GatewayServerEvent;\n dialect: RealtimeDialect;\n channel: GatewayRealtimeDataChannel;\n websocket: WebSocket;\n audio: GatewayRealtimeAudio;\n finalizedAssistantItems: Set<string>;\n getCurrentOutputItemId(): string | null;\n setCurrentOutputItemId(value: string | null): void;\n}): void {\n const event = input.event;\n const eventId = providerEventId(event);\n if (event.type === \"session-created\" || event.type === \"session.created\") {\n const session = isRecord(event.session) ? event.session : null;\n const sessionId =\n stringValue(event.sessionId) ?? stringValue(session?.id) ?? `realtime-${crypto.randomUUID()}`;\n input.channel.providerEvent({\n type: \"session.started\",\n event_id: eventId,\n session: { id: sessionId },\n });\n return;\n }\n if (event.type === \"speech-started\" || event.type === \"input_audio_buffer.speech_started\") {\n const itemId = input.getCurrentOutputItemId();\n if (itemId && input.audio.isPlaying()) {\n const audioEndMs = input.audio.playbackOffsetMs();\n input.audio.stopPlayback();\n send(\n input.websocket,\n input.dialect === \"xai\"\n ? {\n type: \"conversation.item.truncate\",\n item_id: itemId,\n content_index: 0,\n audio_end_ms: Math.max(0, Math.round(audioEndMs)),\n }\n : {\n type: \"conversation-item-truncate\",\n itemId,\n contentIndex: 0,\n audioEndMs: Math.max(0, Math.round(audioEndMs)),\n },\n );\n }\n return;\n }\n if (\n event.type === \"input-transcription-completed\" ||\n event.type === \"conversation.item.input_audio_transcription.completed\"\n ) {\n const transcript = stringValue(event.transcript) ?? \"\";\n const itemId = stringValue(event.itemId) ?? stringValue(event.item_id) ?? crypto.randomUUID();\n if (transcript.trim()) {\n input.channel.providerEvent({\n type: \"turn.done\",\n event_id: eventId,\n turn: { id: itemId, role: \"user\", transcript },\n });\n }\n return;\n }\n if (\n event.type === \"audio-delta\" ||\n event.type === \"response.output_audio.delta\" ||\n event.type === \"response.audio.delta\"\n ) {\n const delta = stringValue(event.delta);\n if (!delta) return;\n const itemId = stringValue(event.itemId) ?? stringValue(event.item_id);\n if (itemId) input.setCurrentOutputItemId(itemId);\n input.audio.play(delta);\n input.channel.providerEvent({ type: \"output_audio.delta\", event_id: eventId, audio: delta });\n return;\n }\n if (\n event.type === \"audio-transcript-done\" ||\n event.type === \"text-done\" ||\n event.type === \"response.output_audio_transcript.done\" ||\n event.type === \"response.audio_transcript.done\" ||\n event.type === \"response.output_text.done\"\n ) {\n const itemId = stringValue(event.itemId) ?? stringValue(event.item_id) ?? crypto.randomUUID();\n const transcript = stringValue(event.transcript) ?? stringValue(event.text) ?? \"\";\n if (transcript.trim() && !input.finalizedAssistantItems.has(itemId)) {\n input.finalizedAssistantItems.add(itemId);\n input.channel.providerEvent({\n type: \"turn.done\",\n event_id: eventId,\n turn: { id: itemId, role: \"assistant\", transcript },\n });\n }\n return;\n }\n if (event.type === \"audio-done\" || event.type === \"response.output_audio.done\") return;\n if (\n event.type === \"function-call-arguments-done\" ||\n event.type === \"response.function_call_arguments.done\"\n ) {\n const callId =\n stringValue(event.callId) ??\n stringValue(event.call_id) ??\n stringValue(event.itemId) ??\n stringValue(event.item_id) ??\n crypto.randomUUID();\n const name = stringValue(event.name);\n if (name !== DELEGATION_TOOL) {\n sendFunctionOutput(\n input.websocket,\n input.dialect,\n callId,\n name,\n JSON.stringify({ error: \"Unsupported realtime tool\" }),\n );\n sendResponseCreate(input.websocket, input.dialect);\n return;\n }\n const request = delegationRequest(stringValue(event.arguments) ?? \"\");\n input.channel.providerEvent({\n type: \"delegation.created\",\n event_id: eventId,\n item: {\n id: callId,\n type: \"delegation\",\n target: \"client\",\n content: [{ type: \"input_text\", text: request }],\n },\n });\n return;\n }\n if (event.type === \"error\") {\n const nested = isRecord(event.error) ? event.error : null;\n input.channel.providerEvent({\n type: \"error\",\n event_id: eventId,\n message:\n stringValue(event.message) ?? stringValue(nested?.message) ?? \"Realtime provider error\",\n });\n }\n}\n\nclass GatewayRealtimeDataChannel extends EventTarget {\n readyState: RTCDataChannelState = \"connecting\";\n private pendingOutbound: Array<Record<string, unknown>> = [];\n private outboundScheduled = false;\n\n constructor(private readonly outbound: (messages: Array<Record<string, unknown>>) => void) {\n super();\n }\n\n asRtcDataChannel(): RTCDataChannel {\n return this as unknown as RTCDataChannel;\n }\n\n open(): void {\n this.readyState = \"open\";\n this.dispatchEvent(new Event(\"open\"));\n }\n\n send(payload: string): void {\n if (this.readyState !== \"open\") throw new Error(\"Gateway realtime channel is not open\");\n let parsed: unknown;\n try {\n parsed = JSON.parse(payload);\n } catch {\n return;\n }\n if (!isRecord(parsed)) return;\n this.pendingOutbound.push(parsed);\n if (this.outboundScheduled) return;\n this.outboundScheduled = true;\n queueMicrotask(() => {\n this.outboundScheduled = false;\n const messages = this.pendingOutbound;\n this.pendingOutbound = [];\n if (messages.length > 0 && this.readyState === \"open\") this.outbound(messages);\n });\n }\n\n providerEvent(event: Record<string, unknown>): void {\n if (this.readyState === \"closed\") return;\n this.dispatchEvent(new MessageEvent(\"message\", { data: JSON.stringify(event) }));\n }\n\n close(): void {\n if (this.readyState === \"closed\") return;\n this.readyState = \"closed\";\n this.pendingOutbound = [];\n this.dispatchEvent(new Event(\"close\"));\n }\n}\n\nfunction handleBridgeOutbound(\n websocket: WebSocket,\n messages: Array<Record<string, unknown>>,\n dialect: RealtimeDialect,\n): void {\n const groups = new Map<\n string,\n { type: string; id: string | null; channel: string; text: string }\n >();\n for (const message of messages) {\n const type = stringValue(message.type);\n if (type !== \"session.context.append\" && type !== \"delegation.context.append\") continue;\n const id = stringValue(message.delegation_item_id) ?? null;\n const channel = stringValue(message.channel) ?? \"commentary\";\n const key = `${type}:${id ?? \"session\"}:${channel}`;\n const content = Array.isArray(message.content) ? message.content : [];\n const text = content\n .filter(isRecord)\n .map((part) => stringValue(part.text) ?? \"\")\n .join(\"\");\n const existing = groups.get(key);\n groups.set(key, {\n type,\n id,\n channel,\n text: `${existing?.text ?? \"\"}${text}`,\n });\n }\n for (const group of groups.values()) {\n if (group.type === \"delegation.context.append\" && group.id && group.channel === \"speakable\") {\n sendFunctionOutput(\n websocket,\n dialect,\n group.id,\n DELEGATION_TOOL,\n JSON.stringify({ result: group.text }),\n );\n sendResponseCreate(websocket, dialect);\n continue;\n }\n const wrapper =\n group.type === \"delegation.context.append\"\n ? group.channel === \"commentary\"\n ? \"execution_progress\"\n : \"execution_result\"\n : \"session_update\";\n const text = `<${wrapper}>\\n${group.text}\\n</${wrapper}>`;\n send(\n websocket,\n dialect === \"xai\"\n ? {\n type: \"conversation.item.create\",\n item: {\n type: \"message\",\n role: \"user\",\n content: [{ type: \"input_text\", text }],\n },\n }\n : {\n type: \"conversation-item-create\",\n item: { type: \"text-message\", role: \"user\", text },\n },\n );\n if (group.channel === \"speakable\") sendResponseCreate(websocket, dialect);\n }\n}\n\nfunction sendFunctionOutput(\n websocket: WebSocket,\n dialect: RealtimeDialect,\n callId: string,\n name: string | null,\n output: string,\n): void {\n send(\n websocket,\n dialect === \"xai\"\n ? {\n type: \"conversation.item.create\",\n item: { type: \"function_call_output\", call_id: callId, output },\n }\n : {\n type: \"conversation-item-create\",\n item: { type: \"function-call-output\", callId, name, output },\n },\n );\n}\n\nfunction sendResponseCreate(websocket: WebSocket, dialect: RealtimeDialect): void {\n send(websocket, { type: dialect === \"xai\" ? \"response.create\" : \"response-create\" });\n}\n\nclass GatewayRealtimeAudio {\n private captureContext: AudioContext | null = null;\n private captureSource: MediaStreamAudioSourceNode | null = null;\n private captureProcessor: ScriptProcessorNode | null = null;\n private playbackContext: AudioContext | null = null;\n private playbackGain: GainNode | null = null;\n private playbackTime = 0;\n private playbackStartedAt = 0;\n private activeSources = new Set<AudioBufferSourceNode>();\n private outputState: CodexRealtimeAudibleOutputState = \"inactive\";\n private muted = false;\n\n constructor(\n private readonly options: {\n onAudio(audio: string): void;\n onAudibleOutputState(state: CodexRealtimeAudibleOutputState): void;\n },\n ) {}\n\n async startCapture(media: MediaStream): Promise<void> {\n const context = new AudioContext({ sampleRate: AUDIO_SAMPLE_RATE });\n this.captureContext = context;\n const source = context.createMediaStreamSource(media);\n const processor = context.createScriptProcessor(4096, 1, 1);\n this.captureSource = source;\n this.captureProcessor = processor;\n processor.onaudioprocess = (event) => {\n const samples = resample(\n new Float32Array(event.inputBuffer.getChannelData(0)),\n context.sampleRate,\n AUDIO_SAMPLE_RATE,\n );\n this.options.onAudio(encodePcm16(samples));\n };\n source.connect(processor);\n processor.connect(context.destination);\n await context.resume();\n }\n\n play(encoded: string): void {\n const context = (this.playbackContext ??= new AudioContext({ sampleRate: AUDIO_SAMPLE_RATE }));\n if (context.state !== \"running\") {\n void this.resume().then((resumed) => {\n if (resumed) this.schedule(encoded);\n });\n return;\n }\n this.schedule(encoded);\n }\n\n private schedule(encoded: string): void {\n const context = this.playbackContext;\n if (!context) return;\n const samples = decodePcm16(encoded);\n const buffer = context.createBuffer(1, samples.length, AUDIO_SAMPLE_RATE);\n buffer.getChannelData(0).set(samples);\n const source = context.createBufferSource();\n source.buffer = buffer;\n source.connect(this.outputNode(context));\n const startAt = Math.max(context.currentTime, this.playbackTime);\n if (this.activeSources.size === 0) this.playbackStartedAt = startAt;\n source.start(startAt);\n this.playbackTime = startAt + buffer.duration;\n this.activeSources.add(source);\n this.publish(\"audible\");\n source.onended = () => {\n this.activeSources.delete(source);\n if (this.activeSources.size === 0) this.publish(\"inactive\");\n };\n }\n\n stopPlayback(): void {\n for (const source of this.activeSources) {\n try {\n source.stop();\n } catch {\n // Already stopped.\n }\n }\n this.activeSources.clear();\n if (this.playbackContext) this.playbackTime = this.playbackContext.currentTime;\n this.publish(\"inactive\");\n }\n\n playbackOffsetMs(): number {\n return this.playbackContext\n ? Math.max(0, (this.playbackContext.currentTime - this.playbackStartedAt) * 1000)\n : 0;\n }\n\n audibleOutputState(): CodexRealtimeAudibleOutputState {\n return this.outputState;\n }\n\n setMuted(muted: boolean): void {\n this.muted = muted;\n const context = this.playbackContext;\n const gain = this.playbackGain;\n if (context && gain) gain.gain.setValueAtTime(muted ? 0 : 1, context.currentTime);\n }\n\n isPlaying(): boolean {\n return this.activeSources.size > 0;\n }\n\n async resume(): Promise<boolean> {\n const context = (this.playbackContext ??= new AudioContext({ sampleRate: AUDIO_SAMPLE_RATE }));\n this.publish(\"pending\");\n try {\n await context.resume();\n this.publish(this.activeSources.size > 0 ? \"audible\" : \"inactive\");\n return true;\n } catch {\n this.publish(\"blocked\");\n return false;\n }\n }\n\n dispose(): void {\n this.captureProcessor?.disconnect();\n this.captureSource?.disconnect();\n void this.captureContext?.close();\n this.captureProcessor = null;\n this.captureSource = null;\n this.captureContext = null;\n this.stopPlayback();\n this.playbackGain?.disconnect();\n void this.playbackContext?.close();\n this.playbackGain = null;\n this.playbackContext = null;\n }\n\n private outputNode(context: AudioContext): GainNode {\n if (!this.playbackGain) {\n this.playbackGain = context.createGain();\n this.playbackGain.gain.value = this.muted ? 0 : 1;\n this.playbackGain.connect(context.destination);\n }\n return this.playbackGain;\n }\n\n private publish(state: CodexRealtimeAudibleOutputState): void {\n if (state === this.outputState) return;\n this.outputState = state;\n this.options.onAudibleOutputState(state);\n }\n}\n\nfunction send(websocket: WebSocket, event: GatewayClientEvent): void {\n if (websocket.readyState !== WebSocket.OPEN) return;\n websocket.send(JSON.stringify(event));\n}\n\nfunction delegationRequest(argumentsJson: string): string {\n try {\n const parsed = JSON.parse(argumentsJson) as unknown;\n if (isRecord(parsed) && typeof parsed.request === \"string\" && parsed.request.trim()) {\n return parsed.request.trim();\n }\n } catch {\n // Fall through to the provider's raw argument string.\n }\n return argumentsJson.trim() || \"Continue the user's current request.\";\n}\n\nfunction providerEventId(event: Record<string, unknown>): string {\n const raw = isRecord(event.raw) ? event.raw : null;\n return (\n stringValue(event.eventId) ??\n stringValue(event.event_id) ??\n stringValue(raw?.event_id) ??\n stringValue(raw?.id) ??\n crypto.randomUUID()\n );\n}\n\nfunction encodePcm16(samples: Float32Array): string {\n const bytes = new Uint8Array(samples.length * 2);\n const view = new DataView(bytes.buffer);\n for (let index = 0; index < samples.length; index += 1) {\n const sample = Math.max(-1, Math.min(1, samples[index] ?? 0));\n view.setInt16(index * 2, sample < 0 ? sample * 0x8000 : sample * 0x7fff, true);\n }\n let binary = \"\";\n for (let start = 0; start < bytes.length; start += 0x8000) {\n binary += String.fromCharCode(...bytes.subarray(start, start + 0x8000));\n }\n return btoa(binary);\n}\n\nfunction decodePcm16(encoded: string): Float32Array {\n const binary = atob(encoded);\n const bytes = Uint8Array.from(binary, (character) => character.charCodeAt(0));\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n const samples = new Float32Array(Math.floor(bytes.byteLength / 2));\n for (let index = 0; index < samples.length; index += 1) {\n samples[index] = view.getInt16(index * 2, true) / 32768;\n }\n return samples;\n}\n\nfunction resample(input: Float32Array, inputRate: number, outputRate: number): Float32Array {\n if (inputRate === outputRate) return input;\n const ratio = inputRate / outputRate;\n const output = new Float32Array(Math.round(input.length / ratio));\n for (let index = 0; index < output.length; index += 1) {\n const source = index * ratio;\n const floor = Math.floor(source);\n const ceil = Math.min(floor + 1, input.length - 1);\n const fraction = source - floor;\n output[index] = (input[floor] ?? 0) * (1 - fraction) + (input[ceil] ?? 0) * fraction;\n }\n return output;\n}\n\nasync function waitForWebSocketOpen(websocket: WebSocket, signal: AbortSignal): Promise<void> {\n if (websocket.readyState === WebSocket.OPEN) return;\n await new Promise<void>((resolve, reject) => {\n const cleanup = (): void => {\n websocket.removeEventListener(\"open\", onOpen);\n websocket.removeEventListener(\"error\", onError);\n websocket.removeEventListener(\"close\", onClose);\n signal.removeEventListener(\"abort\", onAbort);\n };\n const onOpen = (): void => {\n cleanup();\n resolve();\n };\n const onError = (): void => {\n cleanup();\n reject(new Error(\"AI Gateway realtime WebSocket failed to open\"));\n };\n const onClose = (): void => {\n cleanup();\n reject(new Error(\"AI Gateway realtime WebSocket closed before opening\"));\n };\n const onAbort = (): void => {\n cleanup();\n reject(signal.reason ?? new DOMException(\"Aborted\", \"AbortError\"));\n };\n websocket.addEventListener(\"open\", onOpen, { once: true });\n websocket.addEventListener(\"error\", onError, { once: true });\n websocket.addEventListener(\"close\", onClose, { once: true });\n signal.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction stringValue(value: unknown): string | null {\n return typeof value === \"string\" ? value : null;\n}\n\nfunction throwIfAborted(signal: AbortSignal): void {\n if (signal.aborted) throw signal.reason ?? new DOMException(\"Aborted\", \"AbortError\");\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import {
|
|
2
|
+
OpenGeniApiError
|
|
3
|
+
} from "./chunk-V6GIY62B.js";
|
|
4
|
+
|
|
5
|
+
// src/chat/ids.ts
|
|
6
|
+
var CHAT_SESSION_NAMESPACE = "7c1e6d3a-5b2f-4e8a-9d4c-0f3b6a8e2c17";
|
|
7
|
+
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
8
|
+
async function uuidV5(name, namespace) {
|
|
9
|
+
const namespaceBytes = parseUuid(namespace);
|
|
10
|
+
const nameBytes = new TextEncoder().encode(name);
|
|
11
|
+
const input = new Uint8Array(namespaceBytes.length + nameBytes.length);
|
|
12
|
+
input.set(namespaceBytes, 0);
|
|
13
|
+
input.set(nameBytes, namespaceBytes.length);
|
|
14
|
+
const digest = new Uint8Array(await crypto.subtle.digest("SHA-1", input)).slice(0, 16);
|
|
15
|
+
digest[6] = (digest[6] ?? 0) & 15 | 80;
|
|
16
|
+
digest[8] = (digest[8] ?? 0) & 63 | 128;
|
|
17
|
+
return formatUuid(digest);
|
|
18
|
+
}
|
|
19
|
+
async function chatSessionId(workspaceId, conversation, user) {
|
|
20
|
+
return await uuidV5(chatIdentityName(workspaceId, conversation, user), CHAT_SESSION_NAMESPACE);
|
|
21
|
+
}
|
|
22
|
+
function chatIdentityName(workspaceId, conversation, user) {
|
|
23
|
+
return JSON.stringify(
|
|
24
|
+
user ? [workspaceId, user.source, user.id, conversation] : [workspaceId, conversation]
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
function chatIdempotencyKey(sessionId) {
|
|
28
|
+
return `chat:${sessionId}`;
|
|
29
|
+
}
|
|
30
|
+
function isUuid(value) {
|
|
31
|
+
return UUID_PATTERN.test(value);
|
|
32
|
+
}
|
|
33
|
+
function parseUuid(value) {
|
|
34
|
+
if (!UUID_PATTERN.test(value)) {
|
|
35
|
+
throw new TypeError(`Invalid UUID namespace: ${value}`);
|
|
36
|
+
}
|
|
37
|
+
const hex = value.replace(/-/g, "");
|
|
38
|
+
const bytes = new Uint8Array(16);
|
|
39
|
+
for (let index = 0; index < 16; index += 1) {
|
|
40
|
+
bytes[index] = Number.parseInt(hex.slice(index * 2, index * 2 + 2), 16);
|
|
41
|
+
}
|
|
42
|
+
return bytes;
|
|
43
|
+
}
|
|
44
|
+
function formatUuid(bytes) {
|
|
45
|
+
const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
46
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/tenant-workspaces.ts
|
|
50
|
+
var ISOLATION_NAMESPACE = "fc398712-b4db-5b0b-8842-57cb4f2a65f9";
|
|
51
|
+
var CONVERSATION_PERMISSIONS = [
|
|
52
|
+
"workspace:read",
|
|
53
|
+
"sessions:create",
|
|
54
|
+
"sessions:read",
|
|
55
|
+
"sessions:control",
|
|
56
|
+
"files:upload",
|
|
57
|
+
"files:read",
|
|
58
|
+
"mcp_servers:attach"
|
|
59
|
+
];
|
|
60
|
+
function createWorkspaceIdResolver(client, options) {
|
|
61
|
+
const memberPermissions = [...options.memberPermissions ?? CONVERSATION_PERMISSIONS];
|
|
62
|
+
const cache = /* @__PURE__ */ new Map();
|
|
63
|
+
const organizationId = async () => typeof options.organizationId === "function" ? await options.organizationId() : options.organizationId;
|
|
64
|
+
return async (target, resolution) => {
|
|
65
|
+
const isolated = resolution.isolation === "user";
|
|
66
|
+
if (!isolated && !target.tenant) throw new TypeError("workspaceIdFor requires a tenant.");
|
|
67
|
+
if (isolated && !target.user) {
|
|
68
|
+
throw new TypeError("User isolation requires an authenticated product user.");
|
|
69
|
+
}
|
|
70
|
+
const source = target.source ?? options.source;
|
|
71
|
+
const key = target.tenant ? JSON.stringify([
|
|
72
|
+
resolution.isolation,
|
|
73
|
+
options.source,
|
|
74
|
+
source,
|
|
75
|
+
target.tenant,
|
|
76
|
+
isolated ? target.user : null
|
|
77
|
+
]) : JSON.stringify(["user", options.source, source, target.user]);
|
|
78
|
+
let pending = cache.get(key);
|
|
79
|
+
if (!pending) {
|
|
80
|
+
pending = (async () => {
|
|
81
|
+
const productSource = options.source.trim();
|
|
82
|
+
const isolatedSource = `opengeni-sdk:user-isolation:${await uuidV5(productSource, ISOLATION_NAMESPACE)}`;
|
|
83
|
+
const label = target.tenant ?? target.user;
|
|
84
|
+
const { workspace } = await client.ensureWorkspace({
|
|
85
|
+
accountId: await organizationId(),
|
|
86
|
+
externalSource: isolated ? isolatedSource === productSource ? `${isolatedSource}:user` : isolatedSource : options.source,
|
|
87
|
+
externalId: isolated ? await uuidV5(key, ISOLATION_NAMESPACE) : target.tenant,
|
|
88
|
+
name: options.workspaceName?.(label) ?? label
|
|
89
|
+
});
|
|
90
|
+
if (isolated) {
|
|
91
|
+
try {
|
|
92
|
+
await client.addExternalWorkspaceMember(workspace.id, {
|
|
93
|
+
identity: { source, externalId: target.user },
|
|
94
|
+
permissions: [...memberPermissions],
|
|
95
|
+
operationId: await uuidV5(
|
|
96
|
+
JSON.stringify(["member", workspace.id, source, target.user]),
|
|
97
|
+
ISOLATION_NAMESPACE
|
|
98
|
+
)
|
|
99
|
+
});
|
|
100
|
+
} catch (error) {
|
|
101
|
+
if (!(error instanceof OpenGeniApiError) || error.status !== 409 || error.code !== "conflict" || error.outcomeUnknown)
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return workspace.id;
|
|
106
|
+
})();
|
|
107
|
+
pending.catch(() => {
|
|
108
|
+
if (cache.get(key) === pending) cache.delete(key);
|
|
109
|
+
});
|
|
110
|
+
if (cache.size >= 1e3) cache.delete(cache.keys().next().value);
|
|
111
|
+
cache.set(key, pending);
|
|
112
|
+
}
|
|
113
|
+
return await pending;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export {
|
|
118
|
+
CHAT_SESSION_NAMESPACE,
|
|
119
|
+
uuidV5,
|
|
120
|
+
chatSessionId,
|
|
121
|
+
chatIdentityName,
|
|
122
|
+
chatIdempotencyKey,
|
|
123
|
+
isUuid,
|
|
124
|
+
createWorkspaceIdResolver
|
|
125
|
+
};
|
|
126
|
+
//# sourceMappingURL=chunk-LY2K6ELJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/chat/ids.ts","../src/tenant-workspaces.ts"],"sourcesContent":["/**\n * Deterministic chat identities. A conversation id maps to exactly one\n * session id per workspace, so any process can address the same session\n * without storing a mapping, and a double-submitted create collapses through\n * the idempotency key. The optional legacy label argument is retained only to\n * reproduce historical addresses. New chat calls do not use it: authorization\n * is independent of addressing, so collaborators can share a conversation.\n */\n\n/** The end-user label a conversation is namespaced to: the product `source` plus the opaque user id. */\nexport type ChatUserLabel = { source: string; id: string };\n\n/** Fixed RFC 4122 namespace for chat session ids. Never change it. */\nexport const CHAT_SESSION_NAMESPACE = \"7c1e6d3a-5b2f-4e8a-9d4c-0f3b6a8e2c17\";\n\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/** RFC 4122 version 5 (SHA-1) UUID of `name` inside `namespace`. */\nexport async function uuidV5(name: string, namespace: string): Promise<string> {\n const namespaceBytes = parseUuid(namespace);\n const nameBytes = new TextEncoder().encode(name);\n const input = new Uint8Array(namespaceBytes.length + nameBytes.length);\n input.set(namespaceBytes, 0);\n input.set(nameBytes, namespaceBytes.length);\n const digest = new Uint8Array(await crypto.subtle.digest(\"SHA-1\", input)).slice(0, 16);\n digest[6] = ((digest[6] ?? 0) & 0x0f) | 0x50;\n digest[8] = ((digest[8] ?? 0) & 0x3f) | 0x80;\n return formatUuid(digest);\n}\n\n/**\n * The session id of `conversation` in `workspaceId`: RFC 4122 v5 of the JSON\n * tuple `[workspaceId, conversation]`, or `[workspaceId, source, id, conversation]`\n * when the conversation belongs to an end user. JSON encoding keeps the tuple\n * unambiguous: an id containing `:` or any other delimiter can never make two\n * different (user, conversation) pairs share a session.\n */\nexport async function chatSessionId(\n workspaceId: string,\n conversation: string,\n user?: ChatUserLabel | undefined,\n): Promise<string> {\n return await uuidV5(chatIdentityName(workspaceId, conversation, user), CHAT_SESSION_NAMESPACE);\n}\n\n/** The exact v5 name behind {@link chatSessionId}; exported for tests and audits. */\nexport function chatIdentityName(\n workspaceId: string,\n conversation: string,\n user?: ChatUserLabel | undefined,\n): string {\n return JSON.stringify(\n user ? [workspaceId, user.source, user.id, conversation] : [workspaceId, conversation],\n );\n}\n\n/**\n * The create idempotency key for a chat session: `chat:<sessionId>`. The\n * session id already encodes the workspace, user label, and conversation as an\n * unambiguous tuple, so the key inherits that and stays bounded.\n */\nexport function chatIdempotencyKey(sessionId: string): string {\n return `chat:${sessionId}`;\n}\n\nexport function isUuid(value: string): boolean {\n return UUID_PATTERN.test(value);\n}\n\nfunction parseUuid(value: string): Uint8Array {\n if (!UUID_PATTERN.test(value)) {\n throw new TypeError(`Invalid UUID namespace: ${value}`);\n }\n const hex = value.replace(/-/g, \"\");\n const bytes = new Uint8Array(16);\n for (let index = 0; index < 16; index += 1) {\n bytes[index] = Number.parseInt(hex.slice(index * 2, index * 2 + 2), 16);\n }\n return bytes;\n}\n\nfunction formatUuid(bytes: Uint8Array): string {\n const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, \"0\")).join(\"\");\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;\n}\n","import type { OpenGeniEmbeddingClient } from \"./embedding-client\";\nimport type { Permission } from \"./types\";\nimport { OpenGeniApiError } from \"./errors\";\nimport { uuidV5 } from \"./chat/ids\";\n\nconst ISOLATION_NAMESPACE = \"fc398712-b4db-5b0b-8842-57cb4f2a65f9\";\n/**\n * Conversation-only member permissions. The API grants exactly this set when\n * an organization key first acts as a user on a workspace (keep equal to\n * `EXTERNAL_FIRST_USE_MEMBER_PERMISSIONS` in `packages/core/src/access`).\n */\nconst CONVERSATION_PERMISSIONS = [\n \"workspace:read\",\n \"sessions:create\",\n \"sessions:read\",\n \"sessions:control\",\n \"files:upload\",\n \"files:read\",\n \"mcp_servers:attach\",\n] as const;\n\nexport type WorkspaceIdTarget = {\n /**\n * Your tenant id. With user isolation and no tenant, the user gets one\n * workspace of their own, independent of any tenant.\n */\n tenant?: string | undefined;\n user?: string | undefined;\n /** External user identity source; defaults to the resolver's source. */\n source?: string | undefined;\n};\n\nexport type WorkspaceIdOptions = {\n /**\n * `tenant`: one workspace per tenant. `user`: a separate workspace for the\n * user (per tenant when a tenant is given, otherwise one per user).\n */\n isolation: \"tenant\" | \"user\";\n};\n\nexport type WorkspaceIdResolverOptions = {\n /** The organization id, or a lazy lookup (for example derived from the API key). */\n organizationId: string | (() => Promise<string>);\n source: string;\n /** Workspace display name; receives the tenant id, or the user id for a per-user workspace. */\n workspaceName?: ((tenant: string) => string) | undefined;\n /**\n * Per-user workspaces only (user isolation): permissions for the one member\n * this resolver adds explicitly, its owner. Replaces the defaults: workspace\n * read, session create/read/control (including sending messages), file\n * upload/read, and attaching the host's per-session MCP servers. No admin\n * permissions are granted by default. Tenant workspaces rely on the API,\n * which adds a missing member with those defaults on their first request.\n * Existing grants are never changed here; change them with\n * `updateExternalWorkspaceMember`. The organization API key must also allow\n * the selected permissions.\n */\n memberPermissions?: readonly Permission[] | undefined;\n};\n\n/**\n * Server-only workspace resolution using external workspace provisioning.\n * Workspaces are created on first use and cached. A tenant workspace's members\n * are added by the API on their first `asUser` request (the organization key\n * needs `members:manage`). A per-user workspace stays single-user: the API\n * never auto-admits anyone there, and this resolver adds its owner with a\n * stable onboarding key, so retries never restore a revoked grant.\n */\nexport function createWorkspaceIdResolver(\n client: Pick<OpenGeniEmbeddingClient, \"ensureWorkspace\" | \"addExternalWorkspaceMember\">,\n options: WorkspaceIdResolverOptions,\n): (target: WorkspaceIdTarget, resolution: WorkspaceIdOptions) => Promise<string> {\n const memberPermissions = [...(options.memberPermissions ?? CONVERSATION_PERMISSIONS)];\n const cache = new Map<string, Promise<string>>();\n const organizationId = async () =>\n typeof options.organizationId === \"function\"\n ? await options.organizationId()\n : options.organizationId;\n return async (target, resolution) => {\n const isolated = resolution.isolation === \"user\";\n if (!isolated && !target.tenant) throw new TypeError(\"workspaceIdFor requires a tenant.\");\n if (isolated && !target.user) {\n throw new TypeError(\"User isolation requires an authenticated product user.\");\n }\n const source = target.source ?? options.source;\n // A per-user workspace without a tenant has its own key shape, so it can\n // never alias a tenant-scoped isolated workspace.\n const key = target.tenant\n ? JSON.stringify([\n resolution.isolation,\n options.source,\n source,\n target.tenant,\n isolated ? target.user : null,\n ])\n : JSON.stringify([\"user\", options.source, source, target.user]);\n let pending = cache.get(key);\n if (!pending) {\n pending = (async () => {\n const productSource = options.source.trim();\n const isolatedSource = `opengeni-sdk:user-isolation:${await uuidV5(productSource, ISOLATION_NAMESPACE)}`;\n const label = target.tenant ?? target.user!;\n const { workspace } = await client.ensureWorkspace({\n accountId: await organizationId(),\n externalSource: isolated\n ? isolatedSource === productSource\n ? `${isolatedSource}:user`\n : isolatedSource\n : options.source,\n externalId: isolated ? await uuidV5(key, ISOLATION_NAMESPACE) : target.tenant!,\n name: options.workspaceName?.(label) ?? label,\n });\n if (isolated) {\n try {\n await client.addExternalWorkspaceMember(workspace.id, {\n identity: { source, externalId: target.user! },\n permissions: [...memberPermissions],\n operationId: await uuidV5(\n JSON.stringify([\"member\", workspace.id, source, target.user]),\n ISOLATION_NAMESPACE,\n ),\n });\n } catch (error) {\n // Defaults/custom permissions may have changed since this stable\n // onboarding key committed, or the grant may have been cancelled.\n // A definitive conflict must never mint a new key or update access.\n // Return only the address: every asUser operation still checks the\n // live membership, including reduced or withdrawn permissions.\n if (\n !(error instanceof OpenGeniApiError) ||\n error.status !== 409 ||\n error.code !== \"conflict\" ||\n error.outcomeUnknown\n )\n throw error;\n }\n }\n return workspace.id;\n })();\n pending.catch(() => {\n if (cache.get(key) === pending) cache.delete(key);\n });\n if (cache.size >= 1_000) cache.delete(cache.keys().next().value!);\n cache.set(key, pending);\n }\n return await pending;\n };\n}\n"],"mappings":"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","names":[]}
|