🧭 fix: Preserve File Search Upload Target (#13019)

This commit is contained in:
Danny Avila 2026-05-08 11:18:12 -04:00
parent 119ac9c944
commit a43bc45b73
No known key found for this signature in database
GPG key ID: BF31EEB2C5CA0956
2 changed files with 67 additions and 6 deletions

View file

@ -81,7 +81,7 @@ const AttachFileMenu = ({
const [ephemeralAgent, setEphemeralAgent] = useRecoilState(
ephemeralAgentByConvoId(conversationId),
);
const [toolResource, setToolResource] = useState<EToolResources | undefined>();
const toolResourceRef = useRef<EToolResources | undefined>();
const { handleFileChange } = useFileHandlingNoChatContext(undefined, {
files,
setFiles,
@ -90,7 +90,7 @@ const AttachFileMenu = ({
});
const { handleSharePointFiles, isProcessing, downloadProgress } =
useSharePointFileHandlingNoChatContext(
{ toolResource },
{ toolResource: toolResourceRef.current },
{ files, setFiles, setFilesLoading, conversation },
);
@ -142,6 +142,10 @@ const AttachFileMenu = ({
);
const dropdownItems = useMemo(() => {
const setToolResource = (value: EToolResources | undefined) => {
toolResourceRef.current = value;
};
const createMenuItems = (onAction: (fileType?: FileUploadType) => void) => {
const items: MenuItemProps[] = [];
@ -257,7 +261,6 @@ const AttachFileMenu = ({
capabilities,
useResponsesApi,
handleUploadClick,
setToolResource,
setEphemeralAgent,
sharePointEnabled,
codeAllowedByAgent,
@ -301,7 +304,8 @@ const AttachFileMenu = ({
<FileUpload
ref={inputRef}
handleFileChange={(e) => {
handleFileChange(e, toolResource);
handleFileChange(e, toolResourceRef.current);
toolResourceRef.current = undefined;
}}
>
<DropdownPopup

View file

@ -2,7 +2,7 @@ import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { RecoilRoot } from 'recoil';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { EModelEndpoint, Providers } from 'librechat-data-provider';
import { EModelEndpoint, EToolResources, Providers } from 'librechat-data-provider';
import AttachFileMenu from '../AttachFileMenu';
jest.mock('~/hooks', () => ({
@ -31,7 +31,20 @@ jest.mock('@librechat/client', () => {
// eslint-disable-next-line @typescript-eslint/no-require-imports
const R = require('react');
return {
FileUpload: (props) => R.createElement('div', { 'data-testid': 'file-upload' }, props.children),
FileUpload: R.forwardRef((props, ref) =>
R.createElement(
'div',
{ 'data-testid': 'file-upload' },
props.children,
R.createElement('input', {
ref,
multiple: true,
type: 'file',
'data-testid': 'file-input',
onChange: props.handleFileChange,
}),
),
),
TooltipAnchor: (props) => props.render,
DropdownPopup: (props) =>
R.createElement(
@ -318,6 +331,50 @@ describe('AttachFileMenu', () => {
expect(screen.getByText('Upload for File Search')).toBeInTheDocument();
expect(screen.getByText('Upload Code Files')).toBeInTheDocument();
});
it('passes File Search resource when the file input changes before React state commits', () => {
setupMocks();
const handleFileChange = jest.fn();
mockUseFileHandlingNoChatContext.mockReturnValue({ handleFileChange });
mockUseAgentCapabilities.mockReturnValue({
contextEnabled: false,
fileSearchEnabled: true,
codeEnabled: false,
});
mockUseAgentToolPermissions.mockReturnValue({
fileSearchAllowedByAgent: true,
codeAllowedByAgent: false,
provider: undefined,
});
const originalClick = HTMLInputElement.prototype.click;
const file = new File(['data'], 'sheet.xlsx', {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
});
HTMLInputElement.prototype.click = function click() {
Object.defineProperty(this, 'files', {
configurable: true,
value: [file],
});
fireEvent.change(this);
};
try {
renderMenu({ endpointType: EModelEndpoint.openAI });
openMenu();
fireEvent.click(screen.getByText('Upload to Provider'));
fireEvent.click(screen.getByText('Upload for File Search'));
} finally {
HTMLInputElement.prototype.click = originalClick;
}
expect(handleFileChange).toHaveBeenNthCalledWith(1, expect.any(Object), undefined);
expect(handleFileChange).toHaveBeenNthCalledWith(
2,
expect.any(Object),
EToolResources.file_search,
);
});
});
describe('SharePoint Integration', () => {