????JFIF??x?x????'
Server IP : 104.21.48.1 / Your IP : 216.73.216.150 Web Server : LiteSpeed System : Linux premium151.web-hosting.com 4.18.0-553.44.1.lve.el8.x86_64 #1 SMP Thu Mar 13 14:29:12 UTC 2025 x86_64 User : tempvsty ( 647) PHP Version : 8.0.30 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /home/./././tempvsty/eaabusiness.com/custom/wp-content/plugins/extendify/src/Agent/ |
Upload File : |
import { useMemo, useEffect, useState, useRef, useCallback, } from '@wordpress/element'; import { Chat } from '@agent/Chat'; import { pickWorkflow, handleWorkflow, callTool, digest } from '@agent/api'; import { ChatInput } from '@agent/components/ChatInput'; import { ChatMessages } from '@agent/components/ChatMessages'; import { ChatSuggestions } from '@agent/components/ChatSuggestions'; import { WelcomeScreen } from '@agent/components/WelcomeScreen'; import { UsageMessage } from '@agent/components/messages/UsageMessage'; import { useChatStore } from '@agent/state/chat'; import { useGlobalStore } from '@agent/state/global'; import { useWorkflowStore } from '@agent/state/workflows'; import { workflows as wfs } from '@agent/workflows/workflows'; const workflows = wfs.filter(({ available }) => available()); const workflowIds = workflows.map((w) => w.id); const devmode = window.extSharedData.devbuild; export const Agent = () => { const { hasMessages, addMessage } = useChatStore(); const { mergeWorkflowData, getWorkflow, workflowData, setWorkflow, addWorkflowResult, setWhenFinishedToolProps, whenFinishedToolProps, } = useWorkflowStore(); const { open, setOpen, showSuggestions, setShowSuggestions, updateRetryAfter, isChatAvailable, } = useGlobalStore(); const [canType, setCanType] = useState(true); const agentWorking = useRef(false); const toolWorking = useRef(false); const [waitingOnToolOrUser, setWaitingOnToolOrUser] = useState(false); const [loop, setLoop] = useState(0); const workflow = getWorkflow(); const chatAvailable = useMemo(() => isChatAvailable(), [isChatAvailable]); const cleanup = useCallback(() => { setCanType(true); agentWorking.current = false; setWaitingOnToolOrUser(false); const c = Array.from( document.querySelectorAll( '#extendify-agent-chat-scroll-area div:last-child', ), )?.at(-1); c?.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); c?.scrollBy({ top: -5, behavior: 'smooth' }); }, []); const findAgent = useCallback( async (options = {}) => { addMessage('status', { type: 'calling-agent' }); const response = await pickWorkflow({ workflows: workflowIds, options, }).catch((error) => { devmode && console.error(error); if (error?.response?.status === 429) { updateRetryAfter(error?.response?.headers?.get('Retry-After')); setCanType(false); addMessage('status', { type: 'credits-exhausted' }); return; } addMessage('status', { type: 'error' }); setCanType(true); return; }); if (!response) return; const { workflow: wf, reply } = response; if (wf?.id) { setWorkflow(wf); const data = { status: 'started', agent: wf.agent }; addMessage('workflow', data); } if (reply) { const data = { role: 'assistant', content: reply, agent: wf?.agent }; addMessage('message', data); } if (!wf?.id) setCanType(true); }, [addMessage, updateRetryAfter, setWorkflow], ); const handleSubmit = useCallback( async (message) => { setShowSuggestions(false); setWaitingOnToolOrUser(false); agentWorking.current = false; addMessage('message', { role: 'user', content: message }); setCanType(false); // If they typed while waiting on a redirect, reset the workflow if (workflow?.needsRedirect?.()) { setWorkflow(null); } if (workflow && !workflow?.needsRedirect?.()) { // reset the workflow to let the effect handle it const wfData = workflowData || {}; setWorkflow({ ...workflow }); mergeWorkflowData(wfData); return; } await findAgent().catch((e) => devmode && console.error(e)); }, [ addMessage, findAgent, mergeWorkflowData, setWorkflow, workflow, workflowData, setShowSuggestions, ], ); // Allow external messages to trigger the agent useEffect(() => { const handleMessage = ({ detail }) => { if (!detail?.message) return; handleSubmit(detail.message); }; window.addEventListener('extendify-agent:chat-submit', handleMessage); return () => window.removeEventListener('extendify-agent:chat-submit', handleMessage); }, [handleSubmit]); // Handle whenFinished component confirm/cancel useEffect(() => { const handleConfirm = async ({ detail }) => { if (toolWorking.current) return; toolWorking.current = true; const { data, whenFinishedToolProps } = detail ?? {}; const { summary, status, whenFinishedTool, answerId } = whenFinishedToolProps.agentResponse; const { id, labels } = whenFinishedTool || {}; // Not all workflows have a tool at the end (e.g. tours) const toolResponse = await callTool?.({ tool: id, inputs: data }).catch( (error) => { const { sessionId } = workflow || {}; digest({ caller: `when-finished: ${id}`, sessionId, error }); devmode && console.error(error); return { error: error.message }; }, ); toolWorking.current = false; // Add the workflow result to the history addWorkflowResult({ answerId, agentName: workflow?.agent?.name, summary, status, errorMsg: toolResponse?.error, }); if (toolResponse?.error) { addMessage('status', { type: 'error' }); setWorkflow(null); cleanup(); return; } addMessage('status', { label: labels?.confirm, type: 'workflow-tool-completed', }); addMessage('workflow', { status: 'completed', agent: workflow.agent, answerId, }); setWorkflow(null); cleanup(); }; const handleCancel = ({ detail }) => { if (toolWorking.current) return; const { summary, whenFinishedTool, answerId } = detail.whenFinishedToolProps.agentResponse; addMessage('workflow', { status: 'canceled', agent: workflow.agent, answerId, }); addWorkflowResult({ answerId, summary, status: 'canceled', agentName: workflow?.agent?.name, }); setWorkflow(null); cleanup(); addMessage('status', { label: whenFinishedTool?.labels?.cancel, type: 'workflow-tool-canceled', }); }; window.addEventListener('extendify-agent:workflow-confirm', handleConfirm); window.addEventListener('extendify-agent:workflow-cancel', handleCancel); return () => { window.removeEventListener( 'extendify-agent:workflow-confirm', handleConfirm, ); window.removeEventListener( 'extendify-agent:workflow-cancel', handleCancel, ); }; }, [addMessage, cleanup, addWorkflowResult, setWorkflow, workflow]); useEffect(() => { const handleClose = () => setOpen(false); const handleOpen = () => setOpen(true); window.addEventListener('extendify-agent:close', handleClose); window.addEventListener('extendify-agent:open', handleOpen); return () => { window.removeEventListener('extendify-agent:close', handleClose); window.removeEventListener('extendify-agent:open', handleOpen); }; }, [setOpen]); useEffect(() => { if (waitingOnToolOrUser || !open || !workflow?.id) return; // Some workflows require they dont change pages const theyMoved = workflow?.startingPage !== window.location.href; if (workflow?.cancelOnPageChange && theyMoved) { addMessage('workflow', { status: 'canceled', agent: workflow.agent }); setWorkflow(null); cleanup(); return; } // A component is running if (whenFinishedToolProps?.id) return; // They must be on a page where they can do work if (workflow?.needsRedirect?.()) { cleanup(); return; } (async () => { if (agentWorking.current) return; // Prevent multiple calls setCanType(false); setShowSuggestions(false); agentWorking.current = true; addMessage('status', { type: 'agent-working' }); const agentResponse = await handleWorkflow({ workflow: workflow, workflowData, }).catch((error) => { const { sessionId } = workflow || {}; digest({ caller: 'handle-workflow', sessionId, error }); devmode && console.error(error); return { error: error.message }; }); const { summary, status, answerId } = agentResponse; // Add the workflow result to the history addWorkflowResult({ answerId, summary, status, errorMsg: agentResponse?.error, agentName: workflow?.agent?.name, }); if (!open) return; if (agentResponse.error) { // mutate the window to add failed tools rather than keep state window.extAgentData.failedWorkflows = window.extAgentData.failedWorkflows || new Set(); window.extAgentData.failedWorkflows.add(workflow.id); throw new Error(`Error handling workflow: ${agentResponse.error}`); } // The ai sent back some text to show to the user if (agentResponse.reply) { addMessage('message', { role: 'assistant', content: agentResponse.reply, followup: !!agentResponse.tool, pageSuggestion: agentResponse.pageSuggestion, agent: workflow.agent, }); } // This is at the end of the workflow // and we are about to execute the final tool if (agentResponse.whenFinishedTool?.id) { setWhenFinishedToolProps({ ...agentResponse.whenFinishedTool, agentResponse, }); // If static, add it as a message const { id, inputs, static: staticC } = agentResponse.whenFinishedTool; if (staticC) { addMessage('workflow-component', { id, status: 'completed', inputs }); setWorkflow(null); addMessage('workflow', { status: 'completed', agent: workflow.agent, answerId, }); cleanup(); } return; } // Agent thinks it needs to handoff to another agent if (agentResponse.status === 'handoff') { const currentWorkflowId = workflow.id; setWorkflow(null); cleanup(); addMessage('workflow', { status: 'handoff', answerId }); await new Promise((resolve) => setTimeout(resolve, 1000)); await findAgent({ handoff: currentWorkflowId }); return; } // If we're done, it means the AI has the answer if (agentResponse.status === 'completed') { setWorkflow(null); cleanup(); addMessage('workflow', { status: 'completed', agent: workflow.agent, answerId, }); return; } if (agentResponse.status === 'canceled') { setWorkflow(null); cleanup(); addMessage('workflow', { status: 'canceled', agent: workflow.agent, answerId, }); return; } // These inputs are filled out by the AI mergeWorkflowData(agentResponse.inputs); // Agent needs more info from a if (agentResponse.tool) { const { id, inputs, labels } = agentResponse.tool; addMessage('status', { label: labels?.started, type: 'tool-started' }); const toolData = await Promise.all([ callTool({ tool: id, inputs }), new Promise((resolve) => setTimeout(resolve, 3000)), ]) .then(([data]) => data) .catch((error) => { const { sessionId } = workflow || {}; digest({ caller: `in-progress: ${id}`, sessionId, error }); devmode && console.error(error); throw error; }); addMessage('status', { label: labels?.confirm, type: 'tool-completed', }); await new Promise((resolve) => setTimeout(resolve, 1000)); mergeWorkflowData(toolData); setWaitingOnToolOrUser(false); agentWorking.current = false; setLoop((prev) => prev + 1); // Trigger next loop return; } setCanType(true); setWaitingOnToolOrUser(true); })().catch((error) => { const { sessionId } = workflow || {}; digest({ caller: 'main-loop', sessionId, error }); devmode && console.error(error); setWorkflow(null); cleanup(); addMessage('status', { type: 'error' }); }); }, [ loop, cleanup, addWorkflowResult, open, workflow, workflowData, addMessage, setWorkflow, agentWorking, waitingOnToolOrUser, mergeWorkflowData, canType, findAgent, setShowSuggestions, whenFinishedToolProps, setWhenFinishedToolProps, ]); useEffect(() => { if (!canType) return; document.querySelector('#extendify-agent-chat-textarea')?.focus(); }, [canType]); const showWelcomeScreen = !hasMessages(); const showPromptSuggestions = !workflow?.id && !showWelcomeScreen && chatAvailable && showSuggestions; return ( <Chat> <div className="relative z-50 flex h-full flex-col overflow-auto border-t border-solid border-gray-300"> {showWelcomeScreen ? ( <div className="h-full" style={{ backgroundImage: 'linear-gradient( to bottom, #f0f0f0 0%, #fff 60%, #fff 100%)', }}> <WelcomeScreen /> </div> ) : ( <ChatMessages redirectComponent={ workflow?.needsRedirect?.() ? workflow.redirectComponent : null } /> )} <div> <div className="relative flex flex-col px-2.5 pb-2 pt-2.5 shadow-lg-flipped"> <ChatSuggestions show={showPromptSuggestions} /> <UsageMessage onReady={() => { cleanup(); setShowSuggestions(true); addMessage('status', { type: 'credits-restored' }); }} /> </div> <ChatInput disabled={!canType || !chatAvailable} handleSubmit={handleSubmit} /> </div> </div> </Chat> ); };