import { useContext, useEffect, useMemo } from "react"; import { AiContext } from "../context/ai-context"; import { LangGraphInterruptRender } from "../types/interrupt-action"; import { useAiChat } from "./use-ai-chat-internal"; import { useToast } from "../components/toast/toast-provider"; import { dataToUUID } from "@vn-sdk/shared"; export function useLangGraphInterrupt( action: Omit, "id">, dependencies?: any[], ) { const { setLangGraphInterruptAction, removeLangGraphInterruptAction, langGraphInterruptAction, threadId, } = useContext(AiContext); const { runChatCompletion } = useAiChat(); const { addToast } = useToast(); const actionId = dataToUUID(JSON.stringify(action), "lgAction"); // We only consider action to be defined once the ID is there const hasAction = useMemo( () => Boolean(langGraphInterruptAction?.id), [langGraphInterruptAction], ); const isCurrentAction = useMemo( () => langGraphInterruptAction?.id && langGraphInterruptAction?.id === actionId, [langGraphInterruptAction], ); // Run chat completion to submit a response event. Only if it's the current action useEffect(() => { if (hasAction && isCurrentAction && langGraphInterruptAction?.event?.response) { runChatCompletion(); } }, [langGraphInterruptAction?.event?.response, runChatCompletion, hasAction, isCurrentAction]); useEffect(() => { if (!action) return; // An action was already set, with no conditions and it's not the action we're using right now. // Show a warning, as this action will not be executed if (hasAction && !isCurrentAction && !action.enabled) { addToast({ type: "warning", message: "An action is already registered for the interrupt event", }); return; } if (hasAction && isCurrentAction) { return; } setLangGraphInterruptAction(threadId, { ...action, id: actionId }); }, [ action, hasAction, isCurrentAction, setLangGraphInterruptAction, removeLangGraphInterruptAction, threadId, ...(dependencies || []), ]); }