{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "voice-conversation",
  "type": "registry:component",
  "title": "Voice conversation",
  "description": "The live call screen bound to the thread's voice session: orb, caption, transcript, mute, and end call.",
  "dependencies": [
    "@assistant-ui/react@^0.15.23"
  ],
  "registryDependencies": [
    "https://r.assistant-ui.com/elements-voice-conversation.json"
  ],
  "files": [
    {
      "type": "registry:component",
      "path": "components/assistant-ui/elements/voice-conversation.aui.tsx",
      "sourcePath": "packages/ui/src/components/react/assistant-ui/elements/voice-conversation.aui.tsx",
      "content": "\"use client\";\n\nimport {\n  type TextMessagePart,\n  type ThreadMessage,\n  useAuiState,\n  useVoiceControls,\n  useVoiceState,\n  useVoiceVolume,\n  type VoiceSessionState,\n} from \"@assistant-ui/react\";\nimport { type FC, useMemo, useState } from \"react\";\nimport {\n  VoiceConversation as VoiceConversationBase,\n  type VoiceMode,\n  type VoiceTurn,\n} from \"./voice-conversation\";\n\nexport type { VoiceMode, VoiceTurn } from \"./voice-conversation\";\n\nconst deriveVoiceMode = (\n  voice: VoiceSessionState | undefined,\n): VoiceMode | undefined => {\n  if (voice === undefined || voice.status.type === \"ended\") return undefined;\n  if (voice.status.type === \"starting\") return \"connecting\";\n  return voice.mode;\n};\n\nconst toVoiceTurn = (message: ThreadMessage): VoiceTurn => ({\n  id: message.id,\n  role: message.role === \"user\" ? \"user\" : \"assistant\",\n  text: message.content\n    .filter((part): part is TextMessagePart => part.type === \"text\")\n    .map((part) => part.text)\n    .join(\"\"),\n});\n\nexport const useVoiceTranscript = (): readonly VoiceTurn[] => {\n  const active = deriveVoiceMode(useVoiceState()) !== undefined;\n  const messages = useAuiState((s) => s.thread.messages);\n  const [session, setSession] = useState({ active, start: messages.length });\n  if (session.active !== active) {\n    setSession({ active, start: messages.length });\n  }\n  const start = session.active === active ? session.start : messages.length;\n\n  return useMemo(\n    () =>\n      messages\n        .slice(start)\n        .filter((message) => message.metadata.modality === \"voice\")\n        .map(toVoiceTurn),\n    [messages, start],\n  );\n};\n\nexport const VoiceConversation: FC<{ className?: string }> = ({\n  className,\n}) => {\n  const voice = useVoiceState();\n  const amplitude = useVoiceVolume();\n  const transcript = useVoiceTranscript();\n  const { mute, unmute, disconnect } = useVoiceControls();\n  const mode = deriveVoiceMode(voice);\n  if (mode === undefined || voice === undefined) return null;\n\n  return (\n    <VoiceConversationBase\n      className={className}\n      mode={mode}\n      amplitude={amplitude}\n      transcript={transcript.slice(-2)}\n      muted={voice.isMuted}\n      onToggleMute={voice.isMuted ? unmute : mute}\n      onEnd={disconnect}\n    />\n  );\n};\n"
    }
  ]
}