import React, { useCallback } from "react"; import { GraphQLError } from "@copilotkit/runtime-client-gql"; import { useToast } from "../toast/toast-provider"; import { ExclamationMarkIcon } from "../toast/exclamation-mark-icon"; import ReactMarkdown from "react-markdown"; interface OriginalError { message?: string; stack?: string; } export function ErrorToast({ errors }: { errors: (Error | GraphQLError)[] }) { const errorsToRender = errors.map((error, idx) => { const originalError = "extensions" in error ? (error.extensions?.originalError as undefined | OriginalError) : {}; const message = originalError?.message ?? error.message; const code = "extensions" in error ? (error.extensions?.code as string) : null; return (
{code && (
Copilot Runtime Error:{" "} {code}
)} {message}
); }); return (
{errorsToRender}
NOTE: This error only displays during local development.
); } export function useErrorToast() { const { addToast } = useToast(); return useCallback( (errors: (Error | GraphQLError)[]) => { const errorId = errors .map((err) => { const message = "extensions" in err ? (err.extensions?.originalError as any)?.message || err.message : err.message; const stack = err.stack || ""; return btoa(message + stack).slice(0, 32); // Create hash from message + stack }) .join("|"); addToast({ type: "error", id: errorId, // Toast libraries typically dedupe by id message: , }); }, [addToast], ); } export function useAsyncCallback Promise>( callback: T, deps: Parameters[1], ) { const addErrorToast = useErrorToast(); return useCallback(async (...args: Parameters) => { try { return await callback(...args); } catch (error) { console.error("Error in async callback:", error); // @ts-ignore addErrorToast([error]); throw error; } }, deps); }