import { useEffect } from 'react'; import { Search, X } from 'lucide-react'; import { useFormContext } from 'react-hook-form'; import { isAgentsEndpoint } from 'librechat-data-provider'; import { Dialog, DialogPanel, DialogTitle, Description } from '@headlessui/react'; import { useUpdateUserPluginsMutation } from 'librechat-data-provider/react-query'; import type { AssistantsEndpoint, EModelEndpoint, TPluginAction, TPlugin, TError, } from 'librechat-data-provider'; import type { AgentForm, TPluginStoreDialogProps } from '~/common'; import { PluginPagination, PluginAuthForm } from '~/components/Plugins/Store'; import { useAgentPanelContext } from '~/Providers/AgentPanelContext'; import { useLocalize, usePluginDialogHelpers } from '~/hooks'; import ToolItem from './ToolItem'; function ToolSelectDialog({ isOpen, endpoint, setIsOpen, }: TPluginStoreDialogProps & { endpoint: AssistantsEndpoint | EModelEndpoint.agents; }) { const localize = useLocalize(); const isAgentTools = isAgentsEndpoint(endpoint); const { getValues, setValue } = useFormContext(); // Only use regular tools, not MCP tools const { regularTools } = useAgentPanelContext(); const { maxPage, setMaxPage, currentPage, setCurrentPage, itemsPerPage, searchChanged, setSearchChanged, searchValue, setSearchValue, gridRef, handleSearch, handleChangePage, error, setError, errorMessage, setErrorMessage, showPluginAuthForm, setShowPluginAuthForm, selectedPlugin, setSelectedPlugin, } = usePluginDialogHelpers(); const updateUserPlugins = useUpdateUserPluginsMutation(); const handleInstallError = (error: TError) => { setError(true); const errorMessage = error.response?.data?.message ?? ''; if (errorMessage) { setErrorMessage(errorMessage); } setTimeout(() => { setError(false); setErrorMessage(''); }, 5000); }; const handleInstall = (pluginAction: TPluginAction) => { const addFunction = () => { const installedToolIds: string[] = getValues('tools') || []; installedToolIds.push(pluginAction.pluginKey); setValue('tools', Array.from(new Set(installedToolIds))); }; if (!pluginAction.auth) { return addFunction(); } updateUserPlugins.mutate(pluginAction, { onError: (error: unknown) => { handleInstallError(error as TError); }, onSuccess: addFunction, }); setShowPluginAuthForm(false); }; const onRemoveTool = (toolId: string) => { updateUserPlugins.mutate( { pluginKey: toolId, action: 'uninstall', auth: {}, isEntityTool: true }, { onError: (error: unknown) => handleInstallError(error as TError), onSuccess: () => { const remainingToolIds = getValues('tools')?.filter((id) => id !== toolId) || []; setValue('tools', remainingToolIds); }, }, ); }; const onAddTool = (pluginKey: string) => { setShowPluginAuthForm(false); // Find the tool in regularTools const availablePluginFromKey = regularTools?.find((p) => p.pluginKey === pluginKey); setSelectedPlugin(availablePluginFromKey); const { authConfig, authenticated = false } = availablePluginFromKey ?? {}; if (authConfig && authConfig.length > 0 && !authenticated) { setShowPluginAuthForm(true); } else { handleInstall({ pluginKey, action: 'install', auth: {}, }); } }; const filteredTools = (regularTools || []).filter((tool: TPlugin) => { return tool.name?.toLowerCase().includes(searchValue.toLowerCase()); }); useEffect(() => { if (filteredTools) { setMaxPage(Math.ceil(filteredTools.length / itemsPerPage)); if (searchChanged) { setCurrentPage(1); setSearchChanged(false); } } }, [ searchValue, itemsPerPage, filteredTools, searchChanged, setMaxPage, setCurrentPage, setSearchChanged, ]); return ( { setIsOpen(false); setCurrentPage(1); setSearchValue(''); }} className="relative z-[102]" > {/* The backdrop, rendered as a fixed sibling to the panel container */}
{/* Full-screen container to center the panel */}
{isAgentTools ? localize('com_nav_tool_dialog_agents') : localize('com_nav_tool_dialog')} {localize('com_nav_tool_dialog_description')}
{error && (
{localize('com_nav_plugin_auth_error')} {errorMessage}
)} {showPluginAuthForm && (
handleInstall(installActionData)} isEntityTool={true} />
)}
{filteredTools && filteredTools .slice((currentPage - 1) * itemsPerPage, currentPage * itemsPerPage) .map((tool, index) => ( onAddTool(tool.pluginKey)} onRemoveTool={() => onRemoveTool(tool.pluginKey)} /> ))}
{maxPage > 0 ? ( ) : (
)}
); } export default ToolSelectDialog;