mirror of
https://github.com/vercel/ai-elements.git
synced 2026-09-14 19:48:26 +08:00
30cbcfec97
* Migrate to oxlint / oxfmt * Initial fixes * Misc fixes * Temporary fixes * Update Ultracite * Update .oxlintrc.json * Update .oxlintrc.json * Start running manual fixes * Update .oxlintrc.json * AI Fixes Part 2 * AI Fixes Part 3 * AI Fixes Part 4 * AI Fixes Part 5 * AI Fixes Part 6 * AI Fixes Part 7 * AI Fixes Part 8 * AI Fixes Part 9 * AI Fixes Part 10 * AI Fixes Part 11 * AI Fixes Part 12 * Fix tests * Lint / test fixes * Update chat.tsx * Fix AI SDK React version * Misc fixes * Build fixes
75 lines
1.9 KiB
TypeScript
75 lines
1.9 KiB
TypeScript
import { Shimmer } from "@repo/elements/shimmer";
|
|
import {
|
|
Source,
|
|
Sources,
|
|
SourcesContent,
|
|
SourcesTrigger,
|
|
} from "@repo/elements/sources";
|
|
import { isToolUIPart } from "ai";
|
|
import { BookmarkIcon } from "lucide-react";
|
|
|
|
import type { MyUIMessage } from "@/app/api/chat/types";
|
|
|
|
interface MessageMetadataProps {
|
|
parts: MyUIMessage["parts"];
|
|
inProgress: boolean;
|
|
}
|
|
|
|
export const MessageMetadata = ({
|
|
parts,
|
|
inProgress,
|
|
}: MessageMetadataProps) => {
|
|
// Pull out last part that is either text or tool call
|
|
const lastPart = parts
|
|
.filter((part) => part.type === "text" || isToolUIPart(part))
|
|
.at(-1);
|
|
|
|
if (!lastPart) {
|
|
return <Shimmer className="text-xs">Thinking...</Shimmer>;
|
|
}
|
|
|
|
const tool = isToolUIPart(lastPart) ? lastPart : null;
|
|
const hasTextPart = parts.some((part) => part.type === "text");
|
|
|
|
const sources = [
|
|
...new Map(
|
|
parts
|
|
.filter((part) => part.type === "source-url")
|
|
.map((part) => [part.url, part])
|
|
).values(),
|
|
];
|
|
|
|
// Show loading state when sources exist but text hasn't arrived yet
|
|
if (sources.length > 0 && !hasTextPart && inProgress) {
|
|
return <Shimmer className="text-xs">Searching sources...</Shimmer>;
|
|
}
|
|
|
|
if (sources.length > 0 && !(tool && inProgress)) {
|
|
return (
|
|
<Sources>
|
|
<SourcesTrigger count={sources.length}>
|
|
<BookmarkIcon className="size-4" />
|
|
<p>Used {sources.length} sources</p>
|
|
</SourcesTrigger>
|
|
<SourcesContent>
|
|
<ul className="flex flex-col gap-2">
|
|
{sources.map((source) => (
|
|
<li className="ml-4.5 list-disc pl-1" key={source.url}>
|
|
<Source href={source.url} title={source.url}>
|
|
{source.title}
|
|
</Source>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</SourcesContent>
|
|
</Sources>
|
|
);
|
|
}
|
|
|
|
if (!tool && sources.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
return <div className="h-12" />;
|
|
};
|