{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "thread",
  "type": "registry:component",
  "title": "Thread",
  "description": "Chat container with message list, composer, auto scroll, and accessibility built in.",
  "dependencies": [
    "@assistant-ui/react",
    "lucide-react"
  ],
  "registryDependencies": [
    "button",
    "https://r.assistant-ui.com/attachment.json",
    "https://r.assistant-ui.com/file.json",
    "https://r.assistant-ui.com/follow-up-suggestions.json",
    "https://r.assistant-ui.com/image.json",
    "https://r.assistant-ui.com/markdown-text.json",
    "https://r.assistant-ui.com/reasoning.json",
    "https://r.assistant-ui.com/tooltip-icon-button.json",
    "https://r.assistant-ui.com/tool-fallback.json",
    "https://r.assistant-ui.com/tool-group.json"
  ],
  "files": [
    {
      "type": "registry:component",
      "path": "components/assistant-ui/thread.tsx",
      "content": "\"use client\";\n\nimport {\n  ComposerAddAttachment,\n  ComposerAttachments,\n  UserMessageAttachments,\n} from \"@/components/assistant-ui/attachment\";\nimport { File } from \"@/components/assistant-ui/file\";\nimport { ThreadFollowupSuggestions } from \"@/components/assistant-ui/follow-up-suggestions\";\nimport { Image } from \"@/components/assistant-ui/image\";\nimport { MarkdownText } from \"@/components/assistant-ui/markdown-text\";\nimport {\n  Reasoning,\n  ReasoningContent,\n  ReasoningRoot,\n  ReasoningText,\n  ReasoningTrigger,\n} from \"@/components/assistant-ui/reasoning\";\nimport { ToolFallback } from \"@/components/assistant-ui/tool-fallback\";\nimport {\n  ToolGroupContent,\n  ToolGroupRoot,\n  ToolGroupTrigger,\n} from \"@/components/assistant-ui/tool-group\";\nimport { TooltipIconButton } from \"@/components/assistant-ui/tooltip-icon-button\";\nimport { Button } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\nimport {\n  ActionBarMorePrimitive,\n  ActionBarPrimitive,\n  AuiIf,\n  type AssistantState,\n  BranchPickerPrimitive,\n  ComposerPrimitive,\n  ErrorPrimitive,\n  groupPartByType,\n  MessagePrimitive,\n  SuggestionPrimitive,\n  ThreadPrimitive,\n  type FileMessagePartComponent,\n  type ImageMessagePartComponent,\n  type ToolCallMessagePartComponent,\n  useAuiState,\n} from \"@assistant-ui/react\";\nimport {\n  ArrowDownIcon,\n  ArrowUpIcon,\n  CheckIcon,\n  ChevronLeftIcon,\n  ChevronRightIcon,\n  CopyIcon,\n  DownloadIcon,\n  MicIcon,\n  MoreHorizontalIcon,\n  PencilIcon,\n  RefreshCwIcon,\n  SquareIcon,\n} from \"lucide-react\";\nimport {\n  createContext,\n  useContext,\n  type ComponentType,\n  type FC,\n  type PropsWithChildren,\n} from \"react\";\n\nexport type ThreadGroupPart = MessagePrimitive.GroupedParts.GroupPart;\n\n/**\n * Optional component overrides for the thread. `AssistantMessage` and\n * `Welcome` replace whole sections; the remaining slots override how the\n * assistant message renders tool calls and part groups. Tool UIs registered\n * by name (toolkit `render`, `useAssistantDataUI`) take precedence over\n * `ToolFallback`.\n */\nexport type ThreadComponents = {\n  AssistantMessage?: ComponentType | undefined;\n  Welcome?: ComponentType | undefined;\n  ToolFallback?: ToolCallMessagePartComponent | undefined;\n  ToolGroup?:\n    | ComponentType<PropsWithChildren<{ group: ThreadGroupPart }>>\n    | undefined;\n  ReasoningGroup?:\n    | ComponentType<PropsWithChildren<{ group: ThreadGroupPart }>>\n    | undefined;\n};\n\nexport type ThreadProps = {\n  components?: ThreadComponents | undefined;\n};\n\nconst EMPTY_COMPONENTS: ThreadComponents = {};\n\nconst ThreadComponentsContext =\n  createContext<ThreadComponents>(EMPTY_COMPONENTS);\n\n// Startup exposes a loading placeholder thread; treat it as a new chat so\n// the composer mounts centered. Loads after startup keep the docked layout.\nconst isNewChatView = (s: AssistantState) =>\n  s.thread.messages.length === 0 &&\n  (!s.thread.isLoading || s.threads.isLoading);\n\nexport const Thread: FC<ThreadProps> = ({ components = EMPTY_COMPONENTS }) => {\n  const isEmpty = useAuiState(isNewChatView);\n\n  return (\n    <ThreadComponentsContext.Provider value={components}>\n      <ThreadRoot isEmpty={isEmpty} />\n    </ThreadComponentsContext.Provider>\n  );\n};\n\nconst ThreadRoot: FC<{ isEmpty: boolean }> = ({ isEmpty }) => {\n  const { Welcome = ThreadWelcome } = useContext(ThreadComponentsContext);\n\n  return (\n    <ThreadPrimitive.Root\n      className=\"aui-root aui-thread-root bg-background @container flex h-full flex-col\"\n      style={{\n        [\"--thread-max-width\" as string]: \"44rem\",\n        [\"--composer-bg\" as string]:\n          \"color-mix(in oklab, var(--color-muted) 30%, var(--color-background))\",\n        [\"--composer-radius\" as string]: \"1.5rem\",\n        [\"--composer-padding\" as string]: \"8px\",\n      }}\n    >\n      <ThreadPrimitive.Viewport\n        turnAnchor=\"top\"\n        data-slot=\"aui_thread-viewport\"\n        className=\"relative flex flex-1 flex-col overflow-x-auto overflow-y-scroll scroll-smooth\"\n      >\n        <div\n          className={cn(\n            \"mx-auto flex w-full max-w-(--thread-max-width) flex-1 flex-col px-4 pt-4\",\n            isEmpty && \"justify-center\",\n          )}\n        >\n          <AuiIf condition={isNewChatView}>\n            <Welcome />\n          </AuiIf>\n\n          <div\n            data-slot=\"aui_message-group\"\n            className=\"mb-14 flex flex-col gap-y-6 empty:hidden\"\n          >\n            <ThreadPrimitive.Messages>\n              {() => <ThreadMessage />}\n            </ThreadPrimitive.Messages>\n          </div>\n\n          <ThreadPrimitive.ViewportFooter\n            className={cn(\n              \"aui-thread-viewport-footer bg-background flex flex-col gap-4 overflow-visible pb-4 md:pb-6\",\n              !isEmpty &&\n                \"sticky bottom-0 mt-auto rounded-t-(--composer-radius)\",\n            )}\n          >\n            <ThreadScrollToBottom />\n            <ThreadFollowupSuggestions />\n            <Composer />\n            <AuiIf condition={(s) => isNewChatView(s) && s.composer.isEmpty}>\n              <ThreadSuggestions />\n            </AuiIf>\n          </ThreadPrimitive.ViewportFooter>\n        </div>\n      </ThreadPrimitive.Viewport>\n    </ThreadPrimitive.Root>\n  );\n};\n\nconst ThreadMessage: FC = () => {\n  const { AssistantMessage: AssistantMessageComponent = AssistantMessage } =\n    useContext(ThreadComponentsContext);\n  const role = useAuiState((s) => s.message.role);\n  const isEditing = useAuiState((s) => s.message.composer.isEditing);\n\n  if (isEditing) return <EditComposer />;\n  if (role === \"user\") return <UserMessage />;\n  return <AssistantMessageComponent />;\n};\n\nconst ThreadScrollToBottom: FC = () => {\n  return (\n    <ThreadPrimitive.ScrollToBottom asChild>\n      <TooltipIconButton\n        tooltip=\"Scroll to bottom\"\n        variant=\"outline\"\n        className=\"aui-thread-scroll-to-bottom dark:border-border dark:bg-background dark:hover:bg-accent absolute -top-12 z-10 self-center rounded-full p-4 disabled:invisible\"\n      >\n        <ArrowDownIcon />\n      </TooltipIconButton>\n    </ThreadPrimitive.ScrollToBottom>\n  );\n};\n\nconst ThreadWelcome: FC = () => {\n  return (\n    <div className=\"aui-thread-welcome-root mb-6 flex flex-col items-center px-4 text-center\">\n      <h1 className=\"aui-thread-welcome-message-inner fade-in slide-in-from-bottom-1 animate-in fill-mode-both text-2xl font-semibold duration-200\">\n        How can I help you today?\n      </h1>\n    </div>\n  );\n};\n\nconst ThreadSuggestions: FC = () => {\n  return (\n    <div className=\"aui-thread-welcome-suggestions flex w-full flex-wrap items-center justify-center gap-2 px-4\">\n      <ThreadPrimitive.Suggestions>\n        {() => <ThreadSuggestionItem />}\n      </ThreadPrimitive.Suggestions>\n    </div>\n  );\n};\n\nconst ThreadSuggestionItem: FC = () => {\n  return (\n    <div className=\"aui-thread-welcome-suggestion-display fade-in slide-in-from-bottom-2 animate-in fill-mode-both duration-200\">\n      <SuggestionPrimitive.Trigger send asChild>\n        <Button\n          variant=\"ghost\"\n          className=\"aui-thread-welcome-suggestion text-foreground hover:bg-muted border-border/60 h-auto gap-1.5 rounded-full border px-3.5 py-1.5 text-sm font-normal whitespace-nowrap transition-colors\"\n        >\n          <SuggestionPrimitive.Title className=\"aui-thread-welcome-suggestion-text-1\" />\n          <SuggestionPrimitive.Description className=\"aui-thread-welcome-suggestion-text-2 empty:hidden\" />\n        </Button>\n      </SuggestionPrimitive.Trigger>\n    </div>\n  );\n};\n\nconst Composer: FC = () => {\n  return (\n    <ComposerPrimitive.Root className=\"aui-composer-root relative flex w-full flex-col\">\n      <ComposerPrimitive.AttachmentDropzone asChild>\n        <div\n          data-slot=\"aui_composer-shell\"\n          className=\"border-border/60 data-[dragging=true]:border-ring focus-within:border-border dark:border-muted-foreground/15 dark:focus-within:border-muted-foreground/30 flex w-full flex-col gap-2 rounded-(--composer-radius) border bg-(--composer-bg) p-(--composer-padding) shadow-[0_4px_16px_-8px_rgba(0,0,0,0.08),0_1px_2px_rgba(0,0,0,0.04)] transition-[border-color,box-shadow] focus-within:shadow-[0_6px_24px_-8px_rgba(0,0,0,0.12),0_1px_2px_rgba(0,0,0,0.05)] data-[dragging=true]:border-dashed data-[dragging=true]:bg-[color-mix(in_oklab,var(--color-accent)_50%,var(--color-background))] dark:shadow-none\"\n        >\n          <ComposerAttachments />\n          <ComposerPrimitive.Input\n            placeholder=\"Send a message...\"\n            className=\"aui-composer-input caret-primary placeholder:text-muted-foreground/80 max-h-32 min-h-10 w-full resize-none bg-transparent px-2.5 py-1 text-base outline-none\"\n            rows={1}\n            autoFocus\n            enterKeyHint=\"send\"\n            aria-label=\"Message input\"\n          />\n          <ComposerAction />\n        </div>\n      </ComposerPrimitive.AttachmentDropzone>\n    </ComposerPrimitive.Root>\n  );\n};\n\nconst ComposerAction: FC = () => {\n  return (\n    <div className=\"aui-composer-action-wrapper relative flex items-center justify-between\">\n      <ComposerAddAttachment />\n      <div className=\"flex items-center gap-1.5\">\n        <AuiIf condition={(s) => s.thread.capabilities.dictation}>\n          <AuiIf condition={(s) => s.composer.dictation == null}>\n            <ComposerPrimitive.Dictate asChild>\n              <TooltipIconButton\n                tooltip=\"Voice input\"\n                side=\"bottom\"\n                type=\"button\"\n                variant=\"ghost\"\n                size=\"icon\"\n                className=\"aui-composer-dictate size-7 rounded-full\"\n                aria-label=\"Start voice input\"\n              >\n                <MicIcon className=\"aui-composer-dictate-icon size-4\" />\n              </TooltipIconButton>\n            </ComposerPrimitive.Dictate>\n          </AuiIf>\n          <AuiIf condition={(s) => s.composer.dictation != null}>\n            <ComposerPrimitive.StopDictation asChild>\n              <TooltipIconButton\n                tooltip=\"Stop dictation\"\n                side=\"bottom\"\n                type=\"button\"\n                variant=\"ghost\"\n                size=\"icon\"\n                className=\"aui-composer-stop-dictation text-destructive size-7 rounded-full\"\n                aria-label=\"Stop voice input\"\n              >\n                <SquareIcon className=\"aui-composer-stop-dictation-icon size-3.5 animate-pulse fill-current\" />\n              </TooltipIconButton>\n            </ComposerPrimitive.StopDictation>\n          </AuiIf>\n        </AuiIf>\n        <AuiIf condition={(s) => !s.thread.isRunning}>\n          <ComposerPrimitive.Send asChild>\n            <TooltipIconButton\n              tooltip=\"Send message\"\n              side=\"bottom\"\n              type=\"button\"\n              variant=\"default\"\n              size=\"icon\"\n              className=\"aui-composer-send size-7 rounded-full\"\n              aria-label=\"Send message\"\n            >\n              <ArrowUpIcon className=\"aui-composer-send-icon size-4.5\" />\n            </TooltipIconButton>\n          </ComposerPrimitive.Send>\n        </AuiIf>\n        <AuiIf condition={(s) => s.thread.isRunning}>\n          <ComposerPrimitive.Cancel asChild>\n            <Button\n              type=\"button\"\n              variant=\"default\"\n              size=\"icon\"\n              className=\"aui-composer-cancel size-7 rounded-full\"\n              aria-label=\"Stop generating\"\n            >\n              <SquareIcon className=\"aui-composer-cancel-icon size-3.5 fill-current\" />\n            </Button>\n          </ComposerPrimitive.Cancel>\n        </AuiIf>\n      </div>\n    </div>\n  );\n};\n\nconst MessageError: FC = () => {\n  return (\n    <MessagePrimitive.Error>\n      <ErrorPrimitive.Root className=\"aui-message-error-root border-destructive bg-destructive/10 text-destructive dark:bg-destructive/5 mt-2 rounded-md border p-3 text-sm dark:text-red-200\">\n        <ErrorPrimitive.Message className=\"aui-message-error-message line-clamp-2\" />\n      </ErrorPrimitive.Root>\n    </MessagePrimitive.Error>\n  );\n};\n\nconst AssistantMessage: FC = () => {\n  const {\n    ToolFallback: ToolFallbackComponent = ToolFallback,\n    ToolGroup,\n    ReasoningGroup,\n  } = useContext(ThreadComponentsContext);\n\n  const ACTION_BAR_PT = \"pt-1.5\";\n  // Keep the action bar inside the contained root's paint box, then cancel its reserved space in flow.\n  const ACTION_BAR_HEIGHT = `min-h-7.5 ${ACTION_BAR_PT}`;\n\n  return (\n    <MessagePrimitive.Root\n      data-slot=\"aui_assistant-message-root\"\n      data-role=\"assistant\"\n      className=\"fade-in slide-in-from-bottom-1 animate-in relative -mb-7.5 pb-7.5 duration-150 [contain-intrinsic-size:auto_200px] [content-visibility:auto]\"\n    >\n      <div\n        data-slot=\"aui_assistant-message-content\"\n        className=\"text-foreground px-2 leading-relaxed wrap-break-word\"\n      >\n        <MessagePrimitive.GroupedParts\n          groupBy={groupPartByType({\n            reasoning: [\"group-chainOfThought\", \"group-reasoning\"],\n            \"tool-call\": [\"group-chainOfThought\", \"group-tool\"],\n            \"standalone-tool-call\": [],\n          })}\n        >\n          {({ part, children }) => {\n            switch (part.type) {\n              case \"group-chainOfThought\":\n                return <div data-slot=\"aui_chain-of-thought\">{children}</div>;\n              case \"group-tool\":\n                if (ToolGroup) {\n                  return <ToolGroup group={part}>{children}</ToolGroup>;\n                }\n                return (\n                  <ToolGroupRoot variant=\"ghost\">\n                    <ToolGroupTrigger\n                      count={part.indices.length}\n                      active={part.status.type === \"running\"}\n                    />\n                    <ToolGroupContent>{children}</ToolGroupContent>\n                  </ToolGroupRoot>\n                );\n              case \"group-reasoning\": {\n                if (ReasoningGroup) {\n                  return (\n                    <ReasoningGroup group={part}>{children}</ReasoningGroup>\n                  );\n                }\n                const running = part.status.type === \"running\";\n                return (\n                  <ReasoningRoot streaming={running}>\n                    <ReasoningTrigger active={running} />\n                    <ReasoningContent aria-busy={running}>\n                      <ReasoningText>{children}</ReasoningText>\n                    </ReasoningContent>\n                  </ReasoningRoot>\n                );\n              }\n              case \"text\":\n                return <MarkdownText />;\n              case \"reasoning\":\n                return <Reasoning {...part} />;\n              case \"tool-call\":\n                return part.toolUI ?? <ToolFallbackComponent {...part} />;\n              case \"data\":\n                return part.dataRendererUI;\n              case \"file\":\n                return (\n                  <div data-slot=\"aui_assistant-message-file\" className=\"py-1\">\n                    <File {...part} />\n                  </div>\n                );\n              case \"image\":\n                return (\n                  <div data-slot=\"aui_assistant-message-image\" className=\"py-1\">\n                    <Image {...part} />\n                  </div>\n                );\n              case \"indicator\":\n                return (\n                  <span\n                    data-slot=\"aui_assistant-message-indicator\"\n                    className=\"animate-pulse font-sans\"\n                    aria-label=\"Assistant is working\"\n                  >\n                    {\"●\"}\n                  </span>\n                );\n              default:\n                return null;\n            }\n          }}\n        </MessagePrimitive.GroupedParts>\n        <MessageError />\n      </div>\n\n      <div\n        data-slot=\"aui_assistant-message-footer\"\n        className={cn(\"ms-2 flex items-center\", ACTION_BAR_HEIGHT)}\n      >\n        <BranchPicker />\n        <AssistantActionBar />\n      </div>\n    </MessagePrimitive.Root>\n  );\n};\n\nconst AssistantActionBar: FC = () => {\n  return (\n    <ActionBarPrimitive.Root\n      hideWhenRunning\n      autohide=\"not-last\"\n      className=\"aui-assistant-action-bar-root text-muted-foreground animate-in fade-in col-start-3 row-start-2 -ms-1 flex gap-1 duration-200\"\n    >\n      <ActionBarPrimitive.Copy asChild>\n        <TooltipIconButton tooltip=\"Copy\">\n          <AuiIf condition={(s) => s.message.isCopied}>\n            <CheckIcon className=\"animate-in zoom-in-50 fade-in duration-200 ease-out\" />\n          </AuiIf>\n          <AuiIf condition={(s) => !s.message.isCopied}>\n            <CopyIcon className=\"animate-in zoom-in-75 fade-in duration-150\" />\n          </AuiIf>\n        </TooltipIconButton>\n      </ActionBarPrimitive.Copy>\n      <ActionBarPrimitive.Reload asChild>\n        <TooltipIconButton tooltip=\"Refresh\">\n          <RefreshCwIcon />\n        </TooltipIconButton>\n      </ActionBarPrimitive.Reload>\n      <ActionBarMorePrimitive.Root>\n        <ActionBarMorePrimitive.Trigger asChild>\n          <TooltipIconButton\n            tooltip=\"More\"\n            className=\"data-[state=open]:bg-accent\"\n          >\n            <MoreHorizontalIcon />\n          </TooltipIconButton>\n        </ActionBarMorePrimitive.Trigger>\n        <ActionBarMorePrimitive.Content\n          side=\"bottom\"\n          align=\"start\"\n          sideOffset={6}\n          className=\"aui-action-bar-more-content bg-popover/95 text-popover-foreground data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=closed]:animate-out 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 z-50 min-w-[8rem] overflow-hidden rounded-xl border p-1.5 shadow-lg backdrop-blur-sm\"\n        >\n          <ActionBarPrimitive.ExportMarkdown asChild>\n            <ActionBarMorePrimitive.Item className=\"aui-action-bar-more-item hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground flex cursor-pointer items-center gap-2 rounded-lg px-2.5 py-1.5 text-sm outline-none select-none\">\n              <DownloadIcon className=\"size-4\" />\n              Export as Markdown\n            </ActionBarMorePrimitive.Item>\n          </ActionBarPrimitive.ExportMarkdown>\n        </ActionBarMorePrimitive.Content>\n      </ActionBarMorePrimitive.Root>\n    </ActionBarPrimitive.Root>\n  );\n};\n\nconst UserFilePart: FileMessagePartComponent = (part) => (\n  <div data-slot=\"aui_user-message-file\" className=\"py-1\">\n    <File {...part} />\n  </div>\n);\n\nconst UserImagePart: ImageMessagePartComponent = (part) => (\n  <div data-slot=\"aui_user-message-image\" className=\"py-1\">\n    <Image {...part} />\n  </div>\n);\n\nconst UserMessage: FC = () => {\n  return (\n    <MessagePrimitive.Root\n      data-slot=\"aui_user-message-root\"\n      className=\"fade-in slide-in-from-bottom-1 animate-in grid auto-rows-auto grid-cols-[minmax(72px,1fr)_auto] content-start gap-y-2 px-2 duration-150 [contain-intrinsic-size:auto_200px] [content-visibility:auto] [&:where(>*)]:col-start-2\"\n      data-role=\"user\"\n    >\n      <UserMessageAttachments />\n\n      <div className=\"aui-user-message-content-wrapper relative col-start-2 min-w-0\">\n        <div className=\"aui-user-message-content peer bg-muted text-foreground rounded-xl px-4 py-2 wrap-break-word empty:hidden\">\n          <MessagePrimitive.Parts\n            components={{ File: UserFilePart, Image: UserImagePart }}\n          />\n        </div>\n        <div className=\"aui-user-action-bar-wrapper absolute start-0 top-1/2 -translate-x-full -translate-y-1/2 pe-2 peer-empty:hidden rtl:translate-x-full\">\n          <UserActionBar />\n        </div>\n      </div>\n\n      <BranchPicker\n        data-slot=\"aui_user-branch-picker\"\n        className=\"col-span-full col-start-1 row-start-3 -me-1 justify-end\"\n      />\n    </MessagePrimitive.Root>\n  );\n};\n\nconst UserActionBar: FC = () => {\n  return (\n    <ActionBarPrimitive.Root\n      hideWhenRunning\n      autohide=\"not-last\"\n      className=\"aui-user-action-bar-root flex flex-col items-end\"\n    >\n      <ActionBarPrimitive.Edit asChild>\n        <TooltipIconButton tooltip=\"Edit\" className=\"aui-user-action-edit\">\n          <PencilIcon />\n        </TooltipIconButton>\n      </ActionBarPrimitive.Edit>\n    </ActionBarPrimitive.Root>\n  );\n};\n\nconst EditComposer: FC = () => {\n  return (\n    <MessagePrimitive.Root\n      data-slot=\"aui_edit-composer-wrapper\"\n      className=\"flex flex-col px-2 [contain-intrinsic-size:auto_200px] [content-visibility:auto]\"\n    >\n      <ComposerPrimitive.Root className=\"aui-edit-composer-root border-border/60 dark:border-muted-foreground/15 ms-auto flex w-full max-w-[85%] flex-col rounded-(--composer-radius) border bg-(--composer-bg) shadow-[0_4px_16px_-8px_rgba(0,0,0,0.08),0_1px_2px_rgba(0,0,0,0.04)] dark:shadow-none\">\n        <ComposerPrimitive.Input\n          className=\"aui-edit-composer-input text-foreground min-h-14 w-full resize-none bg-transparent px-4 pt-3 pb-1 text-base outline-none\"\n          autoFocus\n        />\n        <div className=\"aui-edit-composer-footer mx-2.5 mb-2.5 flex items-center gap-1.5 self-end\">\n          <ComposerPrimitive.Cancel asChild>\n            <Button\n              variant=\"ghost\"\n              size=\"sm\"\n              className=\"h-8 rounded-full px-3.5\"\n            >\n              Cancel\n            </Button>\n          </ComposerPrimitive.Cancel>\n          <ComposerPrimitive.Send asChild>\n            <Button size=\"sm\" className=\"h-8 rounded-full px-3.5\">\n              Update\n            </Button>\n          </ComposerPrimitive.Send>\n        </div>\n      </ComposerPrimitive.Root>\n    </MessagePrimitive.Root>\n  );\n};\n\nconst BranchPicker: FC<BranchPickerPrimitive.Root.Props> = ({\n  className,\n  ...rest\n}) => {\n  return (\n    <BranchPickerPrimitive.Root\n      hideWhenSingleBranch\n      className={cn(\n        \"aui-branch-picker-root text-muted-foreground -ms-2 me-2 inline-flex items-center text-xs\",\n        className,\n      )}\n      {...rest}\n    >\n      <BranchPickerPrimitive.Previous asChild>\n        <TooltipIconButton tooltip=\"Previous\">\n          <ChevronLeftIcon />\n        </TooltipIconButton>\n      </BranchPickerPrimitive.Previous>\n      <span className=\"aui-branch-picker-state font-medium\">\n        <BranchPickerPrimitive.Number /> / <BranchPickerPrimitive.Count />\n      </span>\n      <BranchPickerPrimitive.Next asChild>\n        <TooltipIconButton tooltip=\"Next\">\n          <ChevronRightIcon />\n        </TooltipIconButton>\n      </BranchPickerPrimitive.Next>\n    </BranchPickerPrimitive.Root>\n  );\n};\n"
    }
  ]
}