"use client"; import { makeAssistantToolUI } from "@assistant-ui/react"; import { AlertCircleIcon, FileTextIcon } from "lucide-react"; import { z } from "zod"; import { Article, ArticleErrorBoundary, ArticleLoading, parseSerializableArticle, } from "@/components/tool-ui/article"; // ============================================================================ // Zod Schemas // ============================================================================ /** * Schema for scrape_webpage tool arguments */ const ScrapeWebpageArgsSchema = z.object({ url: z.string(), max_length: z.number().nullish(), }); /** * Schema for scrape_webpage tool result */ const ScrapeWebpageResultSchema = z.object({ id: z.string(), assetId: z.string(), kind: z.literal("article"), href: z.string(), title: z.string(), description: z.string().nullish(), content: z.string().nullish(), domain: z.string().nullish(), author: z.string().nullish(), date: z.string().nullish(), word_count: z.number().nullish(), was_truncated: z.boolean().nullish(), crawler_type: z.string().nullish(), error: z.string().nullish(), }); // ============================================================================ // Types // ============================================================================ type ScrapeWebpageArgs = z.infer; type ScrapeWebpageResult = z.infer; /** * Error state component shown when webpage scraping fails */ function ScrapeErrorState({ url, error }: { url: string; error: string }) { return (

Failed to scrape webpage

{url}

{error}

); } /** * Cancelled state component */ function ScrapeCancelledState({ url }: { url: string }) { return (

Scraping: {url}

); } /** * Parsed Article component with error handling */ function ParsedArticle({ result }: { result: unknown }) { const { description, ...article } = parseSerializableArticle(result); return
; } /** * Scrape Webpage Tool UI Component * * This component is registered with assistant-ui to render an article card * when the scrape_webpage tool is called by the agent. * * It displays scraped webpage content including: * - Title and description * - Author and date (if available) * - Word count * - Link to original source */ export const ScrapeWebpageToolUI = makeAssistantToolUI({ toolName: "scrape_webpage", render: function ScrapeWebpageUI({ 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 article card return (
); }, }); export { ScrapeWebpageArgsSchema, ScrapeWebpageResultSchema, type ScrapeWebpageArgs, type ScrapeWebpageResult, };