refactor: remove frontend of scrape_webpage tool

This commit is contained in:
Anish Sarkar 2026-03-24 18:55:06 +05:30
parent a009cae62a
commit 3f4e1a7dfd
9 changed files with 118 additions and 655 deletions

View file

@ -29,7 +29,6 @@ import { CreateJiraIssueToolUI, DeleteJiraIssueToolUI, UpdateJiraIssueToolUI } f
import { CreateLinearIssueToolUI, DeleteLinearIssueToolUI, UpdateLinearIssueToolUI } from "@/components/tool-ui/linear";
import { CreateNotionPageToolUI, DeleteNotionPageToolUI, UpdateNotionPageToolUI } from "@/components/tool-ui/notion";
import { SandboxExecuteToolUI } from "@/components/tool-ui/sandbox-execute";
import { ScrapeWebpageToolUI } from "@/components/tool-ui/scrape-webpage";
import { RecallMemoryToolUI, SaveMemoryToolUI } from "@/components/tool-ui/user-memory";
import { useComments } from "@/hooks/use-comments";
import { useMediaQuery } from "@/hooks/use-media-query";
@ -59,7 +58,6 @@ const AssistantMessageInner: FC = () => {
generate_video_presentation: GenerateVideoPresentationToolUI,
display_image: DisplayImageToolUI,
generate_image: GenerateImageToolUI,
scrape_webpage: ScrapeWebpageToolUI,
save_memory: SaveMemoryToolUI,
recall_memory: RecallMemoryToolUI,
execute: SandboxExecuteToolUI,

View file

@ -1,8 +1,14 @@
import type { ToolCallMessagePartComponent } from "@assistant-ui/react";
import { CheckIcon, ChevronDownIcon, ChevronUpIcon, XCircleIcon } from "lucide-react";
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { getToolIcon } from "@/contracts/enums/toolIcons";
function formatToolName(name: string): string {
return name
.replace(/_/g, " ")
.replace(/\b\w/g, (c) => c.toUpperCase());
}
export const ToolFallback: ToolCallMessagePartComponent = ({
toolName,
@ -10,66 +16,127 @@ export const ToolFallback: ToolCallMessagePartComponent = ({
result,
status,
}) => {
const [isCollapsed, setIsCollapsed] = useState(true);
const [isExpanded, setIsExpanded] = useState(false);
const isCancelled = status?.type === "incomplete" && status.reason === "cancelled";
const isError = status?.type === "incomplete" && status.reason === "error";
const isRunning = status?.type === "running" || status?.type === "requires-action";
const cancelledReason =
isCancelled && status.error
? typeof status.error === "string"
? status.error
: JSON.stringify(status.error)
: null;
const errorReason =
isError && status.error
? typeof status.error === "string"
? status.error
: JSON.stringify(status.error)
: null;
const Icon = getToolIcon(toolName);
const displayName = formatToolName(toolName);
return (
<div
className={cn(
"aui-tool-fallback-root mb-4 flex w-full flex-col gap-3 rounded-lg border py-3",
isCancelled && "border-muted-foreground/30 bg-muted/30"
"my-4 max-w-lg overflow-hidden rounded-2xl border bg-muted/30 select-none",
isCancelled && "opacity-60",
isError && "border-destructive/20 bg-destructive/5",
)}
>
<div className="aui-tool-fallback-header flex items-center gap-2 px-4">
{isCancelled ? (
<XCircleIcon className="aui-tool-fallback-icon size-4 text-muted-foreground" />
) : (
<CheckIcon className="aui-tool-fallback-icon size-4" />
)}
<p
<button
type="button"
onClick={() => setIsExpanded(!isExpanded)}
className="flex w-full items-center gap-3 px-5 py-4 text-left transition-colors hover:bg-muted/50 focus:outline-none focus-visible:outline-none"
>
<div
className={cn(
"aui-tool-fallback-title grow",
isCancelled && "text-muted-foreground line-through"
"flex size-8 shrink-0 items-center justify-center rounded-lg",
isError
? "bg-destructive/10"
: isCancelled
? "bg-muted"
: "bg-primary/10",
)}
>
{isCancelled ? "Cancelled tool: " : "Used tool: "}
<b>{toolName}</b>
</p>
<Button onClick={() => setIsCollapsed(!isCollapsed)}>
{isCollapsed ? <ChevronUpIcon /> : <ChevronDownIcon />}
</Button>
</div>
{!isCollapsed && (
<div className="aui-tool-fallback-content flex flex-col gap-2 border-t pt-2">
{cancelledReason && (
<div className="aui-tool-fallback-cancelled-root px-4">
<p className="aui-tool-fallback-cancelled-header font-semibold text-muted-foreground">
Cancelled reason:
</p>
<p className="aui-tool-fallback-cancelled-reason text-muted-foreground">
{cancelledReason}
</p>
</div>
)}
<div className={cn("aui-tool-fallback-args-root px-4", isCancelled && "opacity-60")}>
<pre className="aui-tool-fallback-args-value whitespace-pre-wrap">{argsText}</pre>
</div>
{!isCancelled && result !== undefined && (
<div className="aui-tool-fallback-result-root border-t border-dashed px-4 pt-2">
<p className="aui-tool-fallback-result-header font-semibold">Result:</p>
<pre className="aui-tool-fallback-result-content whitespace-pre-wrap">
{typeof result === "string" ? result : JSON.stringify(result, null, 2)}
</pre>
</div>
{isError ? (
<XCircleIcon className="size-4 text-destructive" />
) : isCancelled ? (
<XCircleIcon className="size-4 text-muted-foreground" />
) : isRunning ? (
<Icon className="size-4 text-primary animate-pulse" />
) : (
<CheckIcon className="size-4 text-primary" />
)}
</div>
<div className="flex-1 min-w-0">
<p
className={cn(
"text-sm font-semibold",
isError
? "text-destructive"
: isCancelled
? "text-muted-foreground line-through"
: "text-foreground",
)}
>
{isRunning
? displayName
: isCancelled
? `Cancelled: ${displayName}`
: isError
? `Failed: ${displayName}`
: displayName}
</p>
{isRunning && (
<p className="text-xs text-muted-foreground mt-0.5">Running...</p>
)}
{cancelledReason && (
<p className="text-xs text-muted-foreground mt-0.5 truncate">{cancelledReason}</p>
)}
{errorReason && (
<p className="text-xs text-destructive/80 mt-0.5 truncate">{errorReason}</p>
)}
</div>
{!isRunning && (
<div className="shrink-0 text-muted-foreground">
{isExpanded ? (
<ChevronDownIcon className="size-4" />
) : (
<ChevronUpIcon className="size-4" />
)}
</div>
)}
</button>
{isExpanded && !isRunning && (
<>
<div className="mx-5 h-px bg-border/50" />
<div className="px-5 py-3 space-y-3">
{argsText && (
<div>
<p className="text-xs font-medium text-muted-foreground mb-1">Arguments</p>
<pre className="text-xs text-foreground/80 whitespace-pre-wrap break-all">
{argsText}
</pre>
</div>
)}
{!isCancelled && result !== undefined && (
<>
<div className="h-px bg-border/30" />
<div>
<p className="text-xs font-medium text-muted-foreground mb-1">Result</p>
<pre className="text-xs text-foreground/80 whitespace-pre-wrap break-all">
{typeof result === "string" ? result : JSON.stringify(result, null, 2)}
</pre>
</div>
</>
)}
</div>
</>
)}
</div>
);