import { memo, useMemo } from "react"; import { Globe } from "lucide-react"; import type { ToolPart } from "../types/parts"; import { PreviewCard, PreviewEmpty, PreviewError, PreviewLoading } from "./preview-primitives"; interface SearchResult { title: string; url: string; snippet?: string; } function coerceString(value: unknown): string | undefined { return typeof value === "string" && value.trim() ? value : undefined; } function extractQuery(input: unknown, output: unknown): string | undefined { if (input && typeof input === "object") { const record = input as Record; const query = coerceString(record.query) ?? coerceString(record.url); if (query) return query; } if (output && typeof output === "object") { const record = output as Record; return coerceString(record.query); } return undefined; } function parseResult(value: unknown): SearchResult | null { if (!value || typeof value !== "object") { return null; } const record = value as Record; const title = coerceString(record.title) ?? coerceString(record.name) ?? "Untitled result"; const url = coerceString(record.url) ?? coerceString(record.link); if (!url) { return null; } return { title, url, snippet: coerceString(record.snippet) ?? coerceString(record.description) ?? coerceString(record.text), }; } function extractResults(output: unknown): SearchResult[] { if (output && typeof output === "object") { const record = output as Record; const candidate = record.results ?? record.items ?? record.output; if (Array.isArray(candidate)) { return candidate.map(parseResult).filter((value): value is SearchResult => value !== null); } } if (Array.isArray(output)) { return output.map(parseResult).filter((value): value is SearchResult => value !== null); } return []; } export interface WebSearchPreviewProps { part: ToolPart; } export const WebSearchPreview = memo(({ part }: WebSearchPreviewProps) => { const query = extractQuery(part.state.input, part.state.output); const results = useMemo(() => extractResults(part.state.output), [part.state.output]); return ( } title={query ? `Web results for ${query}` : "Web results"} description={results.length > 0 ? `${results.length} result${results.length === 1 ? "" : "s"}` : undefined} > {part.state.status === "running" ? : null} {part.state.error ? : null} {part.state.status === "completed" && results.length === 0 ? ( ) : null} ); }); WebSearchPreview.displayName = "WebSearchPreview";