@opengeni/sdk 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +13 -3
  2. package/dist/adapters/next.js +2 -2
  3. package/dist/artifacts.js +4 -4
  4. package/dist/azure-live-transport.d.ts +32 -0
  5. package/dist/browser.js +3 -3
  6. package/dist/chat/index.js +5 -5
  7. package/dist/{chunk-RSKO3CMZ.js → chunk-BVIIRSJY.js} +2 -2
  8. package/dist/{chunk-G5NZGPTB.js → chunk-CA2T7QT4.js} +2 -2
  9. package/dist/{chunk-ZBICMU4Z.js → chunk-D534PIXF.js} +2 -2
  10. package/dist/{chunk-CNSPJYF6.js → chunk-FYQAMXDW.js} +104 -5
  11. package/dist/chunk-FYQAMXDW.js.map +1 -0
  12. package/dist/{chunk-IB6SUE3R.js → chunk-GYM54GKM.js} +1 -1
  13. package/dist/chunk-GYM54GKM.js.map +1 -0
  14. package/dist/{chunk-VYCTL62C.js → chunk-GZQSWAKD.js} +1 -1
  15. package/dist/chunk-GZQSWAKD.js.map +1 -0
  16. package/dist/{chunk-CREM7YRK.js → chunk-LEBDXYMA.js} +2 -2
  17. package/dist/{chunk-YVH2PH4X.js → chunk-MXV5O25O.js} +2 -2
  18. package/dist/{chunk-2UXZUCEZ.js → chunk-ZNC44QEX.js} +77 -7
  19. package/dist/chunk-ZNC44QEX.js.map +1 -0
  20. package/dist/codex-realtime-controller.d.ts +13 -0
  21. package/dist/codex-realtime-controller.js +3 -1
  22. package/dist/codex-realtime-v3-wire.d.ts +3 -2
  23. package/dist/codex-realtime.d.ts +4 -0
  24. package/dist/core.js +4 -4
  25. package/dist/document-authority.js +3 -3
  26. package/dist/editable-artifacts.js +1 -1
  27. package/dist/index.d.ts +3 -2
  28. package/dist/index.js +55 -18
  29. package/dist/index.js.map +1 -1
  30. package/dist/realtime.d.ts +1 -1
  31. package/dist/realtime.js +248 -2
  32. package/dist/realtime.js.map +1 -1
  33. package/dist/session-proxy-client.d.ts +7 -3
  34. package/dist/session-proxy.d.ts +9 -1
  35. package/dist/session-proxy.js +2 -2
  36. package/dist/site.js +3 -3
  37. package/dist/transcription.d.ts +1 -1
  38. package/dist/types.d.ts +30 -8
  39. package/package.json +3 -3
  40. package/src/azure-live-transport.ts +286 -0
  41. package/src/codex-realtime-controller.ts +95 -2
  42. package/src/codex-realtime-v3-wire.ts +4 -3
  43. package/src/codex-realtime-v3.ts +11 -2
  44. package/src/codex-realtime.ts +9 -1
  45. package/src/index.ts +3 -0
  46. package/src/realtime.ts +15 -6
  47. package/src/session-proxy-client.ts +7 -3
  48. package/src/session-proxy.ts +137 -4
  49. package/src/transcription.ts +3 -0
  50. package/src/types.ts +34 -5
  51. package/dist/chunk-2UXZUCEZ.js.map +0 -1
  52. package/dist/chunk-CNSPJYF6.js.map +0 -1
  53. package/dist/chunk-IB6SUE3R.js.map +0 -1
  54. package/dist/chunk-VYCTL62C.js.map +0 -1
  55. /package/dist/{chunk-RSKO3CMZ.js.map → chunk-BVIIRSJY.js.map} +0 -0
  56. /package/dist/{chunk-G5NZGPTB.js.map → chunk-CA2T7QT4.js.map} +0 -0
  57. /package/dist/{chunk-ZBICMU4Z.js.map → chunk-D534PIXF.js.map} +0 -0
  58. /package/dist/{chunk-CREM7YRK.js.map → chunk-LEBDXYMA.js.map} +0 -0
  59. /package/dist/{chunk-YVH2PH4X.js.map → chunk-MXV5O25O.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/realtime.ts"],"sourcesContent":["/**\n * Public, provider-neutral realtime browser SDK.\n *\n * Import this subpath lazily in browser applications. The base `@opengeni/sdk`\n * entry remains free of eager realtime transport initialization.\n */\nimport {\n createCodexRealtimeController,\n hasStoredSessionRealtimeOwnerProof,\n sessionRealtimeOwnerStorageKey,\n sessionRealtimeOwnerStorageNamespace,\n type CodexRealtimeController,\n type CodexRealtimeControllerClient,\n type CodexRealtimeControllerSnapshot,\n type CodexRealtimeControllerStatus,\n type CodexRealtimeDiagnostic,\n type CodexRealtimeDiagnosticKind,\n type CodexRealtimeMicrophoneState,\n type CodexRealtimeOwnerStorage,\n type CreateCodexRealtimeControllerOptions,\n type RealtimeControllerTransportStarter,\n} from \"./codex-realtime-controller\";\nimport {\n createGatewayRealtimeTransportStarter,\n createXaiSubscriptionRealtimeTransportStarter,\n} from \"./gateway-realtime-transport\";\nimport type { SessionRealtimeModel, WorkspaceRealtimeModelCatalogResponse } from \"./types\";\n\n/** Exact backend-facing methods required by the batteries-included realtime SDK. */\nexport type SessionRealtimeClientLike = CodexRealtimeControllerClient & {\n getWorkspaceRealtimeModelCatalog(\n workspaceId: string,\n options?: { signal?: AbortSignal | undefined },\n ): Promise<WorkspaceRealtimeModelCatalogResponse>;\n};\n\nexport type SessionRealtimeTransportKind = \"codex\" | \"gateway\" | \"xai-subscription\";\n\n/** Provider-neutral names for the existing, battle-tested controller projection. */\nexport type SessionRealtimeController = CodexRealtimeController;\nexport type SessionRealtimeControllerSnapshot = CodexRealtimeControllerSnapshot;\nexport type SessionRealtimeControllerStatus = CodexRealtimeControllerStatus;\nexport type SessionRealtimeDiagnostic = CodexRealtimeDiagnostic;\nexport type SessionRealtimeDiagnosticKind = CodexRealtimeDiagnosticKind;\nexport type SessionRealtimeMicrophoneState = CodexRealtimeMicrophoneState;\nexport type SessionRealtimeOwnerStorage = CodexRealtimeOwnerStorage;\n\nexport type CreateSessionRealtimeControllerOptions = Omit<\n CreateCodexRealtimeControllerOptions,\n \"client\" | \"model\" | \"ownerStorageNamespace\" | \"startTransport\"\n> & {\n client: CodexRealtimeControllerClient;\n model: SessionRealtimeModel;\n};\n\n/** Select the existing transport without exposing provider mechanics to hosts. */\nexport function sessionRealtimeTransportKind(\n model: SessionRealtimeModel,\n): SessionRealtimeTransportKind {\n if (model === \"gpt-live-1-boulder-alpha\") return \"codex\";\n if (model === \"supergrok/grok-voice-think-fast-2.0\") return \"xai-subscription\";\n return \"gateway\";\n}\n\n/**\n * Compose the exact current controller with its existing Codex Live or AI\n * Gateway transport. Wire, ledger, delegation, recovery, and lifecycle\n * semantics remain owned by the existing implementations below this facade.\n */\nexport function createSessionRealtimeController(\n options: CreateSessionRealtimeControllerOptions,\n): SessionRealtimeController {\n const transport = sessionRealtimeTransportKind(options.model);\n return createCodexRealtimeController({\n ...options,\n ownerStorageNamespace: sessionRealtimeOwnerStorageNamespace(options.model),\n ...(transport === \"gateway\"\n ? { startTransport: createGatewayRealtimeTransportStarter() }\n : transport === \"xai-subscription\"\n ? { startTransport: createXaiSubscriptionRealtimeTransportStarter() }\n : {}),\n });\n}\n\nexport {\n createCodexRealtimeController,\n createGatewayRealtimeTransportStarter,\n createXaiSubscriptionRealtimeTransportStarter,\n hasStoredSessionRealtimeOwnerProof,\n sessionRealtimeOwnerStorageKey,\n sessionRealtimeOwnerStorageNamespace,\n};\nexport type {\n CodexRealtimeController,\n CodexRealtimeControllerClient,\n CodexRealtimeControllerSnapshot,\n CodexRealtimeControllerStatus,\n CodexRealtimeDiagnostic,\n CodexRealtimeDiagnosticKind,\n CodexRealtimeMicrophoneState,\n CodexRealtimeOwnerStorage,\n CreateCodexRealtimeControllerOptions,\n RealtimeControllerTransportStarter,\n};\n\nexport {\n CODEX_REALTIME_NEGOTIATION_TIMEOUT_MS,\n projectSessionRealtimeLifecycle,\n} from \"./codex-realtime-controller\";\nexport type { SessionRealtimeLifecycleProjection } from \"./codex-realtime-lifecycle\";\n\nexport {\n CodexRealtimeMicrophoneError,\n acquireCodexRealtimeMicrophone,\n codexRealtimeMicrophoneHealthy,\n startCodexRealtimeWebrtc,\n} from \"./codex-realtime\";\nexport type {\n AcquireCodexRealtimeMicrophoneOptions,\n CodexRealtimeAudibleOutputState,\n CodexRealtimeConnectionHealth,\n CodexRealtimeMicrophoneErrorCode,\n CodexRealtimeNegotiator,\n CodexRealtimeWebrtcSession,\n StartCodexRealtimeWebrtcOptions,\n} from \"./codex-realtime\";\n\nexport {\n CODEX_REALTIME_CONTEXT_APPEND_MAX_BYTES,\n CODEX_REALTIME_V3_MAX_EVENT_BYTES,\n CODEX_REALTIME_V3_MAX_IDENTIFIER_BYTES,\n CODEX_REALTIME_V3_MAX_TEXT_BYTES,\n CODEX_REALTIME_V3_PENDING_MAX_BYTES,\n CODEX_REALTIME_V3_PENDING_MAX_ENTRIES,\n CODEX_REALTIME_V3_SYNC_MAX_ENTRIES,\n contextAppendChunks,\n createCodexRealtimeV3Bridge,\n encodeCodexRealtimeV3DelegationContextAppend,\n encodeCodexRealtimeV3SessionContextAppend,\n parseCodexRealtimeV3Event,\n} from \"./codex-realtime-v3\";\nexport type {\n CodexRealtimeV3Bridge,\n CodexRealtimeV3BridgeFatal,\n CodexRealtimeV3BridgeOptions,\n CodexRealtimeV3BridgeSnapshot,\n CodexRealtimeV3ContextAppendChannel,\n CodexRealtimeV3DelegationContextAppend,\n CodexRealtimeV3Event,\n CodexRealtimeV3ParseFailure,\n CodexRealtimeV3ParseResult,\n CodexRealtimeV3SessionContextAppend,\n} from \"./codex-realtime-v3\";\n\nexport {\n CODEX_REALTIME_INITIAL_ITEMS_MAX_COUNT,\n CODEX_REALTIME_INITIAL_ITEMS_MAX_TOKENS,\n} from \"./codex-realtime-v3-wire\";\nexport type { CodexRealtimeInitialItem } from \"./codex-realtime-v3-wire\";\n\nexport type {\n ActivateCodexRealtimeConnectionRequest,\n BeginSessionRealtimeRequest,\n CodexRealtimeVoice,\n CodexRealtimeWebrtcRequest,\n CodexRealtimeWebrtcResponse,\n CodexRealtimeWebrtcVersion,\n EndSessionRealtimeRequest,\n GatewayRealtimeConnectRequest,\n GatewayRealtimeConnectResponse,\n GatewayRealtimeInitialItem,\n RenewSessionRealtimeRequest,\n SessionRealtimeEndReason,\n SessionRealtimeLedgerEntry,\n SessionRealtimeMode,\n SessionRealtimeModel,\n SessionRealtimeMutationResponse,\n SessionRealtimeState,\n SyncSessionRealtimeLedgerRequest,\n SyncSessionRealtimeLedgerResponse,\n WorkspaceRealtimeModelCatalogItem,\n WorkspaceRealtimeModelCatalogResponse,\n} from \"./types\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDO,SAAS,6BACd,OAC8B;AAC9B,MAAI,UAAU,2BAA4B,QAAO;AACjD,MAAI,UAAU,sCAAuC,QAAO;AAC5D,SAAO;AACT;AAOO,SAAS,gCACd,SAC2B;AAC3B,QAAM,YAAY,6BAA6B,QAAQ,KAAK;AAC5D,SAAO,8BAA8B;AAAA,IACnC,GAAG;AAAA,IACH,uBAAuB,qCAAqC,QAAQ,KAAK;AAAA,IACzE,GAAI,cAAc,YACd,EAAE,gBAAgB,sCAAsC,EAAE,IAC1D,cAAc,qBACZ,EAAE,gBAAgB,8CAA8C,EAAE,IAClE,CAAC;AAAA,EACT,CAAC;AACH;","names":[]}
1
+ {"version":3,"sources":["../src/azure-live-transport.ts","../src/realtime.ts"],"sourcesContent":["import { startCodexRealtimeWebrtc, type StartCodexRealtimeWebrtcOptions } from \"./codex-realtime\";\nimport type { RealtimeControllerTransportStarter } from \"./codex-realtime-controller\";\n\ntype Envelope = Record<string, unknown>;\nconst MAX_FRAGMENT_BYTES = 64_000;\n\n/** The most recent speech wins when the user talks for a long time between delegations. */\nfunction takeUtf8Tail(text: string, maxBytes = MAX_FRAGMENT_BYTES): string {\n const encoder = new TextEncoder();\n if (encoder.encode(text).byteLength <= maxBytes) return text;\n let tail = text.slice(-maxBytes);\n while (encoder.encode(tail).byteLength > maxBytes) tail = tail.slice(1);\n return tail;\n}\n\n/** Azure Live has timed transcript fragments, not provider-finalized turns. */\nexport class AzureLiveDataChannel extends EventTarget {\n private pending: {\n role: \"user\" | \"assistant\";\n text: string;\n startMs: number;\n endMs: number;\n } | null = null;\n private timer: ReturnType<typeof setTimeout> | null = null;\n private ordinal = 0;\n private readonly prefix = crypto.randomUUID();\n private closed = false;\n private closeSent = false;\n private providerClosed = false;\n private readonly delegations = new Set<string>();\n // Azure delegations carry no content, so the user's words since the previous\n // delegation become the delegation input.\n private userSinceDelegation = \"\";\n private draining: Promise<void> | null = null;\n private finishDrain: ((error?: Error) => void) | null = null;\n private readonly onOpen = () => this.dispatchEvent(new Event(\"open\"));\n private readonly onClose = () => {\n this.providerClosed = true;\n this.flush();\n this.finishDrain?.();\n this.dispatchEvent(new Event(\"close\"));\n };\n private readonly onError = () => this.dispatchEvent(new Event(\"error\"));\n private readonly onMessage = (event: MessageEvent) => {\n if (typeof event.data !== \"string\" || event.data.length > 1_048_576) return;\n let value: unknown;\n try {\n value = JSON.parse(event.data);\n } catch {\n return;\n }\n if (!value || typeof value !== \"object\") return;\n this.receive(value as Envelope);\n };\n constructor(\n private readonly raw: RTCDataChannel,\n private readonly drainTimeoutMs = 5_000,\n ) {\n super();\n raw.addEventListener(\"open\", this.onOpen);\n raw.addEventListener(\"close\", this.onClose);\n raw.addEventListener(\"error\", this.onError);\n raw.addEventListener(\"message\", this.onMessage);\n }\n get readyState(): RTCDataChannelState {\n return this.closed || this.providerClosed\n ? \"closed\"\n : this.closeSent\n ? \"closing\"\n : this.raw.readyState;\n }\n asRtcDataChannel(): RTCDataChannel {\n return this as unknown as RTCDataChannel;\n }\n private emit(value: Envelope): void {\n if (!this.closed)\n this.dispatchEvent(new MessageEvent(\"message\", { data: JSON.stringify(value) }));\n }\n private flush(): void {\n if (this.timer) clearTimeout(this.timer);\n this.timer = null;\n const pending = this.pending;\n this.pending = null;\n if (!pending?.text) return;\n this.emit({\n type: \"transcript.segment\",\n turn: {\n id: `${this.prefix}:${++this.ordinal}`,\n role: pending.role,\n transcript: pending.text,\n },\n start_ms: pending.startMs,\n end_ms: pending.endMs,\n });\n }\n private receive(value: Envelope): void {\n if (this.closed) return;\n if (\n value.type === \"session.input_transcript.delta\" ||\n value.type === \"session.output_transcript.delta\"\n ) {\n if (\n typeof value.delta !== \"string\" ||\n typeof value.start_ms !== \"number\" ||\n typeof value.end_ms !== \"number\"\n )\n return;\n const role = value.type === \"session.input_transcript.delta\" ? \"user\" : \"assistant\";\n if (role === \"user\")\n this.userSinceDelegation = takeUtf8Tail(this.userSinceDelegation + value.delta);\n if (\n this.pending &&\n (this.pending.role !== role ||\n new TextEncoder().encode(this.pending.text + value.delta).byteLength > MAX_FRAGMENT_BYTES)\n )\n this.flush();\n if (new TextEncoder().encode(value.delta).byteLength > MAX_FRAGMENT_BYTES) {\n this.emit({\n type: \"error\",\n error: { message: \"Voice transcript fragment exceeded the supported size\" },\n });\n return;\n }\n this.pending = {\n role,\n text: (this.pending?.text ?? \"\") + value.delta,\n startMs: this.pending?.startMs ?? value.start_ms,\n endMs: value.end_ms,\n };\n // Application grouping only: never present silence as a provider turn boundary.\n if (!this.timer) this.timer = setTimeout(() => this.flush(), 1_000);\n return;\n }\n if (value.type === \"session.delegation.created\") {\n const delegation = value.delegation as Envelope | undefined;\n if (delegation?.target !== \"client\" || typeof delegation.id !== \"string\") return;\n this.delegations.add(delegation.id);\n this.flush();\n const spoken = this.userSinceDelegation.trim();\n this.userSinceDelegation = \"\";\n this.emit({\n type: \"delegation.created\",\n item: {\n id: delegation.id,\n type: \"delegation\",\n target: \"client\",\n content: spoken ? [{ type: \"input_text\", text: spoken }] : [],\n },\n offset_ms: value.offset_ms,\n });\n return;\n }\n if (value.type === \"session.closed\") {\n this.providerClosed = true;\n this.flush();\n this.finishDrain?.();\n return;\n }\n if (\n value.type === \"session.started\" ||\n value.type === \"session.updated\" ||\n value.type === \"error\"\n )\n this.emit(value);\n }\n send(payload: string): void {\n if (this.readyState !== \"open\") throw Error(\"Hosted voice channel is not open\");\n const value = JSON.parse(payload) as Envelope;\n if (value.type !== \"session.context.append\" && value.type !== \"delegation.context.append\")\n throw Error(\"Unsupported hosted voice context event\");\n const content = Array.isArray(value.content)\n ? value.content.map((part) => (typeof part?.text === \"string\" ? part.text : \"\")).join(\"\")\n : \"\";\n // Existing bridge chunks are <=500 UTF-8 bytes, below Live's 500-token bound.\n this.raw.send(\n JSON.stringify({\n type:\n value.channel === \"speakable\" ? \"session.commentary.append\" : \"session.thinking.append\",\n content,\n // Replayed tasks from an earlier provider session are general context.\n delegation_id:\n value.type === \"delegation.context.append\" &&\n typeof value.delegation_item_id === \"string\" &&\n this.delegations.has(value.delegation_item_id)\n ? value.delegation_item_id\n : null,\n }),\n );\n }\n drain(): Promise<void> {\n if (this.draining) return this.draining;\n if (this.providerClosed || this.raw.readyState === \"closed\") {\n this.flush();\n return Promise.resolve();\n }\n if (this.closed || this.raw.readyState !== \"open\") {\n return Promise.reject(new Error(\"Hosted voice close is not confirmed\"));\n }\n const pending = new Promise<void>((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.flush();\n this.finishDrain?.(\n new Error(\"Hosted voice is still closing; retry to preserve final speech\"),\n );\n }, this.drainTimeoutMs);\n this.finishDrain = (error) => {\n clearTimeout(timeout);\n this.finishDrain = null;\n if (error) reject(error);\n else resolve();\n };\n if (!this.closeSent) {\n this.closeSent = true;\n try {\n this.raw.send(JSON.stringify({ type: \"session.close\" }));\n } catch {\n this.finishDrain(new Error(\"Hosted voice close could not be sent\"));\n }\n }\n });\n this.draining = pending;\n // An uncertain close remains retryable; never resend the provider mutation.\n void pending.then(\n () => {\n if (this.draining === pending) this.draining = null;\n },\n () => {\n if (this.draining === pending) this.draining = null;\n },\n );\n return pending;\n }\n close(): void {\n if (this.closed) return;\n if (this.timer) clearTimeout(this.timer);\n this.timer = null;\n this.pending = null;\n this.finishDrain?.(new Error(\"Hosted voice channel was disposed before close confirmation\"));\n this.closed = true;\n this.raw.removeEventListener(\"open\", this.onOpen);\n this.raw.removeEventListener(\"close\", this.onClose);\n this.raw.removeEventListener(\"error\", this.onError);\n this.raw.removeEventListener(\"message\", this.onMessage);\n this.dispatchEvent(new Event(\"close\"));\n }\n}\n\nexport function createAzureLiveTransportStarter(\n options: Pick<StartCodexRealtimeWebrtcOptions, \"remoteAudio\" | \"createPeerConnection\"> = {},\n): RealtimeControllerTransportStarter {\n return async (input) => {\n let channel: AzureLiveDataChannel | undefined;\n try {\n const transport = await startCodexRealtimeWebrtc({\n ...input,\n ...options,\n activateRemoteAudio: false,\n expectedModel: \"opengeni-azure/gpt-live-1\",\n onEventsCreated(raw) {\n channel = new AzureLiveDataChannel(raw);\n input.onEventsCreated(channel.asRtcDataChannel());\n },\n negotiate: (request, requestOptions) =>\n input.client.negotiateCodexRealtimeWebrtc(\n input.workspaceId,\n input.sessionId,\n request,\n requestOptions,\n ),\n });\n const events = channel!;\n return {\n ...transport,\n events: events.asRtcDataChannel(),\n drain: () => events.drain(),\n stop() {\n events.close();\n transport.stop();\n },\n };\n } catch (error) {\n channel?.close();\n throw error;\n }\n };\n}\n","import { createAzureLiveTransportStarter } from \"./azure-live-transport\";\n/**\n * Public, provider-neutral realtime browser SDK.\n *\n * Import this subpath lazily in browser applications. The base `@opengeni/sdk`\n * entry remains free of eager realtime transport initialization.\n */\nimport {\n createCodexRealtimeController,\n hasStoredSessionRealtimeOwnerProof,\n sessionRealtimeOwnerStorageKey,\n sessionRealtimeOwnerStorageNamespace,\n type CodexRealtimeController,\n type CodexRealtimeControllerClient,\n type CodexRealtimeControllerSnapshot,\n type CodexRealtimeControllerStatus,\n type CodexRealtimeDiagnostic,\n type CodexRealtimeDiagnosticKind,\n type CodexRealtimeMicrophoneState,\n type CodexRealtimeOwnerStorage,\n type CreateCodexRealtimeControllerOptions,\n type RealtimeControllerTransportStarter,\n} from \"./codex-realtime-controller\";\nimport {\n createGatewayRealtimeTransportStarter,\n createXaiSubscriptionRealtimeTransportStarter,\n} from \"./gateway-realtime-transport\";\nimport type { SessionRealtimeModel, WorkspaceRealtimeModelCatalogResponse } from \"./types\";\n\n/** Exact backend-facing methods required by the batteries-included realtime SDK. */\nexport type SessionRealtimeClientLike = CodexRealtimeControllerClient & {\n getWorkspaceRealtimeModelCatalog(\n workspaceId: string,\n options?: { signal?: AbortSignal | undefined },\n ): Promise<WorkspaceRealtimeModelCatalogResponse>;\n};\n\nexport type SessionRealtimeTransportKind = \"codex\" | \"gateway\" | \"xai-subscription\" | \"azure-live\";\n\n/** Provider-neutral names for the existing, battle-tested controller projection. */\nexport type SessionRealtimeController = CodexRealtimeController;\nexport type SessionRealtimeControllerSnapshot = CodexRealtimeControllerSnapshot;\nexport type SessionRealtimeControllerStatus = CodexRealtimeControllerStatus;\nexport type SessionRealtimeDiagnostic = CodexRealtimeDiagnostic;\nexport type SessionRealtimeDiagnosticKind = CodexRealtimeDiagnosticKind;\nexport type SessionRealtimeMicrophoneState = CodexRealtimeMicrophoneState;\nexport type SessionRealtimeOwnerStorage = CodexRealtimeOwnerStorage;\n\nexport type CreateSessionRealtimeControllerOptions = Omit<\n CreateCodexRealtimeControllerOptions,\n \"client\" | \"model\" | \"ownerStorageNamespace\" | \"startTransport\"\n> & {\n client: CodexRealtimeControllerClient;\n model: SessionRealtimeModel;\n};\n\n/** Select the existing transport without exposing provider mechanics to hosts. */\nexport function sessionRealtimeTransportKind(\n model: SessionRealtimeModel,\n): SessionRealtimeTransportKind {\n if (model === \"opengeni-azure/gpt-live-1\") return \"azure-live\";\n if (model === \"gpt-live-1-boulder-alpha\") return \"codex\";\n if (model === \"supergrok/grok-voice-think-fast-2.0\") return \"xai-subscription\";\n return \"gateway\";\n}\n\n/**\n * Compose the exact current controller with its existing Codex Live or AI\n * Gateway transport. Wire, ledger, delegation, recovery, and lifecycle\n * semantics remain owned by the existing implementations below this facade.\n */\nexport function createSessionRealtimeController(\n options: CreateSessionRealtimeControllerOptions,\n): SessionRealtimeController {\n const transport = sessionRealtimeTransportKind(options.model);\n return createCodexRealtimeController({\n ...options,\n ownerStorageNamespace: sessionRealtimeOwnerStorageNamespace(options.model),\n ...(transport === \"azure-live\"\n ? {\n startTransport: createAzureLiveTransportStarter({\n remoteAudio: options.remoteAudio,\n createPeerConnection: options.createPeerConnection,\n }),\n }\n : transport === \"gateway\"\n ? { startTransport: createGatewayRealtimeTransportStarter() }\n : transport === \"xai-subscription\"\n ? { startTransport: createXaiSubscriptionRealtimeTransportStarter() }\n : {}),\n });\n}\n\nexport {\n createCodexRealtimeController,\n createGatewayRealtimeTransportStarter,\n createXaiSubscriptionRealtimeTransportStarter,\n hasStoredSessionRealtimeOwnerProof,\n sessionRealtimeOwnerStorageKey,\n sessionRealtimeOwnerStorageNamespace,\n};\nexport type {\n CodexRealtimeController,\n CodexRealtimeControllerClient,\n CodexRealtimeControllerSnapshot,\n CodexRealtimeControllerStatus,\n CodexRealtimeDiagnostic,\n CodexRealtimeDiagnosticKind,\n CodexRealtimeMicrophoneState,\n CodexRealtimeOwnerStorage,\n CreateCodexRealtimeControllerOptions,\n RealtimeControllerTransportStarter,\n};\n\nexport {\n CODEX_REALTIME_NEGOTIATION_TIMEOUT_MS,\n projectSessionRealtimeLifecycle,\n} from \"./codex-realtime-controller\";\nexport type { SessionRealtimeLifecycleProjection } from \"./codex-realtime-lifecycle\";\n\nexport {\n CodexRealtimeMicrophoneError,\n acquireCodexRealtimeMicrophone,\n codexRealtimeMicrophoneHealthy,\n startCodexRealtimeWebrtc,\n} from \"./codex-realtime\";\nexport type {\n AcquireCodexRealtimeMicrophoneOptions,\n CodexRealtimeAudibleOutputState,\n CodexRealtimeConnectionHealth,\n CodexRealtimeMicrophoneErrorCode,\n CodexRealtimeNegotiator,\n CodexRealtimeWebrtcSession,\n StartCodexRealtimeWebrtcOptions,\n} from \"./codex-realtime\";\n\nexport {\n CODEX_REALTIME_CONTEXT_APPEND_MAX_BYTES,\n CODEX_REALTIME_V3_MAX_EVENT_BYTES,\n CODEX_REALTIME_V3_MAX_IDENTIFIER_BYTES,\n CODEX_REALTIME_V3_MAX_TEXT_BYTES,\n CODEX_REALTIME_V3_PENDING_MAX_BYTES,\n CODEX_REALTIME_V3_PENDING_MAX_ENTRIES,\n CODEX_REALTIME_V3_SYNC_MAX_ENTRIES,\n contextAppendChunks,\n createCodexRealtimeV3Bridge,\n encodeCodexRealtimeV3DelegationContextAppend,\n encodeCodexRealtimeV3SessionContextAppend,\n parseCodexRealtimeV3Event,\n} from \"./codex-realtime-v3\";\nexport type {\n CodexRealtimeV3Bridge,\n CodexRealtimeV3BridgeFatal,\n CodexRealtimeV3BridgeOptions,\n CodexRealtimeV3BridgeSnapshot,\n CodexRealtimeV3ContextAppendChannel,\n CodexRealtimeV3DelegationContextAppend,\n CodexRealtimeV3Event,\n CodexRealtimeV3ParseFailure,\n CodexRealtimeV3ParseResult,\n CodexRealtimeV3SessionContextAppend,\n} from \"./codex-realtime-v3\";\n\nexport {\n CODEX_REALTIME_INITIAL_ITEMS_MAX_COUNT,\n CODEX_REALTIME_INITIAL_ITEMS_MAX_TOKENS,\n} from \"./codex-realtime-v3-wire\";\nexport type { CodexRealtimeInitialItem } from \"./codex-realtime-v3-wire\";\n\nexport type {\n ActivateCodexRealtimeConnectionRequest,\n BeginSessionRealtimeRequest,\n CodexRealtimeVoice,\n CodexRealtimeWebrtcRequest,\n CodexRealtimeWebrtcResponse,\n CodexRealtimeWebrtcVersion,\n EndSessionRealtimeRequest,\n GatewayRealtimeConnectRequest,\n GatewayRealtimeConnectResponse,\n GatewayRealtimeInitialItem,\n RenewSessionRealtimeRequest,\n SessionRealtimeEndReason,\n SessionRealtimeLedgerEntry,\n SessionRealtimeMode,\n SessionRealtimeModel,\n SessionRealtimeMutationResponse,\n SessionRealtimeState,\n SyncSessionRealtimeLedgerRequest,\n SyncSessionRealtimeLedgerResponse,\n WorkspaceRealtimeModelCatalogItem,\n WorkspaceRealtimeModelCatalogResponse,\n} from \"./types\";\n"],"mappings":"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","names":[]}
@@ -11,11 +11,15 @@ export declare class SessionProxySiteHtmlTooLargeError extends Error {
11
11
  }
12
12
  /** Server-only effective grant read; never derive external authority from access/me snapshots. */
13
13
  export declare function getSessionProxyWorkspaceGrant(client: Pick<OpenGeniEmbeddingClient, "requestJson">, workspaceId: string, options?: OpenGeniRequestOptions): Promise<AccessGrant>;
14
- /** Exact association read. The API reauthorizes the source session on every call. */
15
- export declare function getSessionProxyArtifactAssociation(client: Pick<OpenGeniEmbeddingClient, "requestJson">, workspaceId: string, sessionId: string, kind: "editable" | "site", artifactId: string, options?: OpenGeniRequestOptions): Promise<{
14
+ /**
15
+ * Exact association read. The API reauthorizes the source session on every
16
+ * call. `retained` proves a generated image or video, or a published sandbox
17
+ * file, originated in that session.
18
+ */
19
+ export declare function getSessionProxyArtifactAssociation(client: Pick<OpenGeniEmbeddingClient, "requestJson">, workspaceId: string, sessionId: string, kind: "editable" | "site" | "retained", artifactId: string, options?: OpenGeniRequestOptions): Promise<{
16
20
  sessionId: string;
17
21
  artifactId: string;
18
- kind: "editable" | "site";
22
+ kind: "editable" | "site" | "retained";
19
23
  }>;
20
24
  /** Authenticated response stream for the server proxy; does not buffer Site HTML. */
21
25
  export declare function downloadSessionProxySiteHtml(client: Pick<OpenGeniEmbeddingClient, "requestJsonResponse">, workspaceId: string, artifactId: string, options: {
@@ -174,7 +174,15 @@ export type SessionProxyHandlerOptions = {
174
174
  basePath?: string | undefined;
175
175
  /** Maximum JSON request body. Defaults to 1 MiB. */
176
176
  maxBodyBytes?: number | undefined;
177
- /** Expose composer file attachments (upload begin/complete, download URL). Defaults to true. */
177
+ /**
178
+ * Expose composer file attachments (upload begin/complete, download URL) and
179
+ * the media agents produce in a session: generated images, browser and
180
+ * computer screenshots, published sandbox files, and generated video
181
+ * playback. Workspace-level artifact reads must name their session in the
182
+ * `x-opengeni-session-id` header (`SessionConversation` does this); the proxy
183
+ * runs `authorizeSession` and only forwards an artifact OpenGeni proves that
184
+ * session produced. Defaults to true.
185
+ */
178
186
  files?: boolean | undefined;
179
187
  /**
180
188
  * Forward composer voice input (`POST .../transcriptions`, one recording per
@@ -6,11 +6,11 @@ import {
6
6
  downloadSessionProxySiteHtml,
7
7
  getSessionProxyArtifactAssociation,
8
8
  getSessionProxyWorkspaceGrant
9
- } from "./chunk-CNSPJYF6.js";
9
+ } from "./chunk-FYQAMXDW.js";
10
10
  import "./chunk-UM4ZXXJR.js";
11
11
  import "./chunk-U6CV2SXO.js";
12
12
  import "./chunk-APXVSSSY.js";
13
- import "./chunk-IB6SUE3R.js";
13
+ import "./chunk-GYM54GKM.js";
14
14
  import "./chunk-V6GIY62B.js";
15
15
  export {
16
16
  SESSION_PROXY_SITE_HTML_MAX_BYTES,
package/dist/site.js CHANGED
@@ -18,12 +18,12 @@ import {
18
18
  sanitizeOpenGeniSiteToolCallRequest,
19
19
  serveSiteHttp,
20
20
  siteSessionPath
21
- } from "./chunk-CREM7YRK.js";
21
+ } from "./chunk-LEBDXYMA.js";
22
22
  import "./chunk-4SMEOV3P.js";
23
- import "./chunk-RSKO3CMZ.js";
23
+ import "./chunk-BVIIRSJY.js";
24
24
  import "./chunk-VPVMLM7Q.js";
25
25
  import "./chunk-APXVSSSY.js";
26
- import "./chunk-IB6SUE3R.js";
26
+ import "./chunk-GYM54GKM.js";
27
27
  import "./chunk-NC57YMUO.js";
28
28
  import "./chunk-V6GIY62B.js";
29
29
  export {
@@ -70,7 +70,7 @@ export type TranscriptionAuthorization = {
70
70
  reason: TranscriptionPolicyBlockReason;
71
71
  };
72
72
  export type TranscriptionLifecycleStatus = "idle" | "requesting-permission" | "listening" | "reconnecting" | "cancelling" | "closed" | "error";
73
- export type TranscriptionErrorCode = "permission_denied" | "not_supported" | "network" | "provider" | "policy_blocked" | "timeout" | "cancelled" | "unavailable" | "too_large" | "invalid_audio" | "unknown";
73
+ export type TranscriptionErrorCode = "insufficient_credits" | "allowance_exhausted" | "monthly_model_cost_limit" | "permission_denied" | "not_supported" | "network" | "provider" | "policy_blocked" | "timeout" | "cancelled" | "unavailable" | "too_large" | "invalid_audio" | "unknown";
74
74
  /** Native browser voice input defaults to the configured deployment capability. */
75
75
  export declare function resolveWorkspaceVoiceInputEnabled(settings: unknown): boolean | null;
76
76
  export type TranscriptionTimeSpan = {
package/dist/types.d.ts CHANGED
@@ -22,7 +22,7 @@ export type CodexRealtimeWebrtcRequest = {
22
22
  export type CodexRealtimeWebrtcResponse = {
23
23
  sdp: string;
24
24
  version: CodexRealtimeWebrtcVersion;
25
- model: "gpt-live-1-boulder-alpha";
25
+ model: "gpt-live-1-boulder-alpha" | "opengeni-azure/gpt-live-1";
26
26
  connectionId: string;
27
27
  connectionEpoch: number;
28
28
  startupFenceSequence: number;
@@ -186,7 +186,7 @@ export type SyncSessionRealtimeLedgerResponse = {
186
186
  }>;
187
187
  outbound: SessionRealtimeLedgerEntry[];
188
188
  };
189
- export type SessionRealtimeModel = "gpt-live-1-boulder-alpha" | "supergrok/grok-voice-think-fast-2.0" | "opengeni-gateway/openai/gpt-realtime-2.1" | "opengeni-gateway/openai/gpt-realtime-mini" | "opengeni-gateway/xai/grok-voice-think-fast-2.0" | "workspace-gateway/openai/gpt-realtime-2.1" | "workspace-gateway/openai/gpt-realtime-mini" | "workspace-gateway/xai/grok-voice-think-fast-2.0";
189
+ export type SessionRealtimeModel = "opengeni-azure/gpt-live-1" | "gpt-live-1-boulder-alpha" | "supergrok/grok-voice-think-fast-2.0" | "opengeni-gateway/openai/gpt-realtime-2.1" | "opengeni-gateway/openai/gpt-realtime-mini" | "opengeni-gateway/xai/grok-voice-think-fast-2.0" | "workspace-gateway/openai/gpt-realtime-2.1" | "workspace-gateway/openai/gpt-realtime-mini" | "workspace-gateway/xai/grok-voice-think-fast-2.0";
190
190
  export type WorkspaceRealtimeModelCatalogItem = {
191
191
  id: SessionRealtimeModel;
192
192
  label: string;
@@ -194,6 +194,8 @@ export type WorkspaceRealtimeModelCatalogItem = {
194
194
  description: string;
195
195
  available: boolean;
196
196
  unavailableReason: string | null;
197
+ /** Machine-readable reason when unavailable, e.g. `insufficient_credits`. */
198
+ unavailableCode?: string | null | undefined;
197
199
  recommended: boolean;
198
200
  };
199
201
  export type WorkspaceRealtimeModelCatalogResponse = {
@@ -230,9 +232,16 @@ export type RenewSessionRealtimeRequest = {
230
232
  export type EndSessionRealtimeRequest = RenewSessionRealtimeRequest & {
231
233
  reason: Extract<SessionRealtimeEndReason, "user_stop" | "browser_unload">;
232
234
  };
235
+ /** Server instruction to end a live call now (for example, out of credits). */
236
+ export type SessionRealtimeStopInstruction = {
237
+ code: string;
238
+ message: string;
239
+ };
233
240
  export type SessionRealtimeMutationResponse = {
234
241
  mode: SessionRealtimeMode;
235
242
  replay: boolean;
243
+ /** Present on a heartbeat when the server stopped extending the lease. */
244
+ stop?: SessionRealtimeStopInstruction | undefined;
236
245
  };
237
246
  export type SessionStatus = "queued" | "running" | "idle" | "requires_action" | "recovering" | "waiting_capacity" | "failed" | "cancelled";
238
247
  export type SandboxBackend = "docker" | "modal" | "local" | "none" | "daytona" | "runloop" | "e2b" | "blaxel" | "cloudflare" | "vercel" | "selfhosted" | "opensandbox";
@@ -3339,9 +3348,11 @@ export type ClientConfig = {
3339
3348
  */
3340
3349
  workspaceId?: string | undefined;
3341
3350
  /**
3342
- * Session proxy capability for the embedded artifact viewer; absent on
3343
- * native deployments. The live socket is ticket-authenticated and reached
3344
- * directly; the cache partition identifies the proxied user.
3351
+ * Session proxy capability for the embedded artifact viewer and inline Site
3352
+ * previews; absent on native deployments. The live socket is
3353
+ * ticket-authenticated and reached directly; the cache partition identifies
3354
+ * the proxied user. `false` when the proxy does not serve artifacts, so
3355
+ * stock UIs show Site previews as unavailable instead of failing on click.
3345
3356
  */
3346
3357
  artifacts?: {
3347
3358
  editableLiveUrl: string;
@@ -3350,7 +3361,18 @@ export type ClientConfig = {
3350
3361
  principalId: string;
3351
3362
  authorizationEpoch: string;
3352
3363
  };
3353
- } | undefined;
3364
+ } | false | undefined;
3365
+ /**
3366
+ * Session proxy only: whether the browser may start a chat (the proxy has a
3367
+ * `createSession` hook). Stock UIs hide "New chat" when `false`; absent on
3368
+ * native deployments and older proxies.
3369
+ */
3370
+ sessionCreation?: boolean | undefined;
3371
+ /**
3372
+ * Session proxy only: whether users may archive or restore their chats.
3373
+ * Stock UIs hide "Archive" when `false`; absent on native deployments.
3374
+ */
3375
+ archive?: boolean | undefined;
3354
3376
  /** Native browser microphone capture + server-side transcription capability. */
3355
3377
  voiceInput?: ClientVoiceInputConfig | undefined;
3356
3378
  /**
@@ -3416,7 +3438,7 @@ export type ClientResumableVoiceInputConfig = {
3416
3438
  maxChunkSizeBytes: number;
3417
3439
  providerSegmentSeconds: number;
3418
3440
  };
3419
- export type TranscriptionRecordingErrorCode = "permission_denied" | "not_supported" | "network" | "provider" | "policy_blocked" | "timeout" | "cancelled" | "unavailable" | "too_large" | "invalid_audio" | "unknown";
3441
+ export type TranscriptionRecordingErrorCode = "permission_denied" | "not_supported" | "network" | "provider" | "policy_blocked" | "timeout" | "cancelled" | "unavailable" | "too_large" | "invalid_audio" | "unknown" | "insufficient_credits" | "allowance_exhausted" | "monthly_model_cost_limit";
3420
3442
  export type TranscriptionRecordingState = "uploading" | "segmenting" | "ready" | "transcribing" | "complete" | "failed" | "discarded";
3421
3443
  export type TranscriptionRecordingSegmentState = "preparing" | "pending" | "transcribing" | "complete" | "failed";
3422
3444
  export type TranscriptionRecordingSegment = {
@@ -4042,7 +4064,7 @@ export type UpdateSlackChannelRoutesRequest = {
4042
4064
  targetWorkspaceId: string | null;
4043
4065
  }>;
4044
4066
  };
4045
- export type VoiceInputProviderId = "supergrok-subscription" | "codex-subscription" | "openai" | "azure-openai";
4067
+ export type VoiceInputProviderId = "azure-mai" | "supergrok-subscription" | "codex-subscription" | "openai" | "azure-openai";
4046
4068
  export type WorkspaceVoiceInputSettings = {
4047
4069
  enabled: boolean;
4048
4070
  preferredProvider?: VoiceInputProviderId | null | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/sdk",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Framework-agnostic TypeScript SDK for the OpenGeni API: typed client, session lifecycle, SSE event streaming with reconnect + replay-by-sequence, and proxy re-streaming helpers.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -182,8 +182,8 @@
182
182
  "prepublishOnly": "bash ../../scripts/prepublish-guard"
183
183
  },
184
184
  "dependencies": {
185
- "@opengeni/connect": "1.3.0",
186
- "@opengeni/contracts": "1.3.0"
185
+ "@opengeni/connect": "1.4.0",
186
+ "@opengeni/contracts": "1.4.0"
187
187
  },
188
188
  "engines": {
189
189
  "node": ">=18"
@@ -0,0 +1,286 @@
1
+ import { startCodexRealtimeWebrtc, type StartCodexRealtimeWebrtcOptions } from "./codex-realtime";
2
+ import type { RealtimeControllerTransportStarter } from "./codex-realtime-controller";
3
+
4
+ type Envelope = Record<string, unknown>;
5
+ const MAX_FRAGMENT_BYTES = 64_000;
6
+
7
+ /** The most recent speech wins when the user talks for a long time between delegations. */
8
+ function takeUtf8Tail(text: string, maxBytes = MAX_FRAGMENT_BYTES): string {
9
+ const encoder = new TextEncoder();
10
+ if (encoder.encode(text).byteLength <= maxBytes) return text;
11
+ let tail = text.slice(-maxBytes);
12
+ while (encoder.encode(tail).byteLength > maxBytes) tail = tail.slice(1);
13
+ return tail;
14
+ }
15
+
16
+ /** Azure Live has timed transcript fragments, not provider-finalized turns. */
17
+ export class AzureLiveDataChannel extends EventTarget {
18
+ private pending: {
19
+ role: "user" | "assistant";
20
+ text: string;
21
+ startMs: number;
22
+ endMs: number;
23
+ } | null = null;
24
+ private timer: ReturnType<typeof setTimeout> | null = null;
25
+ private ordinal = 0;
26
+ private readonly prefix = crypto.randomUUID();
27
+ private closed = false;
28
+ private closeSent = false;
29
+ private providerClosed = false;
30
+ private readonly delegations = new Set<string>();
31
+ // Azure delegations carry no content, so the user's words since the previous
32
+ // delegation become the delegation input.
33
+ private userSinceDelegation = "";
34
+ private draining: Promise<void> | null = null;
35
+ private finishDrain: ((error?: Error) => void) | null = null;
36
+ private readonly onOpen = () => this.dispatchEvent(new Event("open"));
37
+ private readonly onClose = () => {
38
+ this.providerClosed = true;
39
+ this.flush();
40
+ this.finishDrain?.();
41
+ this.dispatchEvent(new Event("close"));
42
+ };
43
+ private readonly onError = () => this.dispatchEvent(new Event("error"));
44
+ private readonly onMessage = (event: MessageEvent) => {
45
+ if (typeof event.data !== "string" || event.data.length > 1_048_576) return;
46
+ let value: unknown;
47
+ try {
48
+ value = JSON.parse(event.data);
49
+ } catch {
50
+ return;
51
+ }
52
+ if (!value || typeof value !== "object") return;
53
+ this.receive(value as Envelope);
54
+ };
55
+ constructor(
56
+ private readonly raw: RTCDataChannel,
57
+ private readonly drainTimeoutMs = 5_000,
58
+ ) {
59
+ super();
60
+ raw.addEventListener("open", this.onOpen);
61
+ raw.addEventListener("close", this.onClose);
62
+ raw.addEventListener("error", this.onError);
63
+ raw.addEventListener("message", this.onMessage);
64
+ }
65
+ get readyState(): RTCDataChannelState {
66
+ return this.closed || this.providerClosed
67
+ ? "closed"
68
+ : this.closeSent
69
+ ? "closing"
70
+ : this.raw.readyState;
71
+ }
72
+ asRtcDataChannel(): RTCDataChannel {
73
+ return this as unknown as RTCDataChannel;
74
+ }
75
+ private emit(value: Envelope): void {
76
+ if (!this.closed)
77
+ this.dispatchEvent(new MessageEvent("message", { data: JSON.stringify(value) }));
78
+ }
79
+ private flush(): void {
80
+ if (this.timer) clearTimeout(this.timer);
81
+ this.timer = null;
82
+ const pending = this.pending;
83
+ this.pending = null;
84
+ if (!pending?.text) return;
85
+ this.emit({
86
+ type: "transcript.segment",
87
+ turn: {
88
+ id: `${this.prefix}:${++this.ordinal}`,
89
+ role: pending.role,
90
+ transcript: pending.text,
91
+ },
92
+ start_ms: pending.startMs,
93
+ end_ms: pending.endMs,
94
+ });
95
+ }
96
+ private receive(value: Envelope): void {
97
+ if (this.closed) return;
98
+ if (
99
+ value.type === "session.input_transcript.delta" ||
100
+ value.type === "session.output_transcript.delta"
101
+ ) {
102
+ if (
103
+ typeof value.delta !== "string" ||
104
+ typeof value.start_ms !== "number" ||
105
+ typeof value.end_ms !== "number"
106
+ )
107
+ return;
108
+ const role = value.type === "session.input_transcript.delta" ? "user" : "assistant";
109
+ if (role === "user")
110
+ this.userSinceDelegation = takeUtf8Tail(this.userSinceDelegation + value.delta);
111
+ if (
112
+ this.pending &&
113
+ (this.pending.role !== role ||
114
+ new TextEncoder().encode(this.pending.text + value.delta).byteLength > MAX_FRAGMENT_BYTES)
115
+ )
116
+ this.flush();
117
+ if (new TextEncoder().encode(value.delta).byteLength > MAX_FRAGMENT_BYTES) {
118
+ this.emit({
119
+ type: "error",
120
+ error: { message: "Voice transcript fragment exceeded the supported size" },
121
+ });
122
+ return;
123
+ }
124
+ this.pending = {
125
+ role,
126
+ text: (this.pending?.text ?? "") + value.delta,
127
+ startMs: this.pending?.startMs ?? value.start_ms,
128
+ endMs: value.end_ms,
129
+ };
130
+ // Application grouping only: never present silence as a provider turn boundary.
131
+ if (!this.timer) this.timer = setTimeout(() => this.flush(), 1_000);
132
+ return;
133
+ }
134
+ if (value.type === "session.delegation.created") {
135
+ const delegation = value.delegation as Envelope | undefined;
136
+ if (delegation?.target !== "client" || typeof delegation.id !== "string") return;
137
+ this.delegations.add(delegation.id);
138
+ this.flush();
139
+ const spoken = this.userSinceDelegation.trim();
140
+ this.userSinceDelegation = "";
141
+ this.emit({
142
+ type: "delegation.created",
143
+ item: {
144
+ id: delegation.id,
145
+ type: "delegation",
146
+ target: "client",
147
+ content: spoken ? [{ type: "input_text", text: spoken }] : [],
148
+ },
149
+ offset_ms: value.offset_ms,
150
+ });
151
+ return;
152
+ }
153
+ if (value.type === "session.closed") {
154
+ this.providerClosed = true;
155
+ this.flush();
156
+ this.finishDrain?.();
157
+ return;
158
+ }
159
+ if (
160
+ value.type === "session.started" ||
161
+ value.type === "session.updated" ||
162
+ value.type === "error"
163
+ )
164
+ this.emit(value);
165
+ }
166
+ send(payload: string): void {
167
+ if (this.readyState !== "open") throw Error("Hosted voice channel is not open");
168
+ const value = JSON.parse(payload) as Envelope;
169
+ if (value.type !== "session.context.append" && value.type !== "delegation.context.append")
170
+ throw Error("Unsupported hosted voice context event");
171
+ const content = Array.isArray(value.content)
172
+ ? value.content.map((part) => (typeof part?.text === "string" ? part.text : "")).join("")
173
+ : "";
174
+ // Existing bridge chunks are <=500 UTF-8 bytes, below Live's 500-token bound.
175
+ this.raw.send(
176
+ JSON.stringify({
177
+ type:
178
+ value.channel === "speakable" ? "session.commentary.append" : "session.thinking.append",
179
+ content,
180
+ // Replayed tasks from an earlier provider session are general context.
181
+ delegation_id:
182
+ value.type === "delegation.context.append" &&
183
+ typeof value.delegation_item_id === "string" &&
184
+ this.delegations.has(value.delegation_item_id)
185
+ ? value.delegation_item_id
186
+ : null,
187
+ }),
188
+ );
189
+ }
190
+ drain(): Promise<void> {
191
+ if (this.draining) return this.draining;
192
+ if (this.providerClosed || this.raw.readyState === "closed") {
193
+ this.flush();
194
+ return Promise.resolve();
195
+ }
196
+ if (this.closed || this.raw.readyState !== "open") {
197
+ return Promise.reject(new Error("Hosted voice close is not confirmed"));
198
+ }
199
+ const pending = new Promise<void>((resolve, reject) => {
200
+ const timeout = setTimeout(() => {
201
+ this.flush();
202
+ this.finishDrain?.(
203
+ new Error("Hosted voice is still closing; retry to preserve final speech"),
204
+ );
205
+ }, this.drainTimeoutMs);
206
+ this.finishDrain = (error) => {
207
+ clearTimeout(timeout);
208
+ this.finishDrain = null;
209
+ if (error) reject(error);
210
+ else resolve();
211
+ };
212
+ if (!this.closeSent) {
213
+ this.closeSent = true;
214
+ try {
215
+ this.raw.send(JSON.stringify({ type: "session.close" }));
216
+ } catch {
217
+ this.finishDrain(new Error("Hosted voice close could not be sent"));
218
+ }
219
+ }
220
+ });
221
+ this.draining = pending;
222
+ // An uncertain close remains retryable; never resend the provider mutation.
223
+ void pending.then(
224
+ () => {
225
+ if (this.draining === pending) this.draining = null;
226
+ },
227
+ () => {
228
+ if (this.draining === pending) this.draining = null;
229
+ },
230
+ );
231
+ return pending;
232
+ }
233
+ close(): void {
234
+ if (this.closed) return;
235
+ if (this.timer) clearTimeout(this.timer);
236
+ this.timer = null;
237
+ this.pending = null;
238
+ this.finishDrain?.(new Error("Hosted voice channel was disposed before close confirmation"));
239
+ this.closed = true;
240
+ this.raw.removeEventListener("open", this.onOpen);
241
+ this.raw.removeEventListener("close", this.onClose);
242
+ this.raw.removeEventListener("error", this.onError);
243
+ this.raw.removeEventListener("message", this.onMessage);
244
+ this.dispatchEvent(new Event("close"));
245
+ }
246
+ }
247
+
248
+ export function createAzureLiveTransportStarter(
249
+ options: Pick<StartCodexRealtimeWebrtcOptions, "remoteAudio" | "createPeerConnection"> = {},
250
+ ): RealtimeControllerTransportStarter {
251
+ return async (input) => {
252
+ let channel: AzureLiveDataChannel | undefined;
253
+ try {
254
+ const transport = await startCodexRealtimeWebrtc({
255
+ ...input,
256
+ ...options,
257
+ activateRemoteAudio: false,
258
+ expectedModel: "opengeni-azure/gpt-live-1",
259
+ onEventsCreated(raw) {
260
+ channel = new AzureLiveDataChannel(raw);
261
+ input.onEventsCreated(channel.asRtcDataChannel());
262
+ },
263
+ negotiate: (request, requestOptions) =>
264
+ input.client.negotiateCodexRealtimeWebrtc(
265
+ input.workspaceId,
266
+ input.sessionId,
267
+ request,
268
+ requestOptions,
269
+ ),
270
+ });
271
+ const events = channel!;
272
+ return {
273
+ ...transport,
274
+ events: events.asRtcDataChannel(),
275
+ drain: () => events.drain(),
276
+ stop() {
277
+ events.close();
278
+ transport.stop();
279
+ },
280
+ };
281
+ } catch (error) {
282
+ channel?.close();
283
+ throw error;
284
+ }
285
+ };
286
+ }