| import { useToastContext } from '@librechat/client'; |
| import { EToolResources } from 'librechat-data-provider'; |
| import { useMutation, useQueryClient } from '@tanstack/react-query'; |
| import { |
| QueryKeys, |
| dataService, |
| MutationKeys, |
| defaultOrderQuery, |
| isAssistantsEndpoint, |
| } from 'librechat-data-provider'; |
| import type * as t from 'librechat-data-provider'; |
| import type { UseMutationResult } from '@tanstack/react-query'; |
| import { useLocalize } from '~/hooks'; |
|
|
| export const useUploadFileMutation = ( |
| _options?: t.UploadMutationOptions, |
| signal?: AbortSignal | null, |
| ): UseMutationResult< |
| t.TFileUpload, |
| unknown, |
| FormData, |
| unknown |
| > => { |
| const queryClient = useQueryClient(); |
| const { onSuccess, ...options } = _options || {}; |
| return useMutation([MutationKeys.fileUpload], { |
| mutationFn: (body: FormData) => { |
| const width = body.get('width') ?? ''; |
| const height = body.get('height') ?? ''; |
| const version = body.get('version') ?? ''; |
| const endpoint = (body.get('endpoint') ?? '') as string; |
| if (isAssistantsEndpoint(endpoint) && version === '2') { |
| return dataService.uploadFile(body, signal); |
| } |
|
|
| if (width !== '' && height !== '') { |
| return dataService.uploadImage(body, signal); |
| } |
|
|
| return dataService.uploadFile(body, signal); |
| }, |
| ...options, |
| onSuccess: (data, formData, context) => { |
| queryClient.setQueryData<t.TFile[] | undefined>([QueryKeys.files], (_files) => [ |
| data, |
| ...(_files ?? []), |
| ]); |
|
|
| const endpoint = formData.get('endpoint'); |
| const message_file = formData.get('message_file'); |
| const agent_id = (formData.get('agent_id') as string | undefined) ?? ''; |
| const assistant_id = (formData.get('assistant_id') as string | undefined) ?? ''; |
| const tool_resource = (formData.get('tool_resource') as string | undefined) ?? ''; |
|
|
| if (message_file === 'true') { |
| onSuccess?.(data, formData, context); |
| return; |
| } |
|
|
| if (agent_id && tool_resource) { |
| queryClient.setQueryData<t.Agent>([QueryKeys.agent, agent_id], (agent) => { |
| if (!agent) { |
| return agent; |
| } |
|
|
| const update = {}; |
| const prevResources = agent.tool_resources ?? {}; |
| const prevResource: t.ExecuteCodeResource | t.AgentFileResource = agent.tool_resources?.[ |
| tool_resource |
| ] ?? { |
| file_ids: [], |
| }; |
| if (!prevResource.file_ids) { |
| prevResource.file_ids = []; |
| } |
| prevResource.file_ids.push(data.file_id); |
| update['tool_resources'] = { |
| ...prevResources, |
| [tool_resource]: prevResource, |
| }; |
| if (!agent.tools?.includes(tool_resource)) { |
| update['tools'] = [...(agent.tools ?? []), tool_resource]; |
| } |
| return { |
| ...agent, |
| ...update, |
| }; |
| }); |
| } |
|
|
| if (!assistant_id) { |
| onSuccess?.(data, formData, context); |
| return; |
| } |
|
|
| queryClient.setQueryData<t.AssistantListResponse>( |
| [QueryKeys.assistants, endpoint, defaultOrderQuery], |
| (prev) => { |
| if (!prev) { |
| return prev; |
| } |
|
|
| return { |
| ...prev, |
| data: prev.data.map((assistant) => { |
| if (assistant.id !== assistant_id) { |
| return assistant; |
| } |
|
|
| const update = {}; |
| if (!tool_resource) { |
| update['file_ids'] = [...(assistant.file_ids ?? []), data.file_id]; |
| } |
| if (tool_resource === EToolResources.code_interpreter) { |
| const prevResources = assistant.tool_resources ?? {}; |
| const prevResource = assistant.tool_resources?.[tool_resource] ?? { |
| file_ids: [], |
| }; |
| if (!prevResource.file_ids) { |
| prevResource.file_ids = []; |
| } |
| prevResource.file_ids.push(data.file_id); |
| update['tool_resources'] = { |
| ...prevResources, |
| [tool_resource]: prevResource, |
| }; |
| } |
| return { |
| ...assistant, |
| ...update, |
| }; |
| }), |
| }; |
| }, |
| ); |
| onSuccess?.(data, formData, context); |
| }, |
| }); |
| }; |
|
|
| export const useDeleteFilesMutation = ( |
| _options?: t.DeleteMutationOptions, |
| ): UseMutationResult< |
| t.DeleteFilesResponse, |
| unknown, |
| t.DeleteFilesBody, |
| unknown |
| > => { |
| const queryClient = useQueryClient(); |
| const { showToast } = useToastContext(); |
| const localize = useLocalize(); |
| const { onSuccess, onError, ...options } = _options || {}; |
| return useMutation([MutationKeys.fileDelete], { |
| mutationFn: (body: t.DeleteFilesBody) => dataService.deleteFiles(body), |
| ...options, |
| onError: (error, vars, context) => { |
| if (error && typeof error === 'object' && 'response' in error) { |
| const errorWithResponse = error as { response?: { status?: number } }; |
| if (errorWithResponse.response?.status === 403) { |
| showToast({ |
| message: localize('com_ui_delete_not_allowed'), |
| status: 'error', |
| }); |
| } |
| } |
| onError?.(error, vars, context); |
| }, |
| onSuccess: (data, vars, context) => { |
| queryClient.setQueryData<t.TFile[] | undefined>([QueryKeys.files], (cachefiles) => { |
| const { files: filesDeleted } = vars; |
|
|
| const fileMap = filesDeleted.reduce((acc, file) => { |
| acc.set(file.file_id, file); |
| return acc; |
| }, new Map<string, t.BatchFile>()); |
|
|
| return (cachefiles ?? []).filter((file) => !fileMap.has(file.file_id)); |
| }); |
|
|
| showToast({ |
| message: localize('com_ui_delete_success'), |
| status: 'success', |
| }); |
|
|
| onSuccess?.(data, vars, context); |
| if (vars.agent_id != null && vars.agent_id) { |
| queryClient.refetchQueries([QueryKeys.agent, vars.agent_id]); |
| } |
| }, |
| }); |
| }; |
|
|