"use client"; import { makeAssistantToolUI } from "@assistant-ui/react"; import { AlertTriangleIcon, CheckIcon, InfoIcon, Loader2Icon, Trash2Icon, XIcon, } from "lucide-react"; import { useState } from "react"; import { Button } from "@/components/ui/button"; interface GoogleDriveAccount { id: number; name: string; } interface GoogleDriveFile { file_id: string; name: string; mime_type: string; web_view_link: string; } interface InterruptResult { __interrupt__: true; __decided__?: "approve" | "reject"; action_requests: Array<{ name: string; args: Record; }>; review_configs: Array<{ action_name: string; allowed_decisions: Array<"approve" | "reject">; }>; context?: { account?: GoogleDriveAccount; file?: GoogleDriveFile; error?: string; }; } interface SuccessResult { status: "success"; file_id: string; message?: string; } interface ErrorResult { status: "error"; message: string; } interface NotFoundResult { status: "not_found"; message: string; } type TrashGoogleDriveFileResult = | InterruptResult | SuccessResult | ErrorResult | NotFoundResult; function isInterruptResult(result: unknown): result is InterruptResult { return ( typeof result === "object" && result !== null && "__interrupt__" in result && (result as InterruptResult).__interrupt__ === true ); } function isErrorResult(result: unknown): result is ErrorResult { return ( typeof result === "object" && result !== null && "status" in result && (result as ErrorResult).status === "error" ); } function isNotFoundResult(result: unknown): result is NotFoundResult { return ( typeof result === "object" && result !== null && "status" in result && (result as NotFoundResult).status === "not_found" ); } const MIME_TYPE_LABELS: Record = { "application/vnd.google-apps.document": "Google Doc", "application/vnd.google-apps.spreadsheet": "Google Sheet", "application/vnd.google-apps.presentation": "Google Slides", }; function ApprovalCard({ interruptData, onDecision, }: { interruptData: InterruptResult; onDecision: (decision: { type: "approve" | "reject"; message?: string; edited_action?: { name: string; args: Record }; }) => void; }) { const [decided, setDecided] = useState<"approve" | "reject" | null>( interruptData.__decided__ ?? null ); const account = interruptData.context?.account; const file = interruptData.context?.file; const fileLabel = file?.mime_type ? (MIME_TYPE_LABELS[file.mime_type] ?? "File") : "File"; return (
{/* Header */}

Trash Google Drive File

Requires your approval to proceed

{/* Context — read-only file details */} {!decided && interruptData.context && (
{interruptData.context.error ? (

{interruptData.context.error}

) : ( <> {account && (
Google Drive Account
{account.name}
)} {file && (
File to Trash
{file.name}
{fileLabel}
{file.web_view_link && ( Open in Drive )}
)} )}
)} {/* Trash warning */} {!decided && (

⚠️ The file will be moved to Google Drive trash. You can restore it from trash within 30 days.

)} {/* Action buttons */}
{decided ? (

{decided === "approve" ? ( <> Approved ) : ( <> Rejected )}

) : ( <> )}
); } function ErrorCard({ result }: { result: ErrorResult }) { return (

Failed to trash file

{result.message}

); } function NotFoundCard({ result }: { result: NotFoundResult }) { return (

{result.message}

); } function SuccessCard({ result }: { result: SuccessResult }) { return (

{result.message || "File moved to trash successfully"}

); } export const TrashGoogleDriveFileToolUI = makeAssistantToolUI< { file_name: string }, TrashGoogleDriveFileResult >({ toolName: "trash_google_drive_file", render: function TrashGoogleDriveFileUI({ result, status }) { if (status.type === "running") { return (

Looking up file in Google Drive...

); } if (!result) return null; if (isInterruptResult(result)) { return ( { window.dispatchEvent( new CustomEvent("hitl-decision", { detail: { decisions: [decision] } }) ); }} /> ); } if ( typeof result === "object" && result !== null && "status" in result && (result as { status: string }).status === "rejected" ) { return null; } if (isNotFoundResult(result)) return ; if (isErrorResult(result)) return ; return ; }, });