@opengeni/react 0.45.0 → 0.48.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 (141) hide show
  1. package/README.md +68 -12
  2. package/dist/{chunk-U3CSCMWA.js → chunk-FK6VG4LL.js} +9 -13
  3. package/dist/chunk-FK6VG4LL.js.map +1 -0
  4. package/dist/{chunk-HFO4ERGQ.js → chunk-FWXGSNXT.js} +2 -2
  5. package/dist/{chunk-SRFUT2ZU.js → chunk-I4MPFDRP.js} +119 -63
  6. package/dist/chunk-I4MPFDRP.js.map +1 -0
  7. package/dist/{chunk-EB67J347.js → chunk-KZ73RL76.js} +111 -31
  8. package/dist/chunk-KZ73RL76.js.map +1 -0
  9. package/dist/{chunk-LWR4MXSS.js → chunk-LHLYWG5R.js} +10 -1
  10. package/dist/chunk-LHLYWG5R.js.map +1 -0
  11. package/dist/{chunk-L3EWO3UK.js → chunk-NJ7M2B6Z.js} +445 -84
  12. package/dist/chunk-NJ7M2B6Z.js.map +1 -0
  13. package/dist/{chunk-VCBFUSUZ.js → chunk-O4VXOBGF.js} +3 -3
  14. package/dist/{chunk-VCBFUSUZ.js.map → chunk-O4VXOBGF.js.map} +1 -1
  15. package/dist/{chunk-6EDV6YFE.js → chunk-OL6QVXGF.js} +121 -29
  16. package/dist/chunk-OL6QVXGF.js.map +1 -0
  17. package/dist/chunk-VZTQ73XT.js +86 -0
  18. package/dist/chunk-VZTQ73XT.js.map +1 -0
  19. package/dist/{chunk-EHSYZ4KP.js → chunk-WYA65Y3F.js} +16 -16
  20. package/dist/chunk-WYA65Y3F.js.map +1 -0
  21. package/dist/{chunk-FD72GJMK.js → chunk-XCNTXWBB.js} +274 -125
  22. package/dist/chunk-XCNTXWBB.js.map +1 -0
  23. package/dist/client.d.ts +1 -1
  24. package/dist/components/chat-composer.d.ts +7 -2
  25. package/dist/components/composer-transcription-control.d.ts +2 -0
  26. package/dist/components/composer.d.ts +14 -0
  27. package/dist/components/machines/machine-detail.d.ts +3 -1
  28. package/dist/components/machines-dashboard.d.ts +3 -3
  29. package/dist/components/message-timeline.d.ts +12 -2
  30. package/dist/components/sandbox-files.d.ts +2 -2
  31. package/dist/components/sandbox-terminal.d.ts +29 -0
  32. package/dist/components/sandbox-workspace.d.ts +5 -1
  33. package/dist/components/workspace-dock.d.ts +3 -1
  34. package/dist/composer.d.ts +2 -2
  35. package/dist/composer.js +6 -6
  36. package/dist/hooks/internal.d.ts +6 -0
  37. package/dist/hooks/use-codex-accounts.d.ts +1 -1
  38. package/dist/hooks/use-environments.d.ts +10 -4
  39. package/dist/hooks/use-machines.d.ts +7 -0
  40. package/dist/hooks/use-sandbox-files.d.ts +19 -0
  41. package/dist/hooks/use-sandbox-git.d.ts +7 -0
  42. package/dist/hooks/use-transcription.d.ts +2 -2
  43. package/dist/hooks/use-voice-input.d.ts +13 -4
  44. package/dist/index.d.ts +6 -5
  45. package/dist/index.js +904 -538
  46. package/dist/index.js.map +1 -1
  47. package/dist/lib/composer-responsive-context.d.ts +9 -0
  48. package/dist/lib/use-portal-token-style.d.ts +14 -3
  49. package/dist/machines.js +2 -2
  50. package/dist/{queue-surface-implementation-J4XJFKRW.js → queue-surface-implementation-U5JFG7HT.js} +19 -18
  51. package/dist/queue-surface-implementation-U5JFG7HT.js.map +1 -0
  52. package/dist/realtime/realtime-control.d.ts +9 -0
  53. package/dist/realtime.js +29 -32
  54. package/dist/realtime.js.map +1 -1
  55. package/dist/session-ui.js +5 -5
  56. package/dist/session.js +4 -4
  57. package/dist/timeline/activity-rail.d.ts +3 -2
  58. package/dist/timeline/index.d.ts +2 -2
  59. package/dist/timeline/parsers.d.ts +3 -3
  60. package/dist/timeline/registry.d.ts +3 -0
  61. package/dist/timeline/screenshot-lightbox.d.ts +1 -1
  62. package/dist/timeline/types.d.ts +4 -0
  63. package/dist/voice-recording-store.d.ts +8 -2
  64. package/package.json +20 -4
  65. package/src/client.ts +3 -0
  66. package/src/components/chat-composer.tsx +12 -2
  67. package/src/components/code-editor.tsx +1 -1
  68. package/src/components/command-palette.tsx +1 -1
  69. package/src/components/composer-transcription-control.tsx +41 -16
  70. package/src/components/composer.tsx +52 -26
  71. package/src/components/copy-button.tsx +2 -2
  72. package/src/components/desktop-viewer.tsx +2 -2
  73. package/src/components/file-browser.tsx +39 -17
  74. package/src/components/human-input-form.tsx +2 -2
  75. package/src/components/machine-card.tsx +1 -1
  76. package/src/components/machines/machine-detail.tsx +39 -15
  77. package/src/components/machines-dashboard.tsx +7 -6
  78. package/src/components/message-timeline.tsx +44 -11
  79. package/src/components/model-picker.tsx +2 -2
  80. package/src/components/model-policy-picker.tsx +16 -15
  81. package/src/components/queue-surface-implementation.tsx +20 -16
  82. package/src/components/queue-surface-state.tsx +2 -2
  83. package/src/components/sandbox-files.tsx +140 -60
  84. package/src/components/sandbox-terminal.tsx +24 -5
  85. package/src/components/sandbox-workspace.tsx +180 -142
  86. package/src/components/session-chrome.tsx +14 -14
  87. package/src/components/tooltip.tsx +13 -16
  88. package/src/components/user-message-body.tsx +1 -1
  89. package/src/components/workbench-changes.tsx +4 -4
  90. package/src/components/workspace-dock.tsx +13 -5
  91. package/src/composer.ts +3 -0
  92. package/src/hooks/internal.ts +132 -38
  93. package/src/hooks/use-codex-accounts.ts +4 -4
  94. package/src/hooks/use-environments.ts +24 -5
  95. package/src/hooks/use-file-attachments.ts +70 -32
  96. package/src/hooks/use-goal.ts +17 -5
  97. package/src/hooks/use-machines.ts +47 -1
  98. package/src/hooks/use-sandbox-files.ts +310 -59
  99. package/src/hooks/use-sandbox-git.ts +148 -41
  100. package/src/hooks/use-session-capabilities.ts +35 -24
  101. package/src/hooks/use-session-events.ts +18 -4
  102. package/src/hooks/use-transcription.ts +4 -14
  103. package/src/hooks/use-turn-queue.ts +17 -5
  104. package/src/hooks/use-voice-input.ts +481 -36
  105. package/src/hooks/use-windowed-sections.ts +9 -7
  106. package/src/index.ts +11 -6
  107. package/src/lib/composer-responsive-context.ts +15 -0
  108. package/src/lib/use-portal-token-style.ts +60 -15
  109. package/src/provider.tsx +52 -7
  110. package/src/realtime/dropdown-menu.tsx +15 -19
  111. package/src/realtime/realtime-control.tsx +18 -7
  112. package/src/timeline/activity-rail.tsx +15 -6
  113. package/src/timeline/index.ts +1 -1
  114. package/src/timeline/parsers.ts +33 -20
  115. package/src/timeline/projection.ts +23 -0
  116. package/src/timeline/registry.ts +7 -0
  117. package/src/timeline/screenshot-lightbox.tsx +15 -4
  118. package/src/timeline/shared.tsx +8 -8
  119. package/src/timeline/tool-renderers.tsx +166 -22
  120. package/src/timeline/turn-summary.tsx +6 -6
  121. package/src/timeline/types.ts +4 -0
  122. package/src/voice-recording-store.ts +15 -0
  123. package/styles/compiled.css +5065 -0
  124. package/styles/compiled.d.ts +2 -0
  125. package/styles/effective-tokens.css +27 -0
  126. package/styles/index.css +3 -0
  127. package/styles/responsive.css +196 -0
  128. package/styles/responsive.d.ts +2 -0
  129. package/styles/tokens.css +50 -17
  130. package/dist/chunk-6EDV6YFE.js.map +0 -1
  131. package/dist/chunk-EB67J347.js.map +0 -1
  132. package/dist/chunk-EHSYZ4KP.js.map +0 -1
  133. package/dist/chunk-FD72GJMK.js.map +0 -1
  134. package/dist/chunk-JB5725BI.js +0 -48
  135. package/dist/chunk-JB5725BI.js.map +0 -1
  136. package/dist/chunk-L3EWO3UK.js.map +0 -1
  137. package/dist/chunk-LWR4MXSS.js.map +0 -1
  138. package/dist/chunk-SRFUT2ZU.js.map +0 -1
  139. package/dist/chunk-U3CSCMWA.js.map +0 -1
  140. package/dist/queue-surface-implementation-J4XJFKRW.js.map +0 -1
  141. /package/dist/{chunk-HFO4ERGQ.js.map → chunk-FWXGSNXT.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/realtime/realtime-control.tsx","../src/realtime/dropdown-menu.tsx"],"sourcesContent":["import { type EffectiveSessionControl, type SessionEvent, type SessionStatus } from \"@opengeni/sdk\";\nimport {\n hasStoredSessionRealtimeOwnerProof,\n projectSessionRealtimeLifecycle,\n type SessionRealtimeClientLike,\n type SessionRealtimeController,\n type SessionRealtimeControllerSnapshot,\n type CreateSessionRealtimeControllerOptions,\n type SessionRealtimeModel,\n type WorkspaceRealtimeModelCatalogItem,\n} from \"@opengeni/sdk/realtime\";\nimport {\n AudioLinesIcon,\n CheckIcon,\n ChevronDownIcon,\n CircleAlertIcon,\n LoaderCircleIcon,\n MicIcon,\n MicOffIcon,\n RotateCcwIcon,\n SquareIcon,\n Volume2Icon,\n VolumeXIcon,\n} from \"lucide-react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\nimport {\n type ReactNode,\n type RefObject,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport {\n BillingClassMark,\n PickerAnimatedPage,\n PickerBackHeader,\n PickerNavRow,\n} from \"../components/model-policy-picker\";\nimport type { EmbeddedRealtimeSessionClientLike } from \"../client\";\nimport { cn } from \"../lib/cn\";\nimport type { PickerBillingClass as BillingClass } from \"../model-policy\";\nimport { useEmbeddedRealtimeSession } from \"../session-context\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n} from \"./dropdown-menu\";\n\nexport type RealtimeModelOption = {\n id: SessionRealtimeModel;\n label: string;\n provider: \"OpenGeni\" | \"Connected Codex\" | \"Your Gateway\";\n description: string;\n available: boolean;\n unavailableReason: string | null;\n recommended: boolean;\n};\n\nconst CODEX_LIVE_MODEL: RealtimeModelOption = {\n id: \"gpt-live-1-boulder-alpha\",\n label: \"Codex Live\",\n provider: \"Connected Codex\",\n description: \"Deep session integration\",\n available: false,\n unavailableReason: \"Connect Codex to use this voice model\",\n recommended: false,\n};\n\nconst REALTIME_MODEL_PROVIDERS = [\"OpenGeni\", \"Connected Codex\", \"Your Gateway\"] as const;\ntype RealtimeModelProvider = (typeof REALTIME_MODEL_PROVIDERS)[number];\n\nconst REALTIME_PROVIDER_META: Record<\n RealtimeModelProvider,\n { billingClass: BillingClass; hint: string }\n> = {\n OpenGeni: { billingClass: \"opengeni_credits\", hint: \"Will use credits\" },\n \"Connected Codex\": {\n billingClass: \"codex_subscription\",\n hint: \"ChatGPT / Codex plan\",\n },\n \"Your Gateway\": { billingClass: \"byok\", hint: \"Billed to your AI Gateway\" },\n};\nconst REALTIME_MODEL_STORAGE_PREFIX = \"opengeni:realtime-model\";\n\ntype RealtimeControllerClient = EmbeddedRealtimeSessionClientLike & SessionRealtimeClientLike;\n\nexport type SessionRealtimeControllerFactory = (\n options: CreateSessionRealtimeControllerOptions,\n) => SessionRealtimeController;\n\ntype AdmissionInput = {\n sessionStatus: SessionStatus;\n controlState: \"active\" | \"paused\";\n settlement: { state: string } | null;\n codexConnected: boolean;\n lifecycleActive: boolean;\n};\n\nexport function codexRealtimeAdmissionAllowed(input: AdmissionInput): boolean {\n return codexRealtimeAdmissionBlocker(input) === null;\n}\n\nexport function codexRealtimeAdmissionBlocker(input: AdmissionInput): string | null {\n if (input.sessionStatus === \"cancelled\") return \"This session was cancelled.\";\n if (input.controlState !== \"active\") return \"Resume this session before starting voice.\";\n if (input.settlement !== null) return \"Wait for the current session transition to finish.\";\n if (!input.codexConnected) return \"Connect Codex to use this voice model.\";\n if (input.lifecycleActive) return \"Voice is already active for this session.\";\n return null;\n}\n\nexport function useSessionRealtime(options: {\n client?: RealtimeControllerClient | undefined;\n workspaceId?: string | undefined;\n sessionId: string;\n sessionStatus: SessionStatus;\n effectiveControl: EffectiveSessionControl;\n events: SessionEvent[];\n eventsReady: boolean;\n codexConnected: boolean;\n model?: SessionRealtimeModel | undefined;\n modelAvailable?: boolean | undefined;\n modelUnavailableReason?: string | null | undefined;\n /** Deterministic browser-test/demo seam. Production hosts should use the SDK default. */\n controllerFactory?: SessionRealtimeControllerFactory | undefined;\n}) {\n const { client, workspaceId } = useEmbeddedRealtimeSession({\n client: options.client,\n workspaceId: options.workspaceId,\n });\n const model = options.model ?? CODEX_LIVE_MODEL.id;\n const audioRef = useRef<HTMLAudioElement>(null);\n const controllerRef = useRef<SessionRealtimeController | null>(null);\n const controllerModelRef = useRef<SessionRealtimeModel | null>(null);\n const [snapshot, setSnapshot] = useState<SessionRealtimeControllerSnapshot>(() => ({\n status: hasStoredSessionRealtimeOwnerProof({ workspaceId, sessionId: options.sessionId, model })\n ? \"recovering\"\n : \"idle\",\n realtimeId: null,\n mode: null,\n bridge: null,\n microphone: \"inactive\",\n inputMuted: false,\n audibleOutput: \"inactive\",\n outputMuted: false,\n connectionGeneration: 0,\n reconnectAttempt: 0,\n diagnostic: null,\n error: null,\n }));\n const lifecycle = useMemo(\n () => projectSessionRealtimeLifecycle(options.events),\n [options.events],\n );\n const lifecycleRef = useRef(lifecycle);\n const eventsReadyRef = useRef(options.eventsReady);\n lifecycleRef.current = lifecycle;\n eventsReadyRef.current = options.eventsReady;\n const lifecycleActive = lifecycle?.state === \"active\";\n\n useEffect(() => {\n let disposed = false;\n let controller: SessionRealtimeController | null = null;\n let unsubscribe: (() => void) | null = null;\n void import(\"@opengeni/sdk/realtime\")\n .then(({ createSessionRealtimeController }) => {\n if (disposed) return;\n const controllerFactory = options.controllerFactory ?? createSessionRealtimeController;\n controller = controllerFactory({\n client,\n workspaceId,\n sessionId: options.sessionId,\n ...(audioRef.current ? { remoteAudio: audioRef.current } : {}),\n model,\n });\n controllerRef.current = controller;\n controllerModelRef.current = model;\n unsubscribe = controller.subscribe(setSnapshot);\n if (eventsReadyRef.current) {\n void controller.observeLifecycle(lifecycleRef.current).catch(() => undefined);\n }\n })\n .catch((error: unknown) => {\n if (disposed) return;\n setSnapshot({\n status: \"error\",\n realtimeId: null,\n mode: null,\n bridge: null,\n microphone: \"inactive\",\n inputMuted: false,\n audibleOutput: \"inactive\",\n outputMuted: false,\n connectionGeneration: 0,\n reconnectAttempt: 0,\n diagnostic: {\n kind: \"negotiation_failure\",\n message:\n error instanceof Error ? error.message : \"Codex realtime controller failed to load\",\n recoverable: false,\n connectionGeneration: 0,\n attempt: 0,\n },\n error:\n error instanceof Error ? error.message : \"Codex realtime controller failed to load\",\n });\n });\n return () => {\n disposed = true;\n unsubscribe?.();\n controller?.close();\n if (controllerRef.current === controller) {\n controllerRef.current = null;\n controllerModelRef.current = null;\n }\n };\n }, [client, model, options.controllerFactory, options.sessionId, workspaceId]);\n\n useEffect(() => {\n if (!options.eventsReady) return;\n void controllerRef.current?.observeLifecycle(lifecycle).catch(() => undefined);\n }, [lifecycle, options.eventsReady]);\n\n const start = useCallback(async () => {\n const controller = controllerRef.current;\n if (!controller || controllerModelRef.current !== model) {\n throw new Error(\"The selected voice model is still preparing\");\n }\n await controller.start();\n }, [model]);\n const stop = useCallback(async () => {\n await controllerRef.current?.stop();\n }, []);\n const retry = useCallback(async () => {\n await controllerRef.current?.retry();\n }, []);\n const retryAudibleOutput = useCallback(async () => {\n await controllerRef.current?.retryAudibleOutput();\n }, []);\n const setInputMuted = useCallback((muted: boolean) => {\n controllerRef.current?.setInputMuted(muted);\n }, []);\n const setOutputMuted = useCallback((muted: boolean) => {\n controllerRef.current?.setOutputMuted(muted);\n }, []);\n const admissionInput = {\n sessionStatus: options.sessionStatus,\n controlState: options.effectiveControl.state,\n settlement: options.effectiveControl.settlement,\n codexConnected: options.modelAvailable ?? options.codexConnected,\n lifecycleActive,\n } satisfies AdmissionInput;\n const admissionBlocker =\n options.modelAvailable === false\n ? (options.modelUnavailableReason ?? \"This voice model is unavailable.\")\n : codexRealtimeAdmissionBlocker(admissionInput);\n const canStart =\n controllerRef.current !== null &&\n controllerModelRef.current === model &&\n [\"idle\", \"error\"].includes(snapshot.status) &&\n admissionBlocker === null;\n\n return {\n snapshot,\n lifecycleActive,\n canStart,\n admissionBlocker,\n codexConnected: options.codexConnected,\n audioRef,\n start,\n stop,\n retry,\n retryAudibleOutput,\n setInputMuted,\n setOutputMuted,\n };\n}\n\nexport function SessionRealtimeControl(props: {\n client?: RealtimeControllerClient | undefined;\n workspaceId?: string | undefined;\n sessionId: string;\n sessionStatus: SessionStatus;\n effectiveControl: EffectiveSessionControl;\n events: SessionEvent[];\n eventsReady: boolean;\n codexConnected: boolean;\n realtimeAutostartModel?: SessionRealtimeModel | undefined;\n onRealtimeAutostartConsumed?: (() => void) | undefined;\n /** Host hides dictate (and can choreograph layout) while realtime voice is live. */\n onVoiceActiveChange?: ((active: boolean) => void) | undefined;\n /** Deterministic browser-test/demo seam. Production hosts should use the SDK default. */\n controllerFactory?: SessionRealtimeControllerFactory | undefined;\n}) {\n const lifecycle = useMemo(() => projectSessionRealtimeLifecycle(props.events), [props.events]);\n const selection = useRealtimeModelSelection({\n client: props.client,\n workspaceId: props.workspaceId,\n codexConnected: props.codexConnected,\n activeModel: lifecycle?.state === \"active\" ? lifecycle.model : null,\n });\n const selectedModel = selection.selectedModel;\n const realtime = useSessionRealtime({\n ...props,\n model: selectedModel.id,\n modelAvailable: selectedModel.available,\n modelUnavailableReason: selectedModel.unavailableReason,\n });\n const autostartModelRef = useRef(props.realtimeAutostartModel ?? null);\n const autostartStartedRef = useRef(false);\n\n const { models, selectedModel: selectedRealtimeModel, selectModel } = selection;\n const { canStart, start } = realtime;\n const onRealtimeAutostartConsumed = props.onRealtimeAutostartConsumed;\n const onVoiceActiveChange = props.onVoiceActiveChange;\n const voiceActive = realtime.snapshot.mode?.state === \"active\";\n\n useEffect(() => {\n onVoiceActiveChange?.(voiceActive);\n }, [onVoiceActiveChange, voiceActive]);\n\n useEffect(() => {\n const pending = autostartModelRef.current;\n if (!pending || autostartStartedRef.current || lifecycle?.state === \"active\") return;\n const available = models.some((model) => model.id === pending && model.available);\n if (!available) return;\n if (selectedRealtimeModel.id !== pending) {\n selectModel(pending);\n return;\n }\n if (!canStart) return;\n autostartStartedRef.current = true;\n void start()\n .then(() => {\n autostartModelRef.current = null;\n onRealtimeAutostartConsumed?.();\n })\n .catch(() => {\n autostartStartedRef.current = false;\n });\n }, [\n canStart,\n lifecycle?.state,\n models,\n props.sessionId,\n props.workspaceId,\n onRealtimeAutostartConsumed,\n selectModel,\n selectedRealtimeModel.id,\n start,\n ]);\n\n return (\n <RealtimeVoiceControl\n snapshot={realtime.snapshot}\n canStart={realtime.canStart}\n admissionBlocker={realtime.admissionBlocker}\n modelAvailable={selectedModel.available}\n menuSide=\"top\"\n audioRef={realtime.audioRef}\n selectedModel={selectedModel}\n models={selection.models}\n onSelectModel={realtime.lifecycleActive ? undefined : selection.selectModel}\n onStart={realtime.start}\n onStop={realtime.stop}\n onRetry={realtime.retry}\n onRetryAudibleOutput={realtime.retryAudibleOutput}\n onSetInputMuted={realtime.setInputMuted}\n onSetOutputMuted={realtime.setOutputMuted}\n />\n );\n}\n\nexport function useRealtimeModelSelection(options: {\n client?: RealtimeControllerClient | undefined;\n workspaceId?: string | undefined;\n codexConnected: boolean;\n activeModel?: SessionRealtimeModel | null | undefined;\n}) {\n const { client, workspaceId } = useEmbeddedRealtimeSession({\n client: options.client,\n workspaceId: options.workspaceId,\n });\n const activeModel = options.activeModel;\n const [catalog, setCatalog] = useState<RealtimeModelOption[]>(() => [\n {\n ...CODEX_LIVE_MODEL,\n available: options.codexConnected,\n unavailableReason: options.codexConnected ? null : CODEX_LIVE_MODEL.unavailableReason,\n },\n ]);\n const [selectedModelId, setSelectedModelId] = useState<SessionRealtimeModel>(\n () => readRealtimeModelPreference(workspaceId) ?? CODEX_LIVE_MODEL.id,\n );\n\n useEffect(() => {\n let disposed = false;\n const load = client.getWorkspaceRealtimeModelCatalog;\n if (!load) return;\n void load\n .call(client, workspaceId)\n .then((response) => {\n if (disposed) return;\n const models = response.models.map(toRealtimeModelOption);\n setCatalog(models);\n setSelectedModelId((current) => {\n if (models.some((model) => model.id === current && model.available)) return current;\n return models.find((model) => model.available)?.id ?? CODEX_LIVE_MODEL.id;\n });\n })\n .catch(() => undefined);\n return () => {\n disposed = true;\n };\n }, [client, workspaceId]);\n\n useEffect(() => {\n if (activeModel) setSelectedModelId(activeModel);\n }, [activeModel]);\n\n const selectedModel =\n catalog.find((model) => model.id === selectedModelId) ??\n ({\n ...CODEX_LIVE_MODEL,\n available: options.codexConnected,\n unavailableReason: options.codexConnected ? null : CODEX_LIVE_MODEL.unavailableReason,\n } satisfies RealtimeModelOption);\n const selectModel = useCallback(\n (value: string) => {\n const model = catalog.find((candidate) => candidate.id === value);\n if (!model || !model.available || activeModel) return;\n setSelectedModelId(model.id);\n writeRealtimeModelPreference(workspaceId, model.id);\n },\n [activeModel, catalog, workspaceId],\n );\n\n return { models: catalog, selectedModel, selectModel };\n}\n\nconst IDLE_REALTIME_SNAPSHOT: SessionRealtimeControllerSnapshot = {\n status: \"idle\",\n realtimeId: null,\n mode: null,\n bridge: null,\n microphone: \"inactive\",\n inputMuted: false,\n audibleOutput: \"inactive\",\n outputMuted: false,\n connectionGeneration: 0,\n reconnectAttempt: 0,\n diagnostic: null,\n error: null,\n};\n\nexport function NewSessionRealtimeControl(props: {\n client?: RealtimeControllerClient | undefined;\n workspaceId?: string | undefined;\n codexConnected: boolean;\n disabled?: boolean | undefined;\n disabledReason?: string | null | undefined;\n onStart: (model: SessionRealtimeModel) => Promise<boolean>;\n /** Parent-owned selection (e.g. shared with the mobile “+” voice-model panel). */\n models?: readonly RealtimeModelOption[] | undefined;\n selectedModel?: RealtimeModelOption | undefined;\n onSelectModel?: ((modelId: string) => void) | undefined;\n /**\n * `split` attaches the model chevron at every breakpoint (public default).\n * `split-desktop` hides it below `sm` when the host owns mobile selection (e.g. “+”).\n * `none` never attaches a model menu to the bar button.\n */\n modelMenu?: \"split\" | \"split-desktop\" | \"none\" | undefined;\n}) {\n const internalSelection = useRealtimeModelSelection({\n client: props.client,\n workspaceId: props.workspaceId,\n codexConnected: props.codexConnected,\n });\n const selection =\n props.models && props.selectedModel && props.onSelectModel\n ? {\n models: props.models,\n selectedModel: props.selectedModel,\n selectModel: props.onSelectModel,\n }\n : internalSelection;\n const audioRef = useRef<HTMLAudioElement>(null);\n const [starting, setStarting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const snapshot = useMemo<SessionRealtimeControllerSnapshot>(\n () =>\n starting\n ? { ...IDLE_REALTIME_SNAPSHOT, status: \"starting\" }\n : error\n ? { ...IDLE_REALTIME_SNAPSHOT, status: \"error\", error }\n : IDLE_REALTIME_SNAPSHOT,\n [error, starting],\n );\n const canStart = selection.selectedModel.available && props.disabled !== true && !starting;\n const onStart = props.onStart;\n const selectedModelId = selection.selectedModel.id;\n const start = useCallback(async () => {\n if (!canStart) return;\n setStarting(true);\n setError(null);\n try {\n const started = await onStart(selectedModelId);\n if (!started) setError(\"The voice session could not be created.\");\n } catch (cause) {\n setError(cause instanceof Error ? cause.message : String(cause));\n } finally {\n setStarting(false);\n }\n }, [canStart, onStart, selectedModelId]);\n\n return (\n <RealtimeVoiceControl\n snapshot={snapshot}\n canStart={canStart}\n admissionBlocker={selection.selectedModel.unavailableReason ?? props.disabledReason ?? null}\n modelAvailable={selection.selectedModel.available}\n selectionDisabled={starting}\n menuSide=\"bottom\"\n modelMenu={props.modelMenu ?? \"split\"}\n showDiagnostics={false}\n audioRef={audioRef}\n selectedModel={selection.selectedModel}\n models={selection.models}\n onSelectModel={selection.selectModel}\n onStart={start}\n onStop={async () => undefined}\n onRetry={start}\n onRetryAudibleOutput={async () => undefined}\n onSetInputMuted={() => undefined}\n onSetOutputMuted={() => undefined}\n />\n );\n}\n\nexport function RealtimeVoiceControl(props: {\n snapshot: SessionRealtimeControllerSnapshot;\n canStart: boolean;\n admissionBlocker?: string | null | undefined;\n modelAvailable: boolean;\n selectionDisabled?: boolean | undefined;\n /** Prefer `bottom` on home/new-session; `top` for the docked session composer. */\n menuSide?: \"top\" | \"bottom\" | undefined;\n /**\n * `split` = start + model chevron at every breakpoint (public SDK default).\n * `split-desktop` = chevron from `sm` up; below that the host owns selection.\n * `none` = start button only.\n */\n modelMenu?: \"split\" | \"split-desktop\" | \"none\" | undefined;\n showDiagnostics?: boolean;\n /** Extra classes on the in-bar mute cluster (e.g. `max-sm:hidden` when mutes live in “+”). */\n muteControlsClassName?: string | undefined;\n audioRef: RefObject<HTMLAudioElement | null>;\n selectedModel?: RealtimeModelOption | undefined;\n models?: readonly RealtimeModelOption[] | undefined;\n onSelectModel?: ((modelId: string) => void) | undefined;\n onStart: () => Promise<void>;\n onStop: () => Promise<void>;\n onRetry: () => Promise<void>;\n onRetryAudibleOutput: () => Promise<void>;\n onSetInputMuted: (muted: boolean) => void;\n onSetOutputMuted: (muted: boolean) => void;\n}) {\n const reduceMotion = useReducedMotion();\n const selectedModel = props.selectedModel ?? {\n ...CODEX_LIVE_MODEL,\n available: props.modelAvailable,\n unavailableReason: props.modelAvailable ? null : CODEX_LIVE_MODEL.unavailableReason,\n };\n const models = props.models ?? [selectedModel];\n const status = statusContent(\n props.snapshot,\n props.modelAvailable,\n props.canStart,\n props.admissionBlocker ?? null,\n selectedModel.label,\n );\n const modeOwned = props.snapshot.mode?.state === \"active\";\n const retryConnection =\n modeOwned &&\n props.snapshot.status !== \"stopping\" &&\n props.snapshot.status !== \"active\" &&\n props.snapshot.diagnostic?.recoverable === true;\n const audioBlocked = props.snapshot.audibleOutput === \"blocked\" && !props.snapshot.outputMuted;\n const mainDisabled =\n props.snapshot.status === \"stopping\" ||\n props.snapshot.status === \"lost_owner\" ||\n (!modeOwned && !props.canStart) ||\n (props.snapshot.status === \"starting\" && !modeOwned);\n const mainLabel = audioBlocked\n ? \"Resume voice audio\"\n : retryConnection\n ? \"Retry voice connection\"\n : modeOwned\n ? \"End voice conversation\"\n : `Start voice with ${selectedModel.label}`;\n const runMainAction = audioBlocked\n ? props.onRetryAudibleOutput\n : retryConnection\n ? props.onRetry\n : modeOwned\n ? props.onStop\n : props.onStart;\n const diagnosticsVisible = props.showDiagnostics ?? import.meta.env.DEV;\n const modelMenu = props.modelMenu ?? \"split\";\n const showAttachedModelMenu = modelMenu === \"split\" || modelMenu === \"split-desktop\";\n const desktopOnlyModelMenu = modelMenu === \"split-desktop\";\n const [pickerOpen, setPickerOpen] = useState(false);\n const [pickerProvider, setPickerProvider] = useState<RealtimeModelProvider | null>(\n selectedModel.provider,\n );\n const [pickerDirection, setPickerDirection] = useState<1 | -1>(1);\n\n useEffect(() => {\n if (!pickerOpen) setPickerProvider(selectedModel.provider);\n }, [pickerOpen, selectedModel.provider]);\n\n return (\n <div\n role=\"group\"\n aria-label=\"Realtime voice\"\n data-picker-side={props.menuSide ?? \"top\"}\n className=\"inline-flex shrink-0 items-center\"\n >\n <audio ref={props.audioRef} autoPlay className=\"hidden\" aria-hidden=\"true\" />\n <RealtimeComposerGlow phase={status.phase} reduceMotion={reduceMotion === true} />\n <AnimatePresence initial={false}>\n {modeOwned ? (\n <motion.div\n key=\"realtime-mute-controls\"\n data-testid=\"realtime-mute-controls\"\n // After dictate collapses and the model slides left, bloom mutes\n // out from the primary voice control. Exit is immediate (no delay).\n initial={reduceMotion ? false : { opacity: 0, width: 0 }}\n animate={{\n opacity: 1,\n width: \"auto\",\n transition: reduceMotion\n ? { duration: 0 }\n : { delay: 0.3, duration: 0.48, ease: [0.22, 1, 0.36, 1] },\n }}\n {...(reduceMotion\n ? {}\n : {\n exit: {\n opacity: 0,\n width: 0,\n transition: { duration: 0.28, ease: [0.4, 0, 1, 1] },\n },\n })}\n className={cn(\n \"inline-flex shrink-0 items-center overflow-hidden\",\n props.muteControlsClassName,\n )}\n >\n <motion.div\n className=\"inline-flex items-center gap-0.5 pr-1\"\n initial={reduceMotion ? false : { x: 18, opacity: 0 }}\n animate={{\n x: 0,\n opacity: 1,\n transition: reduceMotion\n ? { duration: 0 }\n : { delay: 0.32, type: \"spring\", stiffness: 320, damping: 30, mass: 0.8 },\n }}\n {...(reduceMotion\n ? {}\n : {\n exit: {\n x: 14,\n opacity: 0,\n transition: { duration: 0.22, ease: [0.4, 0, 1, 1] },\n },\n })}\n >\n <RealtimeMuteButton\n muted={props.snapshot.inputMuted}\n kind=\"microphone\"\n reduceMotion={reduceMotion === true}\n enterDelay={reduceMotion ? 0 : 0.34}\n onToggle={() => props.onSetInputMuted(!props.snapshot.inputMuted)}\n />\n <RealtimeMuteButton\n muted={props.snapshot.outputMuted}\n kind=\"output\"\n reduceMotion={reduceMotion === true}\n enterDelay={reduceMotion ? 0 : 0.4}\n onToggle={() => props.onSetOutputMuted(!props.snapshot.outputMuted)}\n />\n </motion.div>\n </motion.div>\n ) : null}\n </AnimatePresence>\n <div className=\"inline-flex shrink-0 items-center\">\n <motion.button\n type=\"button\"\n data-testid=\"realtime-primary-action\"\n data-phase={status.phase}\n aria-label={mainLabel}\n aria-pressed={modeOwned}\n title={mainLabel}\n disabled={mainDisabled}\n {...(reduceMotion ? {} : { whileTap: { scale: 0.92 } })}\n transition={{ type: \"spring\", stiffness: 520, damping: 30 }}\n onClick={() => void runMainAction().catch(() => undefined)}\n className={cn(\n // Match transcription mic: ghost icon when idle; filled only when live.\n // Public contract: coarse pointers keep a 44px target; split menu uses\n // left-only rounding at `sm+` where the chevron attaches.\n \"relative inline-flex size-8 items-center justify-center outline-none\",\n \"rounded-og-md transition-[background-color,border-color,color,box-shadow] duration-200 ease-og-out\",\n \"focus-visible:z-10 focus-visible:ring-2 focus-visible:ring-og-accent/45\",\n \"disabled:cursor-not-allowed disabled:opacity-45 pointer-coarse:size-11\",\n showAttachedModelMenu &&\n (desktopOnlyModelMenu\n ? \"sm:rounded-l-og-md sm:rounded-r-none\"\n : \"rounded-l-og-md rounded-r-none\"),\n voiceButtonTone(status.phase),\n )}\n >\n <RealtimeActionGlyph\n phase={status.phase}\n audioBlocked={audioBlocked}\n reduceMotion={reduceMotion === true}\n />\n </motion.button>\n\n {showAttachedModelMenu ? (\n <DropdownMenu open={pickerOpen} onOpenChange={setPickerOpen}>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n aria-label=\"Choose voice model and options\"\n title={`Voice model: ${selectedModel.label}`}\n disabled={props.selectionDisabled}\n className={cn(\n // ≥24px wide so WCAG 2.2 target-size passes when the chevron is shown.\n \"inline-flex h-8 w-6 items-center justify-center rounded-r-og-md outline-none\",\n \"transition-[background-color,border-color,color] duration-200 ease-og-out\",\n \"focus-visible:z-10 focus-visible:ring-2 focus-visible:ring-og-accent/45\",\n \"pointer-coarse:h-11 pointer-coarse:w-7\",\n desktopOnlyModelMenu && \"hidden sm:inline-flex\",\n voiceChevronTone(status.phase),\n )}\n >\n <ChevronDownIcon className=\"size-3\" aria-hidden />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n side={props.menuSide ?? \"top\"}\n align=\"end\"\n sideOffset={8}\n collisionPadding={12}\n className=\"flex w-72 max-h-[min(20rem,var(--radix-dropdown-menu-content-available-height))] flex-col overflow-hidden rounded-xl border-border bg-surface p-1.5 shadow-xl\"\n onCloseAutoFocus={(event) => event.preventDefault()}\n >\n <div className=\"min-h-0 flex-1 overflow-y-auto overscroll-contain\">\n <RealtimeModelPickerMenu\n models={models}\n selectedModel={selectedModel}\n provider={pickerProvider}\n direction={pickerDirection}\n disabled={\n props.selectionDisabled === true || props.snapshot.mode?.state === \"active\"\n }\n onProviderChange={(provider, direction) => {\n setPickerDirection(direction);\n setPickerProvider(provider);\n }}\n onSelect={(modelId) => {\n props.onSelectModel?.(modelId);\n setPickerOpen(false);\n }}\n />\n </div>\n\n {status.phase !== \"idle\" ? (\n <>\n <DropdownMenuSeparator className=\"mx-1 bg-og-border\" />\n <div className=\"px-2.5 py-2\" role=\"status\" aria-live=\"polite\">\n <div className=\"flex items-center gap-2 text-og-sm font-medium text-og-fg\">\n <RealtimeStatusDot\n phase={status.phase}\n reduceMotion={reduceMotion === true}\n />\n {status.label}\n </div>\n <p className=\"mt-1 text-og-xs leading-5 text-og-fg-subtle\">{status.detail}</p>\n </div>\n </>\n ) : null}\n\n {audioBlocked ? (\n <DropdownMenuItem\n className=\"rounded-og-md\"\n onSelect={() => void props.onRetryAudibleOutput().catch(() => undefined)}\n >\n <Volume2Icon />\n Resume audio\n </DropdownMenuItem>\n ) : null}\n {retryConnection ? (\n <DropdownMenuItem\n className=\"rounded-og-md\"\n onSelect={() => void props.onRetry().catch(() => undefined)}\n >\n <RotateCcwIcon />\n Retry connection\n </DropdownMenuItem>\n ) : null}\n {modeOwned && props.snapshot.status !== \"lost_owner\" ? (\n <DropdownMenuItem\n variant=\"destructive\"\n className=\"rounded-og-md\"\n disabled={props.snapshot.status === \"stopping\"}\n onSelect={() => void props.onStop().catch(() => undefined)}\n >\n <SquareIcon />\n End voice conversation\n </DropdownMenuItem>\n ) : null}\n\n {diagnosticsVisible ? <RealtimeDiagnosticsMenu snapshot={props.snapshot} /> : null}\n </DropdownMenuContent>\n </DropdownMenu>\n ) : null}\n </div>\n\n <span className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n {status.label}. {status.detail}\n </span>\n {props.snapshot.error ? (\n <span className=\"sr-only\" role=\"alert\">\n {props.snapshot.error}\n </span>\n ) : null}\n </div>\n );\n}\n\n/** Drill-in body for the mobile composer “+” menu — same catalog as the desktop chevron. */\nexport function RealtimeVoiceModelPanel(props: {\n models: readonly RealtimeModelOption[];\n selectedModel: RealtimeModelOption;\n disabled?: boolean | undefined;\n leading?: ReactNode | undefined;\n onSelect: (modelId: SessionRealtimeModel) => void;\n}) {\n const [provider, setProvider] = useState<RealtimeModelProvider | null>(null);\n const [direction, setDirection] = useState<1 | -1>(1);\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col\" data-testid=\"realtime-voice-model-panel\">\n <div className=\"flex shrink-0 items-start gap-1 px-2 pt-1 pb-1.5\">\n {props.leading}\n <div className=\"min-w-0\">\n <div className=\"text-og-menu font-medium text-og-fg\">Voice model</div>\n <p className=\"mt-0.5 text-og-control text-og-fg-subtle\">\n Used when you start a voice conversation.\n </p>\n </div>\n </div>\n <div className=\"min-h-0 flex-1 overflow-y-auto overscroll-contain px-1.5 pb-1.5\">\n <RealtimeModelPickerMenu\n models={props.models}\n selectedModel={props.selectedModel}\n provider={provider}\n direction={direction}\n disabled={props.disabled === true}\n onProviderChange={(next, nextDirection) => {\n setDirection(nextDirection);\n setProvider(next);\n }}\n onSelect={props.onSelect}\n />\n </div>\n </div>\n );\n}\n\nfunction RealtimeMuteButton(props: {\n muted: boolean;\n kind: \"microphone\" | \"output\";\n reduceMotion: boolean;\n enterDelay?: number | undefined;\n onToggle(): void;\n}) {\n const microphone = props.kind === \"microphone\";\n const label = microphone\n ? props.muted\n ? \"Unmute microphone\"\n : \"Mute microphone\"\n : props.muted\n ? \"Unmute voice audio\"\n : \"Mute voice audio\";\n const Icon = microphone\n ? props.muted\n ? MicOffIcon\n : MicIcon\n : props.muted\n ? VolumeXIcon\n : Volume2Icon;\n\n return (\n <motion.button\n type=\"button\"\n aria-label={label}\n aria-pressed={props.muted}\n title={label}\n initial={props.reduceMotion ? false : { scale: 0.72, opacity: 0 }}\n animate={{ scale: 1, opacity: 1 }}\n transition={{\n delay: props.enterDelay ?? 0,\n type: \"spring\",\n stiffness: 420,\n damping: 26,\n mass: 0.7,\n }}\n {...(props.reduceMotion ? {} : { whileTap: { scale: 0.92 } })}\n onClick={props.onToggle}\n className={cn(\n \"inline-flex size-8 shrink-0 items-center justify-center rounded-og-md outline-none\",\n \"transition-[background-color,border-color,color] duration-150 ease-og-out\",\n \"focus-visible:ring-2 focus-visible:ring-og-accent/45 pointer-coarse:size-11\",\n props.muted\n ? \"border border-og-accent/35 bg-og-accent-soft text-og-accent\"\n : \"text-og-fg-muted hover:bg-og-surface-2 hover:text-og-fg\",\n )}\n >\n <Icon className=\"size-3.5\" aria-hidden />\n </motion.button>\n );\n}\n\nexport function RealtimeModelPickerMenu(props: {\n models: readonly RealtimeModelOption[];\n selectedModel: RealtimeModelOption;\n provider: RealtimeModelProvider | null;\n direction: 1 | -1;\n disabled: boolean;\n onProviderChange: (provider: RealtimeModelProvider | null, direction: 1 | -1) => void;\n onSelect: (modelId: SessionRealtimeModel) => void;\n}) {\n const providers = REALTIME_MODEL_PROVIDERS.filter((provider) =>\n props.models.some((model) => model.provider === provider),\n );\n const pageKey = props.provider ? `voice-models:${props.provider}` : \"voice-providers\";\n const body = props.provider ? (\n <div data-testid=\"realtime-model-picker-models\">\n <PickerBackHeader\n label={props.provider}\n icon={\n <BillingClassMark\n billingClass={REALTIME_PROVIDER_META[props.provider].billingClass}\n aria-label=\"\"\n />\n }\n onBack={() => props.onProviderChange(null, -1)}\n />\n <div className=\"flex flex-col gap-0.5\">\n {props.models\n .filter((model) => model.provider === props.provider)\n .map((model) => {\n const selected = model.id === props.selectedModel.id;\n return (\n <PickerNavRow\n key={model.id}\n label={model.label}\n hint={\n model.unavailableReason ??\n (model.recommended ? `Recommended · ${model.description}` : model.description)\n }\n disabled={props.disabled || !model.available}\n title={model.unavailableReason ?? model.description}\n active={selected}\n showChevron={false}\n trailing={selected ? <CheckIcon className=\"size-3.5\" aria-hidden /> : undefined}\n testId={`realtime-model-choice-${model.id}`}\n onClick={() => props.onSelect(model.id)}\n />\n );\n })}\n </div>\n </div>\n ) : (\n <div className=\"flex flex-col gap-0.5\" data-testid=\"realtime-model-picker-providers\">\n {providers.map((provider) => {\n const meta = REALTIME_PROVIDER_META[provider];\n return (\n <PickerNavRow\n key={provider}\n label={provider}\n hint={meta.hint}\n icon={<BillingClassMark billingClass={meta.billingClass} aria-label=\"\" />}\n active={props.selectedModel.provider === provider}\n testId={`realtime-model-provider-${meta.billingClass}`}\n onClick={() => props.onProviderChange(provider, 1)}\n />\n );\n })}\n </div>\n );\n\n return (\n <div className=\"relative overflow-hidden\" data-testid=\"realtime-model-picker-menu\">\n <PickerAnimatedPage pageKey={pageKey} direction={props.direction}>\n {body}\n </PickerAnimatedPage>\n </div>\n );\n}\n\nfunction RealtimeDiagnosticsMenu({ snapshot }: { snapshot: SessionRealtimeControllerSnapshot }) {\n const bridge = snapshot.bridge;\n const rows = [\n [\"controller\", snapshot.status],\n [\"microphone\", snapshot.microphone],\n [\"microphone muted\", String(snapshot.inputMuted)],\n [\"audio\", snapshot.audibleOutput],\n [\"audio muted\", String(snapshot.outputMuted)],\n [\"generation\", String(snapshot.connectionGeneration)],\n [\"reconnect attempt\", String(snapshot.reconnectAttempt)],\n [\"mode\", snapshot.mode?.state ?? \"none\"],\n [\"mode version\", snapshot.mode ? String(snapshot.mode.version) : \"—\"],\n [\"connection epoch\", snapshot.mode ? String(snapshot.mode.connectionEpoch) : \"—\"],\n [\"provider started\", bridge ? String(bridge.providerStarted) : \"false\"],\n [\"provider speaking\", bridge ? String(bridge.speaking) : \"false\"],\n [\"delegation\", bridge?.activeDelegationId ? \"active\" : \"none\"],\n [\"pending durable events\", bridge ? String(bridge.pendingInbound) : \"0\"],\n [\"pending bytes\", bridge ? String(bridge.pendingInboundBytes) : \"0\"],\n [\"client ack\", bridge?.clientAckThroughSequence?.toString() ?? \"—\"],\n [\"ignored provider events\", bridge ? String(bridge.ignoredEventCount) : \"0\"],\n [\"last ignored event\", bridge?.lastIgnoredEventType ?? \"none\"],\n [\"bridge error\", bridge?.lastError ?? \"none\"],\n [\"diagnostic\", snapshot.diagnostic?.kind ?? \"none\"],\n ] as const;\n\n return (\n <>\n <DropdownMenuSeparator className=\"mx-1 bg-og-border\" />\n <DropdownMenuSub>\n <DropdownMenuSubTrigger className=\"rounded-og-md text-og-fg-muted\">\n Realtime diagnostics\n </DropdownMenuSubTrigger>\n <DropdownMenuSubContent className=\"max-h-80 w-72 overflow-y-auto rounded-og-lg border-og-border bg-og-surface-1 p-1.5 text-og-fg shadow-og-lg\">\n {rows.map(([label, value]) => (\n <DropdownMenuItem\n key={label}\n disabled\n className=\"grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)] gap-3 rounded-og-md font-mono text-[11px] opacity-100\"\n >\n <span className=\"truncate text-og-fg-subtle\">{label}</span>\n <span className=\"truncate text-right text-og-fg\">{value}</span>\n </DropdownMenuItem>\n ))}\n </DropdownMenuSubContent>\n </DropdownMenuSub>\n </>\n );\n}\n\ntype RealtimeVisualPhase =\n | \"idle\"\n | \"connecting\"\n | \"listening\"\n | \"speaking\"\n | \"reconnecting\"\n | \"blocked\"\n | \"unavailable\"\n | \"error\"\n | \"elsewhere\"\n | \"stopping\";\n\nfunction statusContent(\n snapshot: SessionRealtimeControllerSnapshot,\n modelAvailable: boolean,\n canStart: boolean,\n admissionBlocker: string | null,\n modelLabel: string,\n): { phase: RealtimeVisualPhase; label: string; detail: string } {\n if (snapshot.audibleOutput === \"blocked\" && !snapshot.outputMuted) {\n return {\n phase: \"blocked\",\n label: \"Audio output blocked\",\n detail: \"Resume audio to hear the existing voice connection.\",\n };\n }\n switch (snapshot.status) {\n case \"starting\":\n return {\n phase: \"connecting\",\n label: \"Connecting…\",\n detail: \"Preparing your microphone and live voice.\",\n };\n case \"active\":\n return snapshot.bridge?.speaking\n ? {\n phase: \"speaking\",\n label: \"Speaking\",\n detail: \"Interrupt naturally whenever you want.\",\n }\n : {\n phase: \"listening\",\n label: \"Listening\",\n detail: \"Voice and typed messages share this session.\",\n };\n case \"stopping\":\n return {\n phase: \"stopping\",\n label: \"Ending voice…\",\n detail: \"Saving the remaining conversation context.\",\n };\n case \"recovering\":\n return {\n phase: \"reconnecting\",\n label: \"Reconnecting…\",\n detail: snapshot.error ?? \"Keeping this voice conversation connected.\",\n };\n case \"lost_owner\":\n return {\n phase: \"elsewhere\",\n label: \"Voice active elsewhere\",\n detail: \"Return to the browser that started it, or wait for that connection to expire.\",\n };\n case \"error\":\n return {\n phase: \"error\",\n label: \"Voice unavailable\",\n detail: snapshot.error ?? \"The connection could not be started.\",\n };\n case \"idle\":\n if (!modelAvailable) {\n return {\n phase: \"unavailable\",\n label: \"Voice model unavailable\",\n detail: admissionBlocker ?? \"Choose another voice model.\",\n };\n }\n if (!canStart && admissionBlocker) {\n return { phase: \"unavailable\", label: \"Voice unavailable\", detail: admissionBlocker };\n }\n return {\n phase: \"idle\",\n label: \"Start voice\",\n detail: `Talk live with ${modelLabel}.`,\n };\n }\n}\n\nfunction RealtimeComposerGlow(props: { phase: RealtimeVisualPhase; reduceMotion: boolean }) {\n const visible = [\n \"connecting\",\n \"listening\",\n \"speaking\",\n \"reconnecting\",\n \"blocked\",\n \"error\",\n \"stopping\",\n ].includes(props.phase);\n return (\n <AnimatePresence initial={false}>\n {visible ? (\n <motion.span\n aria-hidden\n key={props.phase}\n initial={{ opacity: 0 }}\n animate={\n props.reduceMotion\n ? { opacity: 0.48 }\n : props.phase === \"speaking\"\n ? { opacity: [0.42, 0.82, 0.52] }\n : props.phase === \"listening\"\n ? { opacity: [0.34, 0.62, 0.42] }\n : { opacity: [0.28, 0.58, 0.28] }\n }\n exit={{ opacity: 0 }}\n transition={\n props.reduceMotion\n ? { duration: 0.12 }\n : {\n duration: props.phase === \"speaking\" ? 1.15 : 2.1,\n ease: \"easeInOut\",\n repeat: Number.POSITIVE_INFINITY,\n }\n }\n className={cn(\n \"pointer-events-none absolute -inset-px z-[1] rounded-og-lg ring-1 ring-inset shadow-og-glow\",\n props.phase === \"speaking\"\n ? \"ring-og-status-running/50\"\n : props.phase === \"blocked\" || props.phase === \"error\"\n ? \"ring-og-status-waiting/45\"\n : \"ring-og-accent/45\",\n )}\n />\n ) : null}\n </AnimatePresence>\n );\n}\n\nfunction RealtimeActionGlyph(props: {\n phase: RealtimeVisualPhase;\n audioBlocked: boolean;\n reduceMotion: boolean;\n}) {\n if ([\"connecting\", \"reconnecting\", \"stopping\"].includes(props.phase)) {\n return <LoaderCircleIcon className=\"size-3.5 animate-og-spin\" aria-hidden />;\n }\n if (props.phase === \"blocked\") {\n return props.audioBlocked ? (\n <Volume2Icon className=\"size-3.5\" aria-hidden />\n ) : (\n <CircleAlertIcon className=\"size-3.5\" aria-hidden />\n );\n }\n if (props.phase === \"error\" || props.phase === \"elsewhere\" || props.phase === \"unavailable\") {\n return <CircleAlertIcon className=\"size-3.5\" aria-hidden />;\n }\n if (props.phase === \"listening\" || props.phase === \"speaking\") {\n return (\n <span className=\"relative inline-flex size-4 items-center justify-center\">\n {!props.reduceMotion ? (\n <motion.span\n aria-hidden\n className=\"absolute inset-0 rounded-full border border-current\"\n animate={{ opacity: [0.65, 0], scale: [0.65, 1.45] }}\n transition={{\n duration: props.phase === \"speaking\" ? 0.9 : 1.5,\n ease: \"easeOut\",\n repeat: Number.POSITIVE_INFINITY,\n }}\n />\n ) : null}\n <SquareIcon className=\"relative size-2.5 fill-current\" aria-hidden />\n </span>\n );\n }\n return <AudioLinesIcon className=\"size-4\" aria-hidden />;\n}\n\nfunction RealtimeStatusDot(props: { phase: RealtimeVisualPhase; reduceMotion: boolean }) {\n const live = props.phase === \"listening\" || props.phase === \"speaking\";\n return (\n <span className=\"relative inline-flex size-2 shrink-0\" aria-hidden>\n {live && !props.reduceMotion ? (\n <motion.span\n className=\"absolute inset-0 rounded-full bg-og-status-running\"\n animate={{ opacity: [0.45, 0], scale: [1, 2.2] }}\n transition={{ duration: 1.4, ease: \"easeOut\", repeat: Number.POSITIVE_INFINITY }}\n />\n ) : null}\n <span\n className={cn(\n \"relative size-2 rounded-full\",\n live\n ? \"bg-og-status-running\"\n : props.phase === \"blocked\" || props.phase === \"error\"\n ? \"bg-og-status-waiting\"\n : props.phase === \"elsewhere\" || props.phase === \"unavailable\"\n ? \"bg-og-fg-subtle\"\n : \"bg-og-accent\",\n )}\n />\n </span>\n );\n}\n\nfunction voiceButtonTone(phase: RealtimeVisualPhase): string {\n if (phase === \"listening\" || phase === \"speaking\") {\n return \"border border-og-accent/45 bg-og-accent text-og-accent-fg shadow-og-sm hover:bg-og-accent-strong\";\n }\n if (phase === \"blocked\" || phase === \"error\") {\n return \"border border-og-status-waiting/35 bg-og-status-waiting/10 text-og-status-waiting hover:bg-og-status-waiting/15\";\n }\n if (phase === \"connecting\" || phase === \"reconnecting\" || phase === \"stopping\") {\n return \"border border-og-accent/35 bg-og-accent-soft text-og-accent\";\n }\n // Idle: same ghost treatment as the composer transcription mic — no box.\n return \"text-og-fg-muted hover:bg-og-surface-2 hover:text-og-fg\";\n}\n\nfunction voiceChevronTone(phase: RealtimeVisualPhase): string {\n if (phase === \"listening\" || phase === \"speaking\") {\n return \"border border-l-0 border-og-accent/45 bg-og-accent text-og-accent-fg hover:bg-og-accent-strong\";\n }\n if (phase === \"blocked\" || phase === \"error\") {\n return \"border border-l-0 border-og-status-waiting/35 bg-og-status-waiting/10 text-og-status-waiting hover:bg-og-status-waiting/15\";\n }\n if (phase === \"connecting\" || phase === \"reconnecting\" || phase === \"stopping\") {\n return \"border border-l-0 border-og-accent/35 bg-og-accent-soft text-og-accent\";\n }\n return \"text-og-fg-muted hover:bg-og-surface-2 hover:text-og-fg\";\n}\n\nfunction toRealtimeModelOption(model: WorkspaceRealtimeModelCatalogItem): RealtimeModelOption {\n return { ...model };\n}\n\nfunction readRealtimeModelPreference(workspaceId: string): SessionRealtimeModel | null {\n if (typeof localStorage === \"undefined\") return null;\n try {\n const value = localStorage.getItem(`${REALTIME_MODEL_STORAGE_PREFIX}:${workspaceId}`);\n return isRealtimeModel(value) ? value : null;\n } catch {\n return null;\n }\n}\n\nfunction writeRealtimeModelPreference(workspaceId: string, model: SessionRealtimeModel): void {\n if (typeof localStorage === \"undefined\") return;\n try {\n localStorage.setItem(`${REALTIME_MODEL_STORAGE_PREFIX}:${workspaceId}`, model);\n } catch {\n // Voice selection still works when browser storage is unavailable.\n }\n}\n\nfunction isRealtimeModel(value: string | null): value is SessionRealtimeModel {\n return (\n value === \"gpt-live-1-boulder-alpha\" ||\n value === \"opengeni-gateway/openai/gpt-realtime-2.1\" ||\n value === \"opengeni-gateway/openai/gpt-realtime-mini\" ||\n value === \"opengeni-gateway/xai/grok-voice-think-fast-2.0\" ||\n value === \"workspace-gateway/openai/gpt-realtime-2.1\" ||\n value === \"workspace-gateway/openai/gpt-realtime-mini\" ||\n value === \"workspace-gateway/xai/grok-voice-think-fast-2.0\"\n );\n}\n\n/** @deprecated Use the provider-neutral realtime names. */\nexport const useSessionCodexRealtime = useSessionRealtime;\n/** @deprecated Use the provider-neutral realtime names. */\nexport const useWorkspaceRealtimeModelSelection = useRealtimeModelSelection;\n/** @deprecated Use the provider-neutral realtime names. */\nexport const SessionCodexRealtimeControl = SessionRealtimeControl;\n/** @deprecated Use the provider-neutral realtime names. */\nexport const CodexRealtimeControl = RealtimeVoiceControl;\n","\"use client\";\n\nimport { ChevronRightIcon } from \"lucide-react\";\nimport { DropdownMenu as DropdownMenuPrimitive } from \"radix-ui\";\nimport {\n createContext,\n useContext,\n useRef,\n type ComponentProps,\n type Ref,\n type RefObject,\n} from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { usePortalTokenStyle } from \"../lib/use-portal-token-style\";\n\nconst DropdownMenuSourceContext = createContext<RefObject<HTMLElement | null> | null>(null);\n\nfunction assignRef<T>(ref: Ref<T> | undefined, value: T | null) {\n if (typeof ref === \"function\") ref(value);\n else if (ref) ref.current = value;\n}\n\nfunction DropdownMenu(props: ComponentProps<typeof DropdownMenuPrimitive.Root>) {\n const sourceRef = useRef<HTMLElement | null>(null);\n return (\n <DropdownMenuSourceContext.Provider value={sourceRef}>\n <DropdownMenuPrimitive.Root data-slot=\"dropdown-menu\" {...props} />\n </DropdownMenuSourceContext.Provider>\n );\n}\n\nfunction DropdownMenuTrigger({\n ref,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {\n const sourceRef = useContext(DropdownMenuSourceContext);\n return (\n <DropdownMenuPrimitive.Trigger\n data-slot=\"dropdown-menu-trigger\"\n ref={(node) => {\n if (sourceRef) sourceRef.current = node;\n assignRef(ref, node);\n }}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuContent({\n className,\n sideOffset = 4,\n style,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Content>) {\n const sourceRef = useContext(DropdownMenuSourceContext);\n const fallbackRef = useRef<HTMLElement | null>(null);\n const portalStyle = usePortalTokenStyle(sourceRef ?? fallbackRef);\n return (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n data-slot=\"dropdown-menu-content\"\n sideOffset={sideOffset}\n className={cn(\n \"og-root z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95\",\n className,\n )}\n style={{ ...portalStyle, ...style }}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n );\n}\n\nfunction DropdownMenuItem({\n className,\n inset,\n variant = \"default\",\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean;\n variant?: \"default\" | \"destructive\";\n}) {\n return (\n <DropdownMenuPrimitive.Item\n data-slot=\"dropdown-menu-item\"\n data-inset={inset}\n data-variant={variant}\n className={cn(\n \"relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-og-menu outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground data-[variant=destructive]:*:[svg]:text-destructive!\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuSeparator({\n className,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Separator>) {\n return (\n <DropdownMenuPrimitive.Separator\n data-slot=\"dropdown-menu-separator\"\n className={cn(\"-mx-1 my-1 h-px bg-border\", className)}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuSub(props: ComponentProps<typeof DropdownMenuPrimitive.Sub>) {\n return <DropdownMenuPrimitive.Sub data-slot=\"dropdown-menu-sub\" {...props} />;\n}\n\nfunction DropdownMenuSubTrigger({\n className,\n inset,\n children,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & { inset?: boolean }) {\n return (\n <DropdownMenuPrimitive.SubTrigger\n data-slot=\"dropdown-menu-sub-trigger\"\n data-inset={inset}\n className={cn(\n \"flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-og-menu outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground\",\n className,\n )}\n {...props}\n >\n {children}\n <ChevronRightIcon className=\"ml-auto size-4\" />\n </DropdownMenuPrimitive.SubTrigger>\n );\n}\n\nfunction DropdownMenuSubContent({\n className,\n style,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {\n const sourceRef = useContext(DropdownMenuSourceContext);\n const fallbackRef = useRef<HTMLElement | null>(null);\n const portalStyle = usePortalTokenStyle(sourceRef ?? fallbackRef);\n return (\n <DropdownMenuPrimitive.SubContent\n data-slot=\"dropdown-menu-sub-content\"\n className={cn(\n \"og-root z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95\",\n className,\n )}\n style={{ ...portalStyle, ...style }}\n {...props}\n />\n );\n}\n\nexport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n};\n"],"mappings":"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","names":["useRef","jsx","jsxs","useRef"]}
1
+ {"version":3,"sources":["../src/realtime/realtime-control.tsx","../src/realtime/dropdown-menu.tsx"],"sourcesContent":["import { type EffectiveSessionControl, type SessionEvent, type SessionStatus } from \"@opengeni/sdk\";\nimport {\n hasStoredSessionRealtimeOwnerProof,\n projectSessionRealtimeLifecycle,\n type SessionRealtimeClientLike,\n type SessionRealtimeController,\n type SessionRealtimeControllerSnapshot,\n type CreateSessionRealtimeControllerOptions,\n type SessionRealtimeModel,\n type WorkspaceRealtimeModelCatalogItem,\n} from \"@opengeni/sdk/realtime\";\nimport {\n AudioLinesIcon,\n CheckIcon,\n ChevronDownIcon,\n CircleAlertIcon,\n LoaderCircleIcon,\n MicIcon,\n MicOffIcon,\n RotateCcwIcon,\n SquareIcon,\n Volume2Icon,\n VolumeXIcon,\n} from \"lucide-react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\nimport {\n type ReactNode,\n type RefObject,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\n\nimport {\n BillingClassMark,\n PickerAnimatedPage,\n PickerBackHeader,\n PickerNavRow,\n} from \"../components/model-policy-picker\";\nimport type { EmbeddedRealtimeSessionClientLike } from \"../client\";\nimport { cn } from \"../lib/cn\";\nimport type { PickerBillingClass as BillingClass } from \"../model-policy\";\nimport { useEmbeddedRealtimeSession } from \"../session-context\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n} from \"./dropdown-menu\";\n\nexport type RealtimeModelOption = {\n id: SessionRealtimeModel;\n label: string;\n provider: \"OpenGeni\" | \"Connected Codex\" | \"Your Gateway\";\n description: string;\n available: boolean;\n unavailableReason: string | null;\n recommended: boolean;\n};\n\nconst CODEX_LIVE_MODEL: RealtimeModelOption = {\n id: \"gpt-live-1-boulder-alpha\",\n label: \"Codex Live\",\n provider: \"Connected Codex\",\n description: \"Deep session integration\",\n available: false,\n unavailableReason: \"Connect Codex to use this voice model\",\n recommended: false,\n};\n\nconst REALTIME_MODEL_PROVIDERS = [\"OpenGeni\", \"Connected Codex\", \"Your Gateway\"] as const;\ntype RealtimeModelProvider = (typeof REALTIME_MODEL_PROVIDERS)[number];\n\nconst REALTIME_PROVIDER_META: Record<\n RealtimeModelProvider,\n { billingClass: BillingClass; hint: string }\n> = {\n OpenGeni: { billingClass: \"opengeni_credits\", hint: \"Will use credits\" },\n \"Connected Codex\": {\n billingClass: \"codex_subscription\",\n hint: \"ChatGPT / Codex plan\",\n },\n \"Your Gateway\": { billingClass: \"byok\", hint: \"Billed to your AI Gateway\" },\n};\nconst REALTIME_MODEL_STORAGE_PREFIX = \"opengeni:realtime-model\";\n\ntype RealtimeControllerClient = EmbeddedRealtimeSessionClientLike & SessionRealtimeClientLike;\n\nexport type SessionRealtimeControllerFactory = (\n options: CreateSessionRealtimeControllerOptions,\n) => SessionRealtimeController;\n\ntype AdmissionInput = {\n sessionStatus: SessionStatus;\n controlState: \"active\" | \"paused\";\n settlement: { state: string } | null;\n codexConnected: boolean;\n lifecycleActive: boolean;\n};\n\nexport function codexRealtimeAdmissionAllowed(input: AdmissionInput): boolean {\n return codexRealtimeAdmissionBlocker(input) === null;\n}\n\nexport function codexRealtimeAdmissionBlocker(input: AdmissionInput): string | null {\n if (input.sessionStatus === \"cancelled\") return \"This session was cancelled.\";\n if (input.controlState !== \"active\") return \"Resume this session before starting voice.\";\n if (input.settlement !== null) return \"Wait for the current session transition to finish.\";\n if (!input.codexConnected) return \"Connect Codex to use this voice model.\";\n if (input.lifecycleActive) return \"Voice is already active for this session.\";\n return null;\n}\n\nexport function useSessionRealtime(options: {\n client?: RealtimeControllerClient | undefined;\n workspaceId?: string | undefined;\n sessionId: string;\n sessionStatus: SessionStatus;\n effectiveControl: EffectiveSessionControl;\n events: SessionEvent[];\n eventsReady: boolean;\n codexConnected: boolean;\n model?: SessionRealtimeModel | undefined;\n modelAvailable?: boolean | undefined;\n modelUnavailableReason?: string | null | undefined;\n /** Deterministic browser-test/demo seam. Production hosts should use the SDK default. */\n controllerFactory?: SessionRealtimeControllerFactory | undefined;\n}) {\n const { client, workspaceId } = useEmbeddedRealtimeSession({\n client: options.client,\n workspaceId: options.workspaceId,\n });\n const model = options.model ?? CODEX_LIVE_MODEL.id;\n const audioRef = useRef<HTMLAudioElement>(null);\n const controllerRef = useRef<SessionRealtimeController | null>(null);\n const controllerModelRef = useRef<SessionRealtimeModel | null>(null);\n const [snapshot, setSnapshot] = useState<SessionRealtimeControllerSnapshot>(() => ({\n status: hasStoredSessionRealtimeOwnerProof({ workspaceId, sessionId: options.sessionId, model })\n ? \"recovering\"\n : \"idle\",\n realtimeId: null,\n mode: null,\n bridge: null,\n microphone: \"inactive\",\n inputMuted: false,\n audibleOutput: \"inactive\",\n outputMuted: false,\n connectionGeneration: 0,\n reconnectAttempt: 0,\n diagnostic: null,\n error: null,\n }));\n const lifecycle = useMemo(\n () => projectSessionRealtimeLifecycle(options.events),\n [options.events],\n );\n const lifecycleRef = useRef(lifecycle);\n const eventsReadyRef = useRef(options.eventsReady);\n lifecycleRef.current = lifecycle;\n eventsReadyRef.current = options.eventsReady;\n const lifecycleActive = lifecycle?.state === \"active\";\n\n useEffect(() => {\n let disposed = false;\n let controller: SessionRealtimeController | null = null;\n let unsubscribe: (() => void) | null = null;\n void import(\"@opengeni/sdk/realtime\")\n .then(({ createSessionRealtimeController }) => {\n if (disposed) return;\n const controllerFactory = options.controllerFactory ?? createSessionRealtimeController;\n controller = controllerFactory({\n client,\n workspaceId,\n sessionId: options.sessionId,\n ...(audioRef.current ? { remoteAudio: audioRef.current } : {}),\n model,\n });\n controllerRef.current = controller;\n controllerModelRef.current = model;\n unsubscribe = controller.subscribe(setSnapshot);\n if (eventsReadyRef.current) {\n void controller.observeLifecycle(lifecycleRef.current).catch(() => undefined);\n }\n })\n .catch((error: unknown) => {\n if (disposed) return;\n setSnapshot({\n status: \"error\",\n realtimeId: null,\n mode: null,\n bridge: null,\n microphone: \"inactive\",\n inputMuted: false,\n audibleOutput: \"inactive\",\n outputMuted: false,\n connectionGeneration: 0,\n reconnectAttempt: 0,\n diagnostic: {\n kind: \"negotiation_failure\",\n message:\n error instanceof Error ? error.message : \"Codex realtime controller failed to load\",\n recoverable: false,\n connectionGeneration: 0,\n attempt: 0,\n },\n error:\n error instanceof Error ? error.message : \"Codex realtime controller failed to load\",\n });\n });\n return () => {\n disposed = true;\n unsubscribe?.();\n controller?.close();\n if (controllerRef.current === controller) {\n controllerRef.current = null;\n controllerModelRef.current = null;\n }\n };\n }, [client, model, options.controllerFactory, options.sessionId, workspaceId]);\n\n useEffect(() => {\n if (!options.eventsReady) return;\n void controllerRef.current?.observeLifecycle(lifecycle).catch(() => undefined);\n }, [lifecycle, options.eventsReady]);\n\n const start = useCallback(async () => {\n const controller = controllerRef.current;\n if (!controller || controllerModelRef.current !== model) {\n throw new Error(\"The selected voice model is still preparing\");\n }\n await controller.start();\n }, [model]);\n const stop = useCallback(async () => {\n await controllerRef.current?.stop();\n }, []);\n const retry = useCallback(async () => {\n await controllerRef.current?.retry();\n }, []);\n const retryAudibleOutput = useCallback(async () => {\n await controllerRef.current?.retryAudibleOutput();\n }, []);\n const setInputMuted = useCallback((muted: boolean) => {\n controllerRef.current?.setInputMuted(muted);\n }, []);\n const setOutputMuted = useCallback((muted: boolean) => {\n controllerRef.current?.setOutputMuted(muted);\n }, []);\n const admissionInput = {\n sessionStatus: options.sessionStatus,\n controlState: options.effectiveControl.state,\n settlement: options.effectiveControl.settlement,\n codexConnected: options.modelAvailable ?? options.codexConnected,\n lifecycleActive,\n } satisfies AdmissionInput;\n const admissionBlocker =\n options.modelAvailable === false\n ? (options.modelUnavailableReason ?? \"This voice model is unavailable.\")\n : codexRealtimeAdmissionBlocker(admissionInput);\n const canStart =\n controllerRef.current !== null &&\n controllerModelRef.current === model &&\n [\"idle\", \"error\"].includes(snapshot.status) &&\n admissionBlocker === null;\n\n return {\n snapshot,\n lifecycleActive,\n canStart,\n admissionBlocker,\n codexConnected: options.codexConnected,\n audioRef,\n start,\n stop,\n retry,\n retryAudibleOutput,\n setInputMuted,\n setOutputMuted,\n };\n}\n\nexport function SessionRealtimeControl(props: {\n client?: RealtimeControllerClient | undefined;\n workspaceId?: string | undefined;\n sessionId: string;\n sessionStatus: SessionStatus;\n effectiveControl: EffectiveSessionControl;\n events: SessionEvent[];\n eventsReady: boolean;\n codexConnected: boolean;\n realtimeAutostartModel?: SessionRealtimeModel | undefined;\n onRealtimeAutostartConsumed?: (() => void) | undefined;\n /** Host hides dictate (and can choreograph layout) while realtime voice is live. */\n onVoiceActiveChange?: ((active: boolean) => void) | undefined;\n /**\n * `split` attaches the model chevron at every breakpoint (public default).\n * `split-desktop` hides it below `sm` when the host owns mobile selection.\n * Inside a container-responsive Composer.Root, `sm` follows that composer.\n * `none` never attaches a model menu to the bar button.\n */\n modelMenu?: \"split\" | \"split-desktop\" | \"none\" | undefined;\n /** Deterministic browser-test/demo seam. Production hosts should use the SDK default. */\n controllerFactory?: SessionRealtimeControllerFactory | undefined;\n}) {\n const lifecycle = useMemo(() => projectSessionRealtimeLifecycle(props.events), [props.events]);\n const selection = useRealtimeModelSelection({\n client: props.client,\n workspaceId: props.workspaceId,\n codexConnected: props.codexConnected,\n activeModel: lifecycle?.state === \"active\" ? lifecycle.model : null,\n });\n const selectedModel = selection.selectedModel;\n const realtime = useSessionRealtime({\n ...props,\n model: selectedModel.id,\n modelAvailable: selectedModel.available,\n modelUnavailableReason: selectedModel.unavailableReason,\n });\n const autostartModelRef = useRef(props.realtimeAutostartModel ?? null);\n const autostartStartedRef = useRef(false);\n\n const { models, selectedModel: selectedRealtimeModel, selectModel } = selection;\n const { canStart, start } = realtime;\n const onRealtimeAutostartConsumed = props.onRealtimeAutostartConsumed;\n const onVoiceActiveChange = props.onVoiceActiveChange;\n const voiceActive = realtime.snapshot.mode?.state === \"active\";\n\n useEffect(() => {\n onVoiceActiveChange?.(voiceActive);\n }, [onVoiceActiveChange, voiceActive]);\n\n useEffect(() => {\n const pending = autostartModelRef.current;\n if (!pending || autostartStartedRef.current || lifecycle?.state === \"active\") return;\n const available = models.some((model) => model.id === pending && model.available);\n if (!available) return;\n if (selectedRealtimeModel.id !== pending) {\n selectModel(pending);\n return;\n }\n if (!canStart) return;\n autostartStartedRef.current = true;\n void start()\n .then(() => {\n autostartModelRef.current = null;\n onRealtimeAutostartConsumed?.();\n })\n .catch(() => {\n autostartStartedRef.current = false;\n });\n }, [\n canStart,\n lifecycle?.state,\n models,\n props.sessionId,\n props.workspaceId,\n onRealtimeAutostartConsumed,\n selectModel,\n selectedRealtimeModel.id,\n start,\n ]);\n\n return (\n <RealtimeVoiceControl\n snapshot={realtime.snapshot}\n canStart={realtime.canStart}\n admissionBlocker={realtime.admissionBlocker}\n modelAvailable={selectedModel.available}\n menuSide=\"top\"\n modelMenu={props.modelMenu ?? \"split\"}\n audioRef={realtime.audioRef}\n selectedModel={selectedModel}\n models={selection.models}\n onSelectModel={realtime.lifecycleActive ? undefined : selection.selectModel}\n onStart={realtime.start}\n onStop={realtime.stop}\n onRetry={realtime.retry}\n onRetryAudibleOutput={realtime.retryAudibleOutput}\n onSetInputMuted={realtime.setInputMuted}\n onSetOutputMuted={realtime.setOutputMuted}\n />\n );\n}\n\nexport function useRealtimeModelSelection(options: {\n client?: RealtimeControllerClient | undefined;\n workspaceId?: string | undefined;\n codexConnected: boolean;\n activeModel?: SessionRealtimeModel | null | undefined;\n}) {\n const { client, workspaceId } = useEmbeddedRealtimeSession({\n client: options.client,\n workspaceId: options.workspaceId,\n });\n const activeModel = options.activeModel;\n const [catalog, setCatalog] = useState<RealtimeModelOption[]>(() => [\n {\n ...CODEX_LIVE_MODEL,\n available: options.codexConnected,\n unavailableReason: options.codexConnected ? null : CODEX_LIVE_MODEL.unavailableReason,\n },\n ]);\n const [selectedModelId, setSelectedModelId] = useState<SessionRealtimeModel>(\n () => readRealtimeModelPreference(workspaceId) ?? CODEX_LIVE_MODEL.id,\n );\n\n useEffect(() => {\n let disposed = false;\n const load = client.getWorkspaceRealtimeModelCatalog;\n if (!load) return;\n void load\n .call(client, workspaceId)\n .then((response) => {\n if (disposed) return;\n const models = response.models.map(toRealtimeModelOption);\n setCatalog(models);\n setSelectedModelId((current) => {\n if (models.some((model) => model.id === current && model.available)) return current;\n return models.find((model) => model.available)?.id ?? CODEX_LIVE_MODEL.id;\n });\n })\n .catch(() => undefined);\n return () => {\n disposed = true;\n };\n }, [client, workspaceId]);\n\n useEffect(() => {\n if (activeModel) setSelectedModelId(activeModel);\n }, [activeModel]);\n\n const selectedModel =\n catalog.find((model) => model.id === selectedModelId) ??\n ({\n ...CODEX_LIVE_MODEL,\n available: options.codexConnected,\n unavailableReason: options.codexConnected ? null : CODEX_LIVE_MODEL.unavailableReason,\n } satisfies RealtimeModelOption);\n const selectModel = useCallback(\n (value: string) => {\n const model = catalog.find((candidate) => candidate.id === value);\n if (!model || !model.available || activeModel) return;\n setSelectedModelId(model.id);\n writeRealtimeModelPreference(workspaceId, model.id);\n },\n [activeModel, catalog, workspaceId],\n );\n\n return { models: catalog, selectedModel, selectModel };\n}\n\nconst IDLE_REALTIME_SNAPSHOT: SessionRealtimeControllerSnapshot = {\n status: \"idle\",\n realtimeId: null,\n mode: null,\n bridge: null,\n microphone: \"inactive\",\n inputMuted: false,\n audibleOutput: \"inactive\",\n outputMuted: false,\n connectionGeneration: 0,\n reconnectAttempt: 0,\n diagnostic: null,\n error: null,\n};\n\nexport function NewSessionRealtimeControl(props: {\n client?: RealtimeControllerClient | undefined;\n workspaceId?: string | undefined;\n codexConnected: boolean;\n disabled?: boolean | undefined;\n disabledReason?: string | null | undefined;\n onStart: (model: SessionRealtimeModel) => Promise<boolean>;\n /** Parent-owned selection (e.g. shared with the mobile “+” voice-model panel). */\n models?: readonly RealtimeModelOption[] | undefined;\n selectedModel?: RealtimeModelOption | undefined;\n onSelectModel?: ((modelId: string) => void) | undefined;\n /**\n * `split` attaches the model chevron at every breakpoint (public default).\n * `split-desktop` hides it below `sm` when the host owns mobile selection (e.g. “+”).\n * Inside a container-responsive Composer.Root, `sm` follows that composer.\n * `none` never attaches a model menu to the bar button.\n */\n modelMenu?: \"split\" | \"split-desktop\" | \"none\" | undefined;\n}) {\n const internalSelection = useRealtimeModelSelection({\n client: props.client,\n workspaceId: props.workspaceId,\n codexConnected: props.codexConnected,\n });\n const selection =\n props.models && props.selectedModel && props.onSelectModel\n ? {\n models: props.models,\n selectedModel: props.selectedModel,\n selectModel: props.onSelectModel,\n }\n : internalSelection;\n const audioRef = useRef<HTMLAudioElement>(null);\n const [starting, setStarting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const snapshot = useMemo<SessionRealtimeControllerSnapshot>(\n () =>\n starting\n ? { ...IDLE_REALTIME_SNAPSHOT, status: \"starting\" }\n : error\n ? { ...IDLE_REALTIME_SNAPSHOT, status: \"error\", error }\n : IDLE_REALTIME_SNAPSHOT,\n [error, starting],\n );\n const canStart = selection.selectedModel.available && props.disabled !== true && !starting;\n const onStart = props.onStart;\n const selectedModelId = selection.selectedModel.id;\n const start = useCallback(async () => {\n if (!canStart) return;\n setStarting(true);\n setError(null);\n try {\n const started = await onStart(selectedModelId);\n if (!started) setError(\"The voice session could not be created.\");\n } catch (cause) {\n setError(cause instanceof Error ? cause.message : String(cause));\n } finally {\n setStarting(false);\n }\n }, [canStart, onStart, selectedModelId]);\n\n return (\n <RealtimeVoiceControl\n snapshot={snapshot}\n canStart={canStart}\n admissionBlocker={selection.selectedModel.unavailableReason ?? props.disabledReason ?? null}\n modelAvailable={selection.selectedModel.available}\n selectionDisabled={starting}\n menuSide=\"bottom\"\n modelMenu={props.modelMenu ?? \"split\"}\n showDiagnostics={false}\n audioRef={audioRef}\n selectedModel={selection.selectedModel}\n models={selection.models}\n onSelectModel={selection.selectModel}\n onStart={start}\n onStop={async () => undefined}\n onRetry={start}\n onRetryAudibleOutput={async () => undefined}\n onSetInputMuted={() => undefined}\n onSetOutputMuted={() => undefined}\n />\n );\n}\n\nexport function RealtimeVoiceControl(props: {\n snapshot: SessionRealtimeControllerSnapshot;\n canStart: boolean;\n admissionBlocker?: string | null | undefined;\n modelAvailable: boolean;\n selectionDisabled?: boolean | undefined;\n /** Prefer `bottom` on home/new-session; `top` for the docked session composer. */\n menuSide?: \"top\" | \"bottom\" | undefined;\n /**\n * `split` = start + model chevron at every breakpoint (public SDK default).\n * `split-desktop` = chevron from `sm` up; below that the host owns selection.\n * Inside a container-responsive Composer.Root, `sm` follows that composer.\n * `none` = start button only.\n */\n modelMenu?: \"split\" | \"split-desktop\" | \"none\" | undefined;\n showDiagnostics?: boolean;\n /** Extra classes on the in-bar mute cluster (e.g. `max-sm:hidden` when mutes live in “+”). */\n muteControlsClassName?: string | undefined;\n audioRef: RefObject<HTMLAudioElement | null>;\n selectedModel?: RealtimeModelOption | undefined;\n models?: readonly RealtimeModelOption[] | undefined;\n onSelectModel?: ((modelId: string) => void) | undefined;\n onStart: () => Promise<void>;\n onStop: () => Promise<void>;\n onRetry: () => Promise<void>;\n onRetryAudibleOutput: () => Promise<void>;\n onSetInputMuted: (muted: boolean) => void;\n onSetOutputMuted: (muted: boolean) => void;\n}) {\n const reduceMotion = useReducedMotion();\n const selectedModel = props.selectedModel ?? {\n ...CODEX_LIVE_MODEL,\n available: props.modelAvailable,\n unavailableReason: props.modelAvailable ? null : CODEX_LIVE_MODEL.unavailableReason,\n };\n const models = props.models ?? [selectedModel];\n const status = statusContent(\n props.snapshot,\n props.modelAvailable,\n props.canStart,\n props.admissionBlocker ?? null,\n selectedModel.label,\n );\n const modeOwned = props.snapshot.mode?.state === \"active\";\n const retryConnection =\n modeOwned &&\n props.snapshot.status !== \"stopping\" &&\n props.snapshot.status !== \"active\" &&\n props.snapshot.diagnostic?.recoverable === true;\n const audioBlocked = props.snapshot.audibleOutput === \"blocked\" && !props.snapshot.outputMuted;\n const mainDisabled =\n props.snapshot.status === \"stopping\" ||\n props.snapshot.status === \"lost_owner\" ||\n (!modeOwned && !props.canStart) ||\n (props.snapshot.status === \"starting\" && !modeOwned);\n const mainLabel = audioBlocked\n ? \"Resume voice audio\"\n : retryConnection\n ? \"Retry voice connection\"\n : modeOwned\n ? \"End voice conversation\"\n : `Start voice with ${selectedModel.label}`;\n const runMainAction = audioBlocked\n ? props.onRetryAudibleOutput\n : retryConnection\n ? props.onRetry\n : modeOwned\n ? props.onStop\n : props.onStart;\n const diagnosticsVisible = props.showDiagnostics ?? import.meta.env.DEV;\n const modelMenu = props.modelMenu ?? \"split\";\n const showAttachedModelMenu = modelMenu === \"split\" || modelMenu === \"split-desktop\";\n const desktopOnlyModelMenu = modelMenu === \"split-desktop\";\n const [pickerOpen, setPickerOpen] = useState(false);\n const [pickerProvider, setPickerProvider] = useState<RealtimeModelProvider | null>(\n selectedModel.provider,\n );\n const [pickerDirection, setPickerDirection] = useState<1 | -1>(1);\n\n useEffect(() => {\n if (!pickerOpen) setPickerProvider(selectedModel.provider);\n }, [pickerOpen, selectedModel.provider]);\n\n return (\n <div\n role=\"group\"\n aria-label=\"Realtime voice\"\n data-picker-side={props.menuSide ?? \"top\"}\n data-model-menu={modelMenu}\n className=\"og-realtime-control inline-flex shrink-0 items-center\"\n >\n <audio ref={props.audioRef} autoPlay className=\"hidden\" aria-hidden=\"true\" />\n <RealtimeComposerGlow phase={status.phase} reduceMotion={reduceMotion === true} />\n <AnimatePresence initial={false}>\n {modeOwned ? (\n <motion.div\n key=\"realtime-mute-controls\"\n data-testid=\"realtime-mute-controls\"\n // After dictate collapses and the model slides left, bloom mutes\n // out from the primary voice control. Exit is immediate (no delay).\n initial={reduceMotion ? false : { opacity: 0, width: 0 }}\n animate={{\n opacity: 1,\n width: \"auto\",\n transition: reduceMotion\n ? { duration: 0 }\n : { delay: 0.3, duration: 0.48, ease: [0.22, 1, 0.36, 1] },\n }}\n {...(reduceMotion\n ? {}\n : {\n exit: {\n opacity: 0,\n width: 0,\n transition: { duration: 0.28, ease: [0.4, 0, 1, 1] },\n },\n })}\n className={cn(\n \"inline-flex shrink-0 items-center overflow-hidden\",\n props.muteControlsClassName,\n )}\n >\n <motion.div\n className=\"inline-flex items-center gap-0.5 pr-1\"\n initial={reduceMotion ? false : { x: 18, opacity: 0 }}\n animate={{\n x: 0,\n opacity: 1,\n transition: reduceMotion\n ? { duration: 0 }\n : { delay: 0.32, type: \"spring\", stiffness: 320, damping: 30, mass: 0.8 },\n }}\n {...(reduceMotion\n ? {}\n : {\n exit: {\n x: 14,\n opacity: 0,\n transition: { duration: 0.22, ease: [0.4, 0, 1, 1] },\n },\n })}\n >\n <RealtimeMuteButton\n muted={props.snapshot.inputMuted}\n kind=\"microphone\"\n reduceMotion={reduceMotion === true}\n enterDelay={reduceMotion ? 0 : 0.34}\n onToggle={() => props.onSetInputMuted(!props.snapshot.inputMuted)}\n />\n <RealtimeMuteButton\n muted={props.snapshot.outputMuted}\n kind=\"output\"\n reduceMotion={reduceMotion === true}\n enterDelay={reduceMotion ? 0 : 0.4}\n onToggle={() => props.onSetOutputMuted(!props.snapshot.outputMuted)}\n />\n </motion.div>\n </motion.div>\n ) : null}\n </AnimatePresence>\n <div className=\"inline-flex shrink-0 items-center\">\n <motion.button\n type=\"button\"\n data-testid=\"realtime-primary-action\"\n data-phase={status.phase}\n aria-label={mainLabel}\n aria-pressed={modeOwned}\n title={mainLabel}\n disabled={mainDisabled}\n {...(reduceMotion ? {} : { whileTap: { scale: 0.92 } })}\n transition={{ type: \"spring\", stiffness: 520, damping: 30 }}\n onClick={() => void runMainAction().catch(() => undefined)}\n className={cn(\n // Match transcription mic: ghost icon when idle; filled only when live.\n // Public contract: coarse pointers keep a 44px target; split menu uses\n // left-only rounding at `sm+` where the chevron attaches.\n \"og-realtime-primary relative inline-flex size-8 items-center justify-center outline-hidden\",\n \"rounded-og-md transition-[background-color,border-color,color,box-shadow] duration-200 ease-og-out\",\n \"focus-visible:z-10 focus-visible:ring-2 focus-visible:ring-og-accent/45\",\n \"disabled:cursor-not-allowed disabled:opacity-45 pointer-coarse:size-11\",\n showAttachedModelMenu &&\n (desktopOnlyModelMenu\n ? \"sm:rounded-l-og-md sm:rounded-r-none\"\n : \"rounded-l-og-md rounded-r-none\"),\n voiceButtonTone(status.phase),\n )}\n >\n <RealtimeActionGlyph\n phase={status.phase}\n audioBlocked={audioBlocked}\n reduceMotion={reduceMotion === true}\n />\n </motion.button>\n\n {showAttachedModelMenu ? (\n <DropdownMenu open={pickerOpen} onOpenChange={setPickerOpen}>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n aria-label=\"Choose voice model and options\"\n title={`Voice model: ${selectedModel.label}`}\n disabled={props.selectionDisabled}\n className={cn(\n // Keep the split trigger compact on desktop while preserving a\n // full 44px mobile target independent of pointer-media support.\n \"og-realtime-model-trigger inline-flex h-11 w-11 items-center justify-center rounded-r-og-md outline-hidden sm:h-8 sm:w-6\",\n \"transition-[background-color,border-color,color] duration-200 ease-og-out\",\n \"focus-visible:z-10 focus-visible:ring-2 focus-visible:ring-og-accent/45\",\n desktopOnlyModelMenu && \"hidden sm:inline-flex\",\n voiceChevronTone(status.phase),\n )}\n >\n <ChevronDownIcon className=\"size-3\" aria-hidden />\n </button>\n </DropdownMenuTrigger>\n <DropdownMenuContent\n side={props.menuSide ?? \"top\"}\n align=\"end\"\n sideOffset={8}\n collisionPadding={12}\n className=\"og-realtime-menu flex w-72 max-h-[min(20rem,var(--radix-dropdown-menu-content-available-height))] flex-col overflow-hidden rounded-xl border-border bg-surface p-1.5 shadow-xl\"\n onCloseAutoFocus={(event) => event.preventDefault()}\n >\n <div className=\"min-h-0 flex-1 overflow-y-auto overscroll-contain\">\n <RealtimeModelPickerMenu\n models={models}\n selectedModel={selectedModel}\n provider={pickerProvider}\n direction={pickerDirection}\n disabled={\n props.selectionDisabled === true || props.snapshot.mode?.state === \"active\"\n }\n onProviderChange={(provider, direction) => {\n setPickerDirection(direction);\n setPickerProvider(provider);\n }}\n onSelect={(modelId) => {\n props.onSelectModel?.(modelId);\n setPickerOpen(false);\n }}\n />\n </div>\n\n {status.phase !== \"idle\" ? (\n <>\n <DropdownMenuSeparator className=\"mx-1 bg-og-border\" />\n <div className=\"px-2.5 py-2\" role=\"status\" aria-live=\"polite\">\n <div className=\"flex items-center gap-2 text-og-sm font-medium text-og-fg\">\n <RealtimeStatusDot\n phase={status.phase}\n reduceMotion={reduceMotion === true}\n />\n {status.label}\n </div>\n <p className=\"mt-1 text-og-xs leading-5 text-og-fg-subtle\">{status.detail}</p>\n </div>\n </>\n ) : null}\n\n {audioBlocked ? (\n <DropdownMenuItem\n className=\"rounded-og-md\"\n onSelect={() => void props.onRetryAudibleOutput().catch(() => undefined)}\n >\n <Volume2Icon />\n Resume audio\n </DropdownMenuItem>\n ) : null}\n {retryConnection ? (\n <DropdownMenuItem\n className=\"rounded-og-md\"\n onSelect={() => void props.onRetry().catch(() => undefined)}\n >\n <RotateCcwIcon />\n Retry connection\n </DropdownMenuItem>\n ) : null}\n {modeOwned && props.snapshot.status !== \"lost_owner\" ? (\n <DropdownMenuItem\n variant=\"destructive\"\n className=\"rounded-og-md\"\n disabled={props.snapshot.status === \"stopping\"}\n onSelect={() => void props.onStop().catch(() => undefined)}\n >\n <SquareIcon />\n End voice conversation\n </DropdownMenuItem>\n ) : null}\n\n {diagnosticsVisible ? <RealtimeDiagnosticsMenu snapshot={props.snapshot} /> : null}\n </DropdownMenuContent>\n </DropdownMenu>\n ) : null}\n </div>\n\n <span className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n {status.label}. {status.detail}\n </span>\n {props.snapshot.error ? (\n <span className=\"sr-only\" role=\"alert\">\n {props.snapshot.error}\n </span>\n ) : null}\n </div>\n );\n}\n\n/** Drill-in body for the mobile composer “+” menu — same catalog as the desktop chevron. */\nexport function RealtimeVoiceModelPanel(props: {\n models: readonly RealtimeModelOption[];\n selectedModel: RealtimeModelOption;\n disabled?: boolean | undefined;\n leading?: ReactNode | undefined;\n onSelect: (modelId: SessionRealtimeModel) => void;\n}) {\n const [provider, setProvider] = useState<RealtimeModelProvider | null>(null);\n const [direction, setDirection] = useState<1 | -1>(1);\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col\" data-testid=\"realtime-voice-model-panel\">\n <div className=\"flex shrink-0 items-start gap-1 px-2 pt-1 pb-1.5\">\n {props.leading}\n <div className=\"min-w-0\">\n <div className=\"text-og-menu font-medium text-og-fg\">Voice model</div>\n <p className=\"mt-0.5 text-og-control text-og-fg-subtle\">\n Used when you start a voice conversation.\n </p>\n </div>\n </div>\n <div className=\"min-h-0 flex-1 overflow-y-auto overscroll-contain px-1.5 pb-1.5\">\n <RealtimeModelPickerMenu\n models={props.models}\n selectedModel={props.selectedModel}\n provider={provider}\n direction={direction}\n disabled={props.disabled === true}\n onProviderChange={(next, nextDirection) => {\n setDirection(nextDirection);\n setProvider(next);\n }}\n onSelect={props.onSelect}\n />\n </div>\n </div>\n );\n}\n\nfunction RealtimeMuteButton(props: {\n muted: boolean;\n kind: \"microphone\" | \"output\";\n reduceMotion: boolean;\n enterDelay?: number | undefined;\n onToggle(): void;\n}) {\n const microphone = props.kind === \"microphone\";\n const label = microphone\n ? props.muted\n ? \"Unmute microphone\"\n : \"Mute microphone\"\n : props.muted\n ? \"Unmute voice audio\"\n : \"Mute voice audio\";\n const Icon = microphone\n ? props.muted\n ? MicOffIcon\n : MicIcon\n : props.muted\n ? VolumeXIcon\n : Volume2Icon;\n\n return (\n <motion.button\n type=\"button\"\n aria-label={label}\n aria-pressed={props.muted}\n title={label}\n initial={props.reduceMotion ? false : { scale: 0.72, opacity: 0 }}\n animate={{ scale: 1, opacity: 1 }}\n transition={{\n delay: props.enterDelay ?? 0,\n type: \"spring\",\n stiffness: 420,\n damping: 26,\n mass: 0.7,\n }}\n {...(props.reduceMotion ? {} : { whileTap: { scale: 0.92 } })}\n onClick={props.onToggle}\n className={cn(\n \"inline-flex size-8 shrink-0 items-center justify-center rounded-og-md outline-hidden\",\n \"transition-[background-color,border-color,color] duration-150 ease-og-out\",\n \"focus-visible:ring-2 focus-visible:ring-og-accent/45 pointer-coarse:size-11\",\n props.muted\n ? \"border border-og-accent/35 bg-og-accent-soft text-og-accent\"\n : \"text-og-fg-muted hover:bg-og-surface-2 hover:text-og-fg\",\n )}\n >\n <Icon className=\"size-3.5\" aria-hidden />\n </motion.button>\n );\n}\n\nexport function RealtimeModelPickerMenu(props: {\n models: readonly RealtimeModelOption[];\n selectedModel: RealtimeModelOption;\n provider: RealtimeModelProvider | null;\n direction: 1 | -1;\n disabled: boolean;\n onProviderChange: (provider: RealtimeModelProvider | null, direction: 1 | -1) => void;\n onSelect: (modelId: SessionRealtimeModel) => void;\n}) {\n const providers = REALTIME_MODEL_PROVIDERS.filter((provider) =>\n props.models.some((model) => model.provider === provider),\n );\n const pageKey = props.provider ? `voice-models:${props.provider}` : \"voice-providers\";\n const body = props.provider ? (\n <div data-testid=\"realtime-model-picker-models\">\n <PickerBackHeader\n label={props.provider}\n icon={\n <BillingClassMark\n billingClass={REALTIME_PROVIDER_META[props.provider].billingClass}\n aria-label=\"\"\n />\n }\n onBack={() => props.onProviderChange(null, -1)}\n />\n <div className=\"flex flex-col gap-0.5\">\n {props.models\n .filter((model) => model.provider === props.provider)\n .map((model) => {\n const selected = model.id === props.selectedModel.id;\n return (\n <PickerNavRow\n key={model.id}\n label={model.label}\n hint={\n model.unavailableReason ??\n (model.recommended ? `Recommended · ${model.description}` : model.description)\n }\n disabled={props.disabled || !model.available}\n title={model.unavailableReason ?? model.description}\n active={selected}\n showChevron={false}\n trailing={selected ? <CheckIcon className=\"size-3.5\" aria-hidden /> : undefined}\n testId={`realtime-model-choice-${model.id}`}\n onClick={() => props.onSelect(model.id)}\n />\n );\n })}\n </div>\n </div>\n ) : (\n <div className=\"flex flex-col gap-0.5\" data-testid=\"realtime-model-picker-providers\">\n {providers.map((provider) => {\n const meta = REALTIME_PROVIDER_META[provider];\n return (\n <PickerNavRow\n key={provider}\n label={provider}\n hint={meta.hint}\n icon={<BillingClassMark billingClass={meta.billingClass} aria-label=\"\" />}\n active={props.selectedModel.provider === provider}\n testId={`realtime-model-provider-${meta.billingClass}`}\n onClick={() => props.onProviderChange(provider, 1)}\n />\n );\n })}\n </div>\n );\n\n return (\n <div className=\"relative overflow-hidden\" data-testid=\"realtime-model-picker-menu\">\n <PickerAnimatedPage pageKey={pageKey} direction={props.direction}>\n {body}\n </PickerAnimatedPage>\n </div>\n );\n}\n\nfunction RealtimeDiagnosticsMenu({ snapshot }: { snapshot: SessionRealtimeControllerSnapshot }) {\n const bridge = snapshot.bridge;\n const rows = [\n [\"controller\", snapshot.status],\n [\"microphone\", snapshot.microphone],\n [\"microphone muted\", String(snapshot.inputMuted)],\n [\"audio\", snapshot.audibleOutput],\n [\"audio muted\", String(snapshot.outputMuted)],\n [\"generation\", String(snapshot.connectionGeneration)],\n [\"reconnect attempt\", String(snapshot.reconnectAttempt)],\n [\"mode\", snapshot.mode?.state ?? \"none\"],\n [\"mode version\", snapshot.mode ? String(snapshot.mode.version) : \"—\"],\n [\"connection epoch\", snapshot.mode ? String(snapshot.mode.connectionEpoch) : \"—\"],\n [\"provider started\", bridge ? String(bridge.providerStarted) : \"false\"],\n [\"provider speaking\", bridge ? String(bridge.speaking) : \"false\"],\n [\"delegation\", bridge?.activeDelegationId ? \"active\" : \"none\"],\n [\"pending durable events\", bridge ? String(bridge.pendingInbound) : \"0\"],\n [\"pending bytes\", bridge ? String(bridge.pendingInboundBytes) : \"0\"],\n [\"client ack\", bridge?.clientAckThroughSequence?.toString() ?? \"—\"],\n [\"ignored provider events\", bridge ? String(bridge.ignoredEventCount) : \"0\"],\n [\"last ignored event\", bridge?.lastIgnoredEventType ?? \"none\"],\n [\"bridge error\", bridge?.lastError ?? \"none\"],\n [\"diagnostic\", snapshot.diagnostic?.kind ?? \"none\"],\n ] as const;\n\n return (\n <>\n <DropdownMenuSeparator className=\"mx-1 bg-og-border\" />\n <DropdownMenuSub>\n <DropdownMenuSubTrigger className=\"rounded-og-md text-og-fg-muted\">\n Realtime diagnostics\n </DropdownMenuSubTrigger>\n <DropdownMenuSubContent className=\"max-h-80 w-72 overflow-y-auto rounded-og-lg border-og-border bg-og-surface-1 p-1.5 text-og-fg shadow-og-lg\">\n {rows.map(([label, value]) => (\n <DropdownMenuItem\n key={label}\n disabled\n className=\"grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)] gap-3 rounded-og-md font-mono text-[11px] opacity-100\"\n >\n <span className=\"truncate text-og-fg-subtle\">{label}</span>\n <span className=\"truncate text-right text-og-fg\">{value}</span>\n </DropdownMenuItem>\n ))}\n </DropdownMenuSubContent>\n </DropdownMenuSub>\n </>\n );\n}\n\ntype RealtimeVisualPhase =\n | \"idle\"\n | \"connecting\"\n | \"listening\"\n | \"speaking\"\n | \"reconnecting\"\n | \"blocked\"\n | \"unavailable\"\n | \"error\"\n | \"elsewhere\"\n | \"stopping\";\n\nfunction statusContent(\n snapshot: SessionRealtimeControllerSnapshot,\n modelAvailable: boolean,\n canStart: boolean,\n admissionBlocker: string | null,\n modelLabel: string,\n): { phase: RealtimeVisualPhase; label: string; detail: string } {\n if (snapshot.audibleOutput === \"blocked\" && !snapshot.outputMuted) {\n return {\n phase: \"blocked\",\n label: \"Audio output blocked\",\n detail: \"Resume audio to hear the existing voice connection.\",\n };\n }\n switch (snapshot.status) {\n case \"starting\":\n return {\n phase: \"connecting\",\n label: \"Connecting…\",\n detail: \"Preparing your microphone and live voice.\",\n };\n case \"active\":\n return snapshot.bridge?.speaking\n ? {\n phase: \"speaking\",\n label: \"Speaking\",\n detail: \"Interrupt naturally whenever you want.\",\n }\n : {\n phase: \"listening\",\n label: \"Listening\",\n detail: \"Voice and typed messages share this session.\",\n };\n case \"stopping\":\n return {\n phase: \"stopping\",\n label: \"Ending voice…\",\n detail: \"Saving the remaining conversation context.\",\n };\n case \"recovering\":\n return {\n phase: \"reconnecting\",\n label: \"Reconnecting…\",\n detail: snapshot.error ?? \"Keeping this voice conversation connected.\",\n };\n case \"lost_owner\":\n return {\n phase: \"elsewhere\",\n label: \"Voice active elsewhere\",\n detail: \"Return to the browser that started it, or wait for that connection to expire.\",\n };\n case \"error\":\n return {\n phase: \"error\",\n label: \"Voice unavailable\",\n detail: snapshot.error ?? \"The connection could not be started.\",\n };\n case \"idle\":\n if (!modelAvailable) {\n return {\n phase: \"unavailable\",\n label: \"Voice model unavailable\",\n detail: admissionBlocker ?? \"Choose another voice model.\",\n };\n }\n if (!canStart && admissionBlocker) {\n return { phase: \"unavailable\", label: \"Voice unavailable\", detail: admissionBlocker };\n }\n return {\n phase: \"idle\",\n label: \"Start voice\",\n detail: `Talk live with ${modelLabel}.`,\n };\n }\n}\n\nfunction RealtimeComposerGlow(props: { phase: RealtimeVisualPhase; reduceMotion: boolean }) {\n const visible = [\n \"connecting\",\n \"listening\",\n \"speaking\",\n \"reconnecting\",\n \"blocked\",\n \"error\",\n \"stopping\",\n ].includes(props.phase);\n return (\n <AnimatePresence initial={false}>\n {visible ? (\n <motion.span\n aria-hidden\n key={props.phase}\n initial={{ opacity: 0 }}\n animate={\n props.reduceMotion\n ? { opacity: 0.48 }\n : props.phase === \"speaking\"\n ? { opacity: [0.42, 0.82, 0.52] }\n : props.phase === \"listening\"\n ? { opacity: [0.34, 0.62, 0.42] }\n : { opacity: [0.28, 0.58, 0.28] }\n }\n exit={{ opacity: 0 }}\n transition={\n props.reduceMotion\n ? { duration: 0.12 }\n : {\n duration: props.phase === \"speaking\" ? 1.15 : 2.1,\n ease: \"easeInOut\",\n repeat: Number.POSITIVE_INFINITY,\n }\n }\n className={cn(\n \"pointer-events-none absolute -inset-px z-[1] rounded-og-lg ring-1 ring-inset shadow-og-glow\",\n props.phase === \"speaking\"\n ? \"ring-og-status-running/50\"\n : props.phase === \"blocked\" || props.phase === \"error\"\n ? \"ring-og-status-waiting/45\"\n : \"ring-og-accent/45\",\n )}\n />\n ) : null}\n </AnimatePresence>\n );\n}\n\nfunction RealtimeActionGlyph(props: {\n phase: RealtimeVisualPhase;\n audioBlocked: boolean;\n reduceMotion: boolean;\n}) {\n if ([\"connecting\", \"reconnecting\", \"stopping\"].includes(props.phase)) {\n return <LoaderCircleIcon className=\"size-3.5 animate-og-spin\" aria-hidden />;\n }\n if (props.phase === \"blocked\") {\n return props.audioBlocked ? (\n <Volume2Icon className=\"size-3.5\" aria-hidden />\n ) : (\n <CircleAlertIcon className=\"size-3.5\" aria-hidden />\n );\n }\n if (props.phase === \"error\" || props.phase === \"elsewhere\" || props.phase === \"unavailable\") {\n return <CircleAlertIcon className=\"size-3.5\" aria-hidden />;\n }\n if (props.phase === \"listening\" || props.phase === \"speaking\") {\n return (\n <span className=\"relative inline-flex size-4 items-center justify-center\">\n {!props.reduceMotion ? (\n <motion.span\n aria-hidden\n className=\"absolute inset-0 rounded-full border border-current\"\n animate={{ opacity: [0.65, 0], scale: [0.65, 1.45] }}\n transition={{\n duration: props.phase === \"speaking\" ? 0.9 : 1.5,\n ease: \"easeOut\",\n repeat: Number.POSITIVE_INFINITY,\n }}\n />\n ) : null}\n <SquareIcon className=\"relative size-2.5 fill-current\" aria-hidden />\n </span>\n );\n }\n return <AudioLinesIcon className=\"size-4\" aria-hidden />;\n}\n\nfunction RealtimeStatusDot(props: { phase: RealtimeVisualPhase; reduceMotion: boolean }) {\n const live = props.phase === \"listening\" || props.phase === \"speaking\";\n return (\n <span className=\"relative inline-flex size-2 shrink-0\" aria-hidden>\n {live && !props.reduceMotion ? (\n <motion.span\n className=\"absolute inset-0 rounded-full bg-og-status-running\"\n animate={{ opacity: [0.45, 0], scale: [1, 2.2] }}\n transition={{ duration: 1.4, ease: \"easeOut\", repeat: Number.POSITIVE_INFINITY }}\n />\n ) : null}\n <span\n className={cn(\n \"relative size-2 rounded-full\",\n live\n ? \"bg-og-status-running\"\n : props.phase === \"blocked\" || props.phase === \"error\"\n ? \"bg-og-status-waiting\"\n : props.phase === \"elsewhere\" || props.phase === \"unavailable\"\n ? \"bg-og-fg-subtle\"\n : \"bg-og-accent\",\n )}\n />\n </span>\n );\n}\n\nfunction voiceButtonTone(phase: RealtimeVisualPhase): string {\n if (phase === \"listening\" || phase === \"speaking\") {\n return \"border border-og-accent/45 bg-og-accent text-og-accent-fg shadow-og-sm hover:bg-og-accent-strong\";\n }\n if (phase === \"blocked\" || phase === \"error\") {\n return \"border border-og-status-waiting/35 bg-og-status-waiting/10 text-og-status-waiting hover:bg-og-status-waiting/15\";\n }\n if (phase === \"connecting\" || phase === \"reconnecting\" || phase === \"stopping\") {\n return \"border border-og-accent/35 bg-og-accent-soft text-og-accent\";\n }\n // Idle: same ghost treatment as the composer transcription mic — no box.\n return \"text-og-fg-muted hover:bg-og-surface-2 hover:text-og-fg\";\n}\n\nfunction voiceChevronTone(phase: RealtimeVisualPhase): string {\n if (phase === \"listening\" || phase === \"speaking\") {\n return \"border border-l-0 border-og-accent/45 bg-og-accent text-og-accent-fg hover:bg-og-accent-strong\";\n }\n if (phase === \"blocked\" || phase === \"error\") {\n return \"border border-l-0 border-og-status-waiting/35 bg-og-status-waiting/10 text-og-status-waiting hover:bg-og-status-waiting/15\";\n }\n if (phase === \"connecting\" || phase === \"reconnecting\" || phase === \"stopping\") {\n return \"border border-l-0 border-og-accent/35 bg-og-accent-soft text-og-accent\";\n }\n return \"text-og-fg-muted hover:bg-og-surface-2 hover:text-og-fg\";\n}\n\nfunction toRealtimeModelOption(model: WorkspaceRealtimeModelCatalogItem): RealtimeModelOption {\n return { ...model };\n}\n\nfunction readRealtimeModelPreference(workspaceId: string): SessionRealtimeModel | null {\n if (typeof localStorage === \"undefined\") return null;\n try {\n const value = localStorage.getItem(`${REALTIME_MODEL_STORAGE_PREFIX}:${workspaceId}`);\n return isRealtimeModel(value) ? value : null;\n } catch {\n return null;\n }\n}\n\nfunction writeRealtimeModelPreference(workspaceId: string, model: SessionRealtimeModel): void {\n if (typeof localStorage === \"undefined\") return;\n try {\n localStorage.setItem(`${REALTIME_MODEL_STORAGE_PREFIX}:${workspaceId}`, model);\n } catch {\n // Voice selection still works when browser storage is unavailable.\n }\n}\n\nfunction isRealtimeModel(value: string | null): value is SessionRealtimeModel {\n return (\n value === \"gpt-live-1-boulder-alpha\" ||\n value === \"opengeni-gateway/openai/gpt-realtime-2.1\" ||\n value === \"opengeni-gateway/openai/gpt-realtime-mini\" ||\n value === \"opengeni-gateway/xai/grok-voice-think-fast-2.0\" ||\n value === \"workspace-gateway/openai/gpt-realtime-2.1\" ||\n value === \"workspace-gateway/openai/gpt-realtime-mini\" ||\n value === \"workspace-gateway/xai/grok-voice-think-fast-2.0\"\n );\n}\n\n/** @deprecated Use the provider-neutral realtime names. */\nexport const useSessionCodexRealtime = useSessionRealtime;\n/** @deprecated Use the provider-neutral realtime names. */\nexport const useWorkspaceRealtimeModelSelection = useRealtimeModelSelection;\n/** @deprecated Use the provider-neutral realtime names. */\nexport const SessionCodexRealtimeControl = SessionRealtimeControl;\n/** @deprecated Use the provider-neutral realtime names. */\nexport const CodexRealtimeControl = RealtimeVoiceControl;\n","\"use client\";\n\nimport { ChevronRightIcon } from \"lucide-react\";\nimport { DropdownMenu as DropdownMenuPrimitive } from \"radix-ui\";\nimport { createContext, useContext, type ComponentProps, type Ref } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { usePortalTokenSource, usePortalTokenStyle } from \"../lib/use-portal-token-style\";\n\ntype DropdownMenuSourceContextValue = {\n source: HTMLElement | null;\n ref: (node: HTMLElement | null) => void;\n};\n\nconst DropdownMenuSourceContext = createContext<DropdownMenuSourceContextValue | null>(null);\n\nfunction assignRef<T>(ref: Ref<T> | undefined, value: T | null) {\n if (typeof ref === \"function\") ref(value);\n else if (ref) ref.current = value;\n}\n\nfunction DropdownMenu(props: ComponentProps<typeof DropdownMenuPrimitive.Root>) {\n const source = usePortalTokenSource<HTMLElement>();\n return (\n <DropdownMenuSourceContext.Provider value={source}>\n <DropdownMenuPrimitive.Root data-slot=\"dropdown-menu\" {...props} />\n </DropdownMenuSourceContext.Provider>\n );\n}\n\nfunction DropdownMenuTrigger({\n ref,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {\n const sourceRef = useContext(DropdownMenuSourceContext);\n return (\n <DropdownMenuPrimitive.Trigger\n data-slot=\"dropdown-menu-trigger\"\n ref={(node) => {\n sourceRef?.ref(node);\n assignRef(ref, node);\n }}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuContent({\n className,\n sideOffset = 4,\n style,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Content>) {\n const source = useContext(DropdownMenuSourceContext);\n const portalStyle = usePortalTokenStyle(source?.source ?? null);\n return (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n data-slot=\"dropdown-menu-content\"\n sideOffset={sideOffset}\n className={cn(\n \"og-root z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95\",\n className,\n )}\n style={{ ...portalStyle, ...style }}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n );\n}\n\nfunction DropdownMenuItem({\n className,\n inset,\n variant = \"default\",\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Item> & {\n inset?: boolean;\n variant?: \"default\" | \"destructive\";\n}) {\n return (\n <DropdownMenuPrimitive.Item\n data-slot=\"dropdown-menu-item\"\n data-inset={inset}\n data-variant={variant}\n className={cn(\n \"relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-og-menu outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground data-[variant=destructive]:*:[svg]:text-destructive!\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuSeparator({\n className,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.Separator>) {\n return (\n <DropdownMenuPrimitive.Separator\n data-slot=\"dropdown-menu-separator\"\n className={cn(\"-mx-1 my-1 h-px bg-border\", className)}\n {...props}\n />\n );\n}\n\nfunction DropdownMenuSub(props: ComponentProps<typeof DropdownMenuPrimitive.Sub>) {\n return <DropdownMenuPrimitive.Sub data-slot=\"dropdown-menu-sub\" {...props} />;\n}\n\nfunction DropdownMenuSubTrigger({\n className,\n inset,\n children,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & { inset?: boolean }) {\n return (\n <DropdownMenuPrimitive.SubTrigger\n data-slot=\"dropdown-menu-sub-trigger\"\n data-inset={inset}\n className={cn(\n \"flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-og-menu outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground\",\n className,\n )}\n {...props}\n >\n {children}\n <ChevronRightIcon className=\"ml-auto size-4\" />\n </DropdownMenuPrimitive.SubTrigger>\n );\n}\n\nfunction DropdownMenuSubContent({\n className,\n style,\n ...props\n}: ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {\n const source = useContext(DropdownMenuSourceContext);\n const portalStyle = usePortalTokenStyle(source?.source ?? null);\n return (\n <DropdownMenuPrimitive.SubContent\n data-slot=\"dropdown-menu-sub-content\"\n className={cn(\n \"og-root z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95\",\n className,\n )}\n style={{ ...portalStyle, ...style }}\n {...props}\n />\n );\n}\n\nexport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n};\n"],"mappings":"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","names":["jsx","jsxs"]}
@@ -9,12 +9,12 @@ import {
9
9
  UserMessageBody,
10
10
  sessionChromeGoalPillState,
11
11
  userMessageLikelyNeedsDisclosure
12
- } from "./chunk-FD72GJMK.js";
13
- import "./chunk-VCBFUSUZ.js";
14
- import "./chunk-LWR4MXSS.js";
15
- import "./chunk-U3CSCMWA.js";
12
+ } from "./chunk-XCNTXWBB.js";
13
+ import "./chunk-O4VXOBGF.js";
14
+ import "./chunk-LHLYWG5R.js";
15
+ import "./chunk-FK6VG4LL.js";
16
16
  import "./chunk-LAKLF4PA.js";
17
- import "./chunk-JB5725BI.js";
17
+ import "./chunk-VZTQ73XT.js";
18
18
  import "./chunk-22KP6LR5.js";
19
19
  export {
20
20
  BUILT_IN_TURN_SUMMARY_FACET_IDS,
package/dist/session.js CHANGED
@@ -18,7 +18,7 @@ import {
18
18
  useSessionLineage,
19
19
  useSessionMcpApprovalPolicy,
20
20
  useTurnQueue
21
- } from "./chunk-SRFUT2ZU.js";
21
+ } from "./chunk-I4MPFDRP.js";
22
22
  import {
23
23
  buildTimeline,
24
24
  creditExhaustedFromEvents,
@@ -26,15 +26,15 @@ import {
26
26
  groupTimeline,
27
27
  sessionStatusFromEvents,
28
28
  toolDisplayName
29
- } from "./chunk-LWR4MXSS.js";
29
+ } from "./chunk-LHLYWG5R.js";
30
30
  import {
31
31
  FILE_ONLY_MESSAGE_TEXT,
32
32
  composeSendInput,
33
33
  shouldSteerOnKey,
34
34
  shouldSubmitOnKey,
35
35
  useComposer
36
- } from "./chunk-HFO4ERGQ.js";
37
- import "./chunk-EB67J347.js";
36
+ } from "./chunk-FWXGSNXT.js";
37
+ import "./chunk-KZ73RL76.js";
38
38
  import "./chunk-EKZH6IDG.js";
39
39
  import "./chunk-LAKLF4PA.js";
40
40
  export {
@@ -1,4 +1,4 @@
1
- import type { ToolRegistry } from "./registry";
1
+ import type { RetainedScreenshotLoader, ToolRegistry } from "./registry";
2
2
  import type { ActivityItem } from "./types";
3
3
  export type ActivityRailProps = {
4
4
  items: ActivityItem[];
@@ -12,8 +12,9 @@ export type ActivityRailProps = {
12
12
  * row is then non-interactive rich content). See {@link MessageTimelineProps}.
13
13
  */
14
14
  onMemoryClick?: ((memoryId: string) => void) | undefined;
15
+ loadRetainedScreenshot?: RetainedScreenshotLoader | undefined;
15
16
  /** Drop the left rule + indent (used inside a folded turn summary). */
16
17
  bare?: boolean | undefined;
17
18
  className?: string | undefined;
18
19
  };
19
- export declare function ActivityRail({ items, toolRegistry, onOpenSession, onMemoryClick, bare, className, }: ActivityRailProps): import("react/jsx-runtime").JSX.Element;
20
+ export declare function ActivityRail({ items, toolRegistry, onOpenSession, onMemoryClick, loadRetainedScreenshot, bare, className, }: ActivityRailProps): import("react/jsx-runtime").JSX.Element;
@@ -1,7 +1,7 @@
1
1
  export { buildTimeline, creditExhaustedFromEvents, extractSessionRef, groupTimeline, sessionStatusFromEvents, mcpToolLeaf, toolDisplayName, toolMatchesLeaf, } from "./projection";
2
2
  export type { ActivityItem, AgentMessageItem, AuthNeededItem, ContextCompactionItem, FleetDecisionItem, FleetDecisionScoreItem, GoalItem, MachineInputBatchItem, MachineInputMember, MemoryItem, NoticeItem, ReasoningItem, SandboxItem, SessionStatusItem, TimelineGroup, TimelineItem, TurnEndItem, ToolCallItem, UserMessageItem, WorkerCompletionItem, WorkerItem, } from "./types";
3
3
  export { createToolRegistry, rawTypeOf } from "./registry";
4
- export type { CreateToolRegistryOptions, ToolRegistry, ToolRegistryEntry, ToolRenderer, ToolRendererProps, } from "./registry";
4
+ export type { CreateToolRegistryOptions, RetainedScreenshotLoader, ToolRegistry, ToolRegistryEntry, ToolRenderer, ToolRendererProps, } from "./registry";
5
5
  export { createDefaultToolRegistry, defaultToolRegistry } from "./tool-renderers";
6
6
  export { ActivityRail } from "./activity-rail";
7
7
  export type { ActivityRailProps } from "./activity-rail";
@@ -15,5 +15,5 @@ export { SeenActivityIdsProvider, useSeenActivityIds } from "./seen-activity-ids
15
15
  export { TimelineComputeLabelProvider, useTimelineComputeLabel } from "./compute-label";
16
16
  export { BUILT_IN_TURN_SUMMARY_FACET_IDS, TurnSummary, useTurnSettleOpen } from "./turn-summary";
17
17
  export type { BuiltInTurnSummaryFacetId, TurnOutcome, TurnSummaryContext, TurnSummaryFacet, TurnSummaryFacetConfiguration, TurnSummaryFacetResult, TurnSummaryOptions, TurnSummaryProps, } from "./turn-summary";
18
- export { applyPatchOps, applyPatchOpsFromToolItem, parseFreeformApplyPatch, controlCaret, execTruncated, isApplyPatch, isExecSessionLostBanner, looksBinary, parseExecBannerSessionId, parseToolArgs, redactSecrets, sandboxCommandExitCode, stripExecBanner, tailPeek, unwrapMcpOutput, v4aToGitFileDiff, } from "./parsers";
18
+ export { applyPatchOps, applyPatchOpsFromToolItem, parseFreeformApplyPatch, controlCaret, execTruncated, isApplyPatch, isExecSessionLostBanner, looksBinary, parseExecBannerSessionId, parseToolArgs, sandboxCommandExitCode, stripExecBanner, tailPeek, unwrapMcpOutput, v4aToGitFileDiff, } from "./parsers";
19
19
  export type { ApplyPatchOperation } from "./parsers";
@@ -1,4 +1,4 @@
1
- import { type GitFileDiff } from "@opengeni/sdk";
1
+ import { type GitFileDiff, type RetainedArtifactMetadata } from "@opengeni/sdk";
2
2
  /** Recover the exit code from a sandbox exec banner (`Process exited with code N`). */
3
3
  export declare function sandboxCommandExitCode(out: unknown): number | null;
4
4
  /**
@@ -68,8 +68,6 @@ export declare function isApplyPatch(item: {
68
68
  name: string;
69
69
  raw: unknown;
70
70
  }): boolean;
71
- /** Deep-redact secret-looking values so arguments never leak a key into the UI. */
72
- export declare function redactSecrets(value: unknown): unknown;
73
71
  /** Parse tool arguments that may arrive as a JSON string or an object. */
74
72
  export declare function parseToolArgs(args: unknown): Record<string, unknown>;
75
73
  /** The last non-empty line of a string -- the compact "what happened" peek. */
@@ -95,6 +93,8 @@ export declare function unwrapMcpOutput(output: unknown): {
95
93
  * text/empty presentation).
96
94
  */
97
95
  export declare function screenshotDataUrl(out: unknown): string | null;
96
+ /** Parse the closed retained-screenshot receipt carried by new tool events. */
97
+ export declare function retainedScreenshotMetadata(out: unknown): RetainedArtifactMetadata | null;
98
98
  export type TimelineMediaPreview = {
99
99
  type: "media_preview";
100
100
  mediaType: string;
@@ -1,8 +1,11 @@
1
+ import type { RetainedArtifactReference } from "@opengeni/sdk";
1
2
  import type { ComponentType } from "react";
2
3
  import type { ToolCallItem } from "./types";
3
4
  export type ToolRendererProps = {
4
5
  item: ToolCallItem;
6
+ loadRetainedScreenshot?: RetainedScreenshotLoader | undefined;
5
7
  };
8
+ export type RetainedScreenshotLoader = (artifact: RetainedArtifactReference, signal: AbortSignal) => Promise<Uint8Array | null>;
6
9
  export type ToolRenderer = ComponentType<ToolRendererProps>;
7
10
  /** A registry entry: which key it matches and the component that renders it. */
8
11
  export type ToolRegistryEntry = {
@@ -1,6 +1,6 @@
1
1
  import { type ReactNode } from "react";
2
2
  type LightboxController = {
3
- open: (src: string, caption?: string) => void;
3
+ open: (src: string, caption?: string, source?: HTMLElement | null) => void;
4
4
  };
5
5
  /** Open the app-level screenshot lightbox. No-op outside a `LightboxProvider`. */
6
6
  export declare function useLightbox(): LightboxController;
@@ -240,6 +240,10 @@ export type AuthNeededItem = {
240
240
  kind: "auth-needed";
241
241
  id: string;
242
242
  turnId: string | null;
243
+ /** The runtime surface that requested recovery, when the event is an MCP auth signal. */
244
+ serverId: string | null;
245
+ /** Durable event family that produced this notice. */
246
+ source?: "tool" | "credential" | undefined;
243
247
  /** The connection's registrable domain, e.g. "linear.app". */
244
248
  providerDomain: string;
245
249
  /** The lapsed connection to reconnect, when the row survived. */
@@ -3,6 +3,8 @@ export type VoiceRecordingUploadState = "pending" | "syncing" | "retrying" | "co
3
3
  export type VoiceRecordingTranscriptionState = "pending" | "transcribing" | "retrying" | "complete";
4
4
  export type VoiceRecordingFinalizationState = "pending" | "transcript-ready" | "handed-off";
5
5
  export type VoiceRecordingChunkUploadState = "pending" | "syncing" | "complete";
6
+ export type VoiceRecordingRecoveryMode = "automatic" | "manual";
7
+ export type VoiceRecordingHandoffMode = "append" | "explicit";
6
8
  export type VoiceRecordingManifest = {
7
9
  version: 1;
8
10
  recordingId: string;
@@ -15,6 +17,10 @@ export type VoiceRecordingManifest = {
15
17
  uploadState: VoiceRecordingUploadState;
16
18
  transcriptionState: VoiceRecordingTranscriptionState;
17
19
  finalizationState: VoiceRecordingFinalizationState;
20
+ /** Whether safe server reconciliation should continue without another user action. */
21
+ recoveryMode: VoiceRecordingRecoveryMode;
22
+ /** Delayed/recovered results require explicit insertion instead of mutating an uncertain draft. */
23
+ handoffMode: VoiceRecordingHandoffMode;
18
24
  /** Tab/process lease. A different owner may take over only after this heartbeat is stale. */
19
25
  ownerId: string | null;
20
26
  ownerHeartbeatAt: string | null;
@@ -63,7 +69,7 @@ export interface VoiceRecordingStore {
63
69
  claimManifest(recordingId: string, ownerId: string, claimedAt: string, staleBefore: string): Promise<VoiceRecordingManifest>;
64
70
  listChunks(recordingId: string): Promise<VoiceRecordingChunk[]>;
65
71
  persistChunk(input: PersistVoiceRecordingChunkInput): Promise<PersistVoiceRecordingChunkResult>;
66
- updateManifest(recordingId: string, update: Partial<Pick<VoiceRecordingManifest, "captureState" | "uploadState" | "transcriptionState" | "finalizationState" | "ownerId" | "ownerHeartbeatAt" | "transcriptText">>, updatedAt: string, ownerId?: string | undefined): Promise<VoiceRecordingManifest>;
72
+ updateManifest(recordingId: string, update: Partial<Pick<VoiceRecordingManifest, "captureState" | "uploadState" | "transcriptionState" | "finalizationState" | "ownerId" | "ownerHeartbeatAt" | "transcriptText" | "recoveryMode" | "handoffMode">>, updatedAt: string, ownerId?: string | undefined): Promise<VoiceRecordingManifest>;
67
73
  discard(recordingId: string, ownerId?: string | undefined): Promise<void>;
68
74
  cleanupHandedOffManifests(ownership: {
69
75
  ownerId: string;
@@ -114,7 +120,7 @@ export declare class IndexedDbVoiceRecordingStore implements VoiceRecordingStore
114
120
  claimManifest(recordingId: string, ownerId: string, claimedAt: string, staleBefore: string): Promise<VoiceRecordingManifest>;
115
121
  listChunks(recordingId: string): Promise<VoiceRecordingChunk[]>;
116
122
  persistChunk(input: PersistVoiceRecordingChunkInput): Promise<PersistVoiceRecordingChunkResult>;
117
- updateManifest(recordingId: string, update: Partial<Pick<VoiceRecordingManifest, "captureState" | "uploadState" | "transcriptionState" | "finalizationState" | "ownerId" | "ownerHeartbeatAt" | "transcriptText">>, updatedAt: string, ownerId?: string | undefined): Promise<VoiceRecordingManifest>;
123
+ updateManifest(recordingId: string, update: Partial<Pick<VoiceRecordingManifest, "captureState" | "uploadState" | "transcriptionState" | "finalizationState" | "ownerId" | "ownerHeartbeatAt" | "transcriptText" | "recoveryMode" | "handoffMode">>, updatedAt: string, ownerId?: string | undefined): Promise<VoiceRecordingManifest>;
118
124
  discard(recordingId: string, ownerId?: string | undefined): Promise<void>;
119
125
  cleanupHandedOffManifests(ownership: {
120
126
  ownerId: string;