import {
ComposerAddAttachment,
ComposerAttachments,
UserMessageAttachments,
} from "@/components/assistant-ui/attachment";
import { MarkdownText } from "@/components/assistant-ui/markdown-text";
import { ToolFallback } from "@/components/assistant-ui/tool-fallback";
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import {
ActionBarMorePrimitive,
ActionBarPrimitive,
AuiIf,
type AssistantState,
BranchPickerPrimitive,
ComposerPrimitive,
ErrorPrimitive,
MessagePrimitive,
SuggestionPrimitive,
ThreadPrimitive,
useAuiState,
} from "@assistant-ui/react";
import {
ArrowDownIcon,
ArrowUpIcon,
CheckIcon,
ChevronLeftIcon,
ChevronRightIcon,
CopyIcon,
DownloadIcon,
MicIcon,
MoreHorizontalIcon,
PencilIcon,
RefreshCwIcon,
SquareIcon,
} from "lucide-react";
import type { FC } from "react";
// Startup exposes a loading placeholder thread; treat it as a new chat so
// the composer mounts centered. Loads after startup keep the docked layout.
const isNewChatView = (s: AssistantState) =>
s.thread.messages.length === 0 &&
(!s.thread.isLoading || s.threads.isLoading);
export const Thread: FC = () => {
const isEmpty = useAuiState(isNewChatView);
return (
{() => }
isNewChatView(s) && s.composer.isEmpty}>
);
};
const ThreadMessage: FC = () => {
const role = useAuiState((s) => s.message.role);
const isEditing = useAuiState((s) => s.message.composer.isEditing);
if (isEditing) return ;
if (role === "user") return ;
return ;
};
const ThreadScrollToBottom: FC = () => {
return (
);
};
const ThreadWelcome: FC = () => {
return (
How can I help you today?
);
};
const ThreadSuggestions: FC = () => {
return (
{() => }
);
};
const ThreadSuggestionItem: FC = () => {
return (
);
};
const Composer: FC = () => {
return (
);
};
const ComposerAction: FC = () => {
return (
s.thread.capabilities.dictation}>
s.composer.dictation == null}>
s.composer.dictation != null}>
!s.thread.isRunning}>
s.thread.isRunning}>
);
};
const MessageError: FC = () => {
return (
);
};
const AssistantMessage: FC = () => {
const ACTION_BAR_PT = "pt-1.5";
const ACTION_BAR_HEIGHT = `min-h-7.5 ${ACTION_BAR_PT}`;
return (
{({ part }) => {
if (part.type === "text") return ;
if (part.type === "tool-call")
return part.toolUI ?? ;
return null;
}}
s.message.status?.type === "running" && s.message.parts.length === 0
}
>
{"●"}
);
};
const AssistantActionBar: FC = () => {
return (
s.message.isCopied}>
!s.message.isCopied}>
Export as Markdown
);
};
const UserMessage: FC = () => {
return (
);
};
const UserActionBar: FC = () => {
return (
);
};
const EditComposer: FC = () => {
return (
);
};
const BranchPicker: FC = ({
className,
...rest
}) => {
return (
/
);
};