"use client";
import { makeAssistantToolUI } from "@assistant-ui/react";
import { AlertCircleIcon, ExternalLinkIcon, LinkIcon } from "lucide-react";
import {
MediaCard,
MediaCardErrorBoundary,
MediaCardLoading,
parseSerializableMediaCard,
type SerializableMediaCard,
} from "@/components/tool-ui/media-card";
/**
* Type definitions for the link_preview tool
*/
interface LinkPreviewArgs {
url: string;
title?: string;
}
interface LinkPreviewResult {
id: string;
assetId: string;
kind: "link";
href: string;
title: string;
description?: string;
thumb?: string;
domain?: string;
error?: string;
}
/**
* Error state component shown when link preview fails
*/
function LinkPreviewErrorState({ url, error }: { url: string; error: string }) {
return (
Failed to load preview
{url}
{error}
);
}
/**
* Cancelled state component
*/
function LinkPreviewCancelledState({ url }: { url: string }) {
return (
);
}
/**
* Parsed MediaCard component with error handling
*/
function ParsedMediaCard({ result }: { result: unknown }) {
const card = parseSerializableMediaCard(result);
return (
{
if (id === "open" && card.href) {
window.open(card.href, "_blank", "noopener,noreferrer");
}
}}
/>
);
}
/**
* Link Preview Tool UI Component
*
* This component is registered with assistant-ui to render a rich
* link preview card when the link_preview tool is called by the agent.
*
* It displays website metadata including:
* - Title and description
* - Thumbnail/Open Graph image
* - Domain name
* - Clickable link to open in new tab
*/
export const LinkPreviewToolUI = makeAssistantToolUI({
toolName: "link_preview",
render: function LinkPreviewUI({ args, result, status }) {
const url = args.url || "Unknown URL";
// Loading state - tool is still running
if (status.type === "running" || status.type === "requires-action") {
return (
);
}
// Incomplete/cancelled state
if (status.type === "incomplete") {
if (status.reason === "cancelled") {
return ;
}
if (status.reason === "error") {
return (
);
}
}
// No result yet
if (!result) {
return (
);
}
// Error result from the tool
if (result.error) {
return ;
}
// Success - render the media card
return (
);
},
});
/**
* Multiple Link Previews Tool UI Component
*
* This component handles cases where multiple links need to be previewed.
* It renders a grid of link preview cards.
*/
interface MultiLinkPreviewArgs {
urls: string[];
}
interface MultiLinkPreviewResult {
previews: LinkPreviewResult[];
errors?: { url: string; error: string }[];
}
export const MultiLinkPreviewToolUI = makeAssistantToolUI<
MultiLinkPreviewArgs,
MultiLinkPreviewResult
>({
toolName: "multi_link_preview",
render: function MultiLinkPreviewUI({ args, result, status }) {
const urls = args.urls || [];
// Loading state
if (status.type === "running" || status.type === "requires-action") {
return (
{urls.slice(0, 4).map((url, index) => (
))}
);
}
// Incomplete state
if (status.type === "incomplete") {
return (
);
}
// No result
if (!result || !result.previews) {
return null;
}
// Render grid of previews
return (
{result.previews.map((preview) => (
))}
{result.errors?.map((err) => (
))}
);
},
});
export type { LinkPreviewArgs, LinkPreviewResult, MultiLinkPreviewArgs, MultiLinkPreviewResult };