import React, { useRef, useState, useMemo } from 'react'; import * as Ariakit from '@ariakit/react'; import { useRecoilState } from 'recoil'; import { FileSearch, ImageUpIcon, TerminalSquareIcon, FileType2Icon } from 'lucide-react'; import { EToolResources, EModelEndpoint, defaultAgentCapabilities } from 'librechat-data-provider'; import { FileUpload, TooltipAnchor, DropdownPopup, AttachmentIcon, SharePointIcon, } from '@librechat/client'; import type { EndpointFileConfig } from 'librechat-data-provider'; import { useAgentToolPermissions, useAgentCapabilities, useGetAgentsConfig, useFileHandling, useLocalize, } from '~/hooks'; import useSharePointFileHandling from '~/hooks/Files/useSharePointFileHandling'; import { SharePointPickerDialog } from '~/components/SharePoint'; import { useGetStartupConfig } from '~/data-provider'; import { ephemeralAgentByConvoId } from '~/store'; import { MenuItemProps } from '~/common'; import { cn } from '~/utils'; interface AttachFileMenuProps { conversationId: string; agentId?: string | null; disabled?: boolean | null; endpointFileConfig?: EndpointFileConfig; } const AttachFileMenu = ({ agentId, disabled, conversationId, endpointFileConfig, }: AttachFileMenuProps) => { const localize = useLocalize(); const isUploadDisabled = disabled ?? false; const inputRef = useRef(null); const [isPopoverActive, setIsPopoverActive] = useState(false); const [ephemeralAgent, setEphemeralAgent] = useRecoilState( ephemeralAgentByConvoId(conversationId), ); const [toolResource, setToolResource] = useState(); const { handleFileChange } = useFileHandling({ overrideEndpoint: EModelEndpoint.agents, overrideEndpointFileConfig: endpointFileConfig, }); const { handleSharePointFiles, isProcessing, downloadProgress } = useSharePointFileHandling({ overrideEndpoint: EModelEndpoint.agents, overrideEndpointFileConfig: endpointFileConfig, toolResource, }); const { data: startupConfig } = useGetStartupConfig(); const sharePointEnabled = startupConfig?.sharePointFilePickerEnabled; const [isSharePointDialogOpen, setIsSharePointDialogOpen] = useState(false); const { agentsConfig } = useGetAgentsConfig(); /** TODO: Ephemeral Agent Capabilities * Allow defining agent capabilities on a per-endpoint basis * Use definition for agents endpoint for ephemeral agents * */ const capabilities = useAgentCapabilities(agentsConfig?.capabilities ?? defaultAgentCapabilities); const { fileSearchAllowedByAgent, codeAllowedByAgent } = useAgentToolPermissions( agentId, ephemeralAgent, ); const handleUploadClick = (isImage?: boolean) => { if (!inputRef.current) { return; } inputRef.current.value = ''; inputRef.current.accept = isImage === true ? 'image/*' : ''; inputRef.current.click(); inputRef.current.accept = ''; }; const dropdownItems = useMemo(() => { const createMenuItems = (onAction: (isImage?: boolean) => void) => { const items: MenuItemProps[] = [ { label: localize('com_ui_upload_image_input'), onClick: () => { setToolResource(undefined); onAction(true); }, icon: , }, ]; if (capabilities.contextEnabled) { items.push({ label: localize('com_ui_upload_ocr_text'), onClick: () => { setToolResource(EToolResources.context); onAction(); }, icon: , }); } if (capabilities.fileSearchEnabled && fileSearchAllowedByAgent) { items.push({ label: localize('com_ui_upload_file_search'), onClick: () => { setToolResource(EToolResources.file_search); setEphemeralAgent((prev) => ({ ...prev, [EToolResources.file_search]: true, })); onAction(); }, icon: , }); } if (capabilities.codeEnabled && codeAllowedByAgent) { items.push({ label: localize('com_ui_upload_code_files'), onClick: () => { setToolResource(EToolResources.execute_code); setEphemeralAgent((prev) => ({ ...prev, [EToolResources.execute_code]: true, })); onAction(); }, icon: , }); } return items; }; const localItems = createMenuItems(handleUploadClick); if (sharePointEnabled) { const sharePointItems = createMenuItems(() => { setIsSharePointDialogOpen(true); // Note: toolResource will be set by the specific item clicked }); localItems.push({ label: localize('com_files_upload_sharepoint'), onClick: () => {}, icon: , subItems: sharePointItems, }); return localItems; } return localItems; }, [ capabilities, localize, setToolResource, setEphemeralAgent, sharePointEnabled, codeAllowedByAgent, fileSearchAllowedByAgent, setIsSharePointDialogOpen, ]); const menuTrigger = (
} id="attach-file-menu-button" description={localize('com_sidepanel_attach_files')} disabled={isUploadDisabled} /> ); const handleSharePointFilesSelected = async (sharePointFiles: any[]) => { try { await handleSharePointFiles(sharePointFiles); setIsSharePointDialogOpen(false); } catch (error) { console.error('SharePoint file processing error:', error); } }; return ( <> { handleFileChange(e, toolResource); }} > ); }; export default React.memo(AttachFileMenu);