"use client"; import { makeAssistantToolUI } from "@assistant-ui/react"; import { CornerDownLeftIcon, TriangleAlertIcon } from "lucide-react"; import { useCallback, useEffect, useState } from "react"; import { Button } from "@/components/ui/button"; import { Spinner } from "@/components/ui/spinner"; interface InterruptResult { __interrupt__: true; __decided__?: "approve" | "reject"; action_requests: Array<{ name: string; args: Record; description?: string; }>; review_configs: Array<{ action_name: string; allowed_decisions: Array<"approve" | "reject">; }>; interrupt_type?: string; message?: string; context?: { account?: { id: number; name: string; workspace_id: string | null; workspace_name: string; workspace_icon: string; }; page_id?: string; current_title?: string; document_id?: number; indexed_at?: string; error?: string; }; } interface SuccessResult { status: "success"; page_id: string; title?: string; message?: string; deleted_from_kb?: boolean; } interface ErrorResult { status: "error"; message: string; } interface InfoResult { status: "not_found"; message: string; } interface WarningResult { status: "success"; warning: string; page_id?: string; title?: string; message?: string; } interface AuthErrorResult { status: "auth_error"; message: string; connector_id?: number; connector_type: string; } type DeleteNotionPageResult = | InterruptResult | SuccessResult | ErrorResult | InfoResult | WarningResult | AuthErrorResult; 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 isInfoResult(result: unknown): result is InfoResult { return ( typeof result === "object" && result !== null && "status" in result && (result as InfoResult).status === "not_found" ); } function isAuthErrorResult(result: unknown): result is AuthErrorResult { return ( typeof result === "object" && result !== null && "status" in result && (result as AuthErrorResult).status === "auth_error" ); } function isWarningResult(result: unknown): result is WarningResult { return ( typeof result === "object" && result !== null && "status" in result && (result as WarningResult).status === "success" && "warning" in result && typeof (result as WarningResult).warning === "string" ); } 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 [deleteFromKb, setDeleteFromKb] = useState(false); const account = interruptData.context?.account; const currentTitle = interruptData.context?.current_title; const handleApprove = useCallback(() => { if (decided) return; setDecided("approve"); onDecision({ type: "approve", edited_action: { name: interruptData.action_requests[0].name, args: { page_id: interruptData.context?.page_id, connector_id: account?.id, delete_from_kb: deleteFromKb, }, }, }); }, [decided, onDecision, interruptData, account?.id, deleteFromKb]); useEffect(() => { const handler = (e: KeyboardEvent) => { if (e.key === "Enter" && !e.shiftKey && !e.ctrlKey && !e.metaKey) { handleApprove(); } }; window.addEventListener("keydown", handler); return () => window.removeEventListener("keydown", handler); }, [handleApprove]); return (
{/* Header */}

{decided === "reject" ? "Notion Page Deletion Rejected" : decided === "approve" ? "Notion Page Deletion Approved" : "Delete Notion Page"}

{decided === "reject" ? "Page deletion was cancelled" : decided === "approve" ? "Page deletion is in progress" : "Requires your approval to proceed"}

{/* Context section — read-only account and page info */} {!decided && interruptData.context && ( <>
{interruptData.context.error ? (

{interruptData.context.error}

) : ( <> {account && (

Notion Account

{account.workspace_icon} {account.workspace_name}
)} {currentTitle && (

Page to Delete

📄 {currentTitle}
)} )}
)} {/* delete_from_kb toggle */} {!decided && ( <>
)} {/* Action buttons - only shown when pending */} {!decided && ( <>
)}
); } function AuthErrorCard({ result }: { result: AuthErrorResult }) { return (

Notion authentication expired

{result.message}

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

Failed to delete Notion page

{result.message}

); } function InfoCard({ result }: { result: InfoResult }) { return (

Page not found

{result.message}

); } function WarningCard({ result }: { result: WarningResult }) { return (

Partial success

{result.warning}

{result.title && (
Deleted page: {result.title}
)}
); } function SuccessCard({ result }: { result: SuccessResult }) { return (

{result.message || "Notion page deleted successfully"}

{(result.deleted_from_kb || result.title) && ( <>
{result.title && (
Deleted page: {result.title}
)} {result.deleted_from_kb && (
Also removed from knowledge base
)}
)}
); } export const DeleteNotionPageToolUI = makeAssistantToolUI< { page_title: string; delete_from_kb?: boolean }, DeleteNotionPageResult >({ toolName: "delete_notion_page", render: function DeleteNotionPageUI({ result, status }) { if (status.type === "running") { return (

Deleting Notion page...

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