mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-19 18:00:15 +01:00
📂 refactor: Cleanup File Filtering Logic, Improve Validation (#10414)
* feat: add filterFilesByEndpointConfig to filter disabled file processing by provider * chore: explicit define of endpointFileConfig for better debugging * refactor: move `normalizeEndpointName` to data-provider as used app-wide * chore: remove overrideEndpoint from useFileHandling * refactor: improve endpoint file config selection * refactor: update filterFilesByEndpointConfig to accept structured parameters and improve endpoint file config handling * refactor: replace defaultFileConfig with getEndpointFileConfig for improved file configuration handling across components * test: add comprehensive unit tests for getEndpointFileConfig to validate endpoint configuration handling * refactor: streamline agent endpoint assignment and improve file filtering logic * feat: add error handling for disabled file uploads in endpoint configuration * refactor: update encodeAndFormat functions to accept structured parameters for provider and endpoint * refactor: streamline requestFiles handling in initializeAgent function * fix: getEndpointFileConfig partial config merging scenarios * refactor: enhance mergeWithDefault function to support document-supported providers with comprehensive MIME types * refactor: user-configured default file config in getEndpointFileConfig * fix: prevent file handling when endpoint is disabled and file is dragged to chat * refactor: move `getEndpointField` to `data-provider` and update usage across components and hooks * fix: prioritize endpointType based on agent.endpoint in file filtering logic * fix: prioritize agent.endpoint in file filtering logic and remove unnecessary endpointType defaulting
This commit is contained in:
parent
06c060b983
commit
2524d33362
62 changed files with 2352 additions and 290 deletions
|
|
@ -6,6 +6,7 @@ import {
|
|||
QueryKeys,
|
||||
ContentTypes,
|
||||
EModelEndpoint,
|
||||
getEndpointField,
|
||||
isAgentsEndpoint,
|
||||
parseCompactConvo,
|
||||
replaceSpecialVars,
|
||||
|
|
@ -25,10 +26,10 @@ import type { TAskFunction, ExtendedFile } from '~/common';
|
|||
import useSetFilesToDelete from '~/hooks/Files/useSetFilesToDelete';
|
||||
import useGetSender from '~/hooks/Conversations/useGetSender';
|
||||
import store, { useGetEphemeralAgent } from '~/store';
|
||||
import { getEndpointField, logger } from '~/utils';
|
||||
import useUserKey from '~/hooks/Input/useUserKey';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useAuthContext } from '~/hooks';
|
||||
import { logger } from '~/utils';
|
||||
|
||||
const logChatRequest = (request: Record<string, unknown>) => {
|
||||
logger.log('=====================================\nAsk function called with:');
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import { useRecoilValue } from 'recoil';
|
||||
import { useCallback, useRef, useEffect } from 'react';
|
||||
import { useGetModelsQuery } from 'librechat-data-provider/react-query';
|
||||
import { LocalStorageKeys, isAssistantsEndpoint } from 'librechat-data-provider';
|
||||
import { getEndpointField, LocalStorageKeys, isAssistantsEndpoint } from 'librechat-data-provider';
|
||||
import type {
|
||||
TPreset,
|
||||
TModelsConfig,
|
||||
TConversation,
|
||||
TEndpointsConfig,
|
||||
EModelEndpoint,
|
||||
TModelsConfig,
|
||||
TConversation,
|
||||
TPreset,
|
||||
} from 'librechat-data-provider';
|
||||
import type { SetterOrUpdater } from 'recoil';
|
||||
import type { AssistantListItem } from '~/common';
|
||||
import { getEndpointField, buildDefaultConvo, getDefaultEndpoint, logger } from '~/utils';
|
||||
import type { SetterOrUpdater } from 'recoil';
|
||||
import useAssistantListMap from '~/hooks/Assistants/useAssistantListMap';
|
||||
import { buildDefaultConvo, getDefaultEndpoint, logger } from '~/utils';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { mainTextareaId } from '~/common';
|
||||
import store from '~/store';
|
||||
|
|
|
|||
|
|
@ -2,20 +2,14 @@ import { useCallback } from 'react';
|
|||
import { useSetRecoilState } from 'recoil';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { QueryKeys, Constants, dataService } from 'librechat-data-provider';
|
||||
import { QueryKeys, Constants, dataService, getEndpointField } from 'librechat-data-provider';
|
||||
import type {
|
||||
TEndpointsConfig,
|
||||
TStartupConfig,
|
||||
TModelsConfig,
|
||||
TConversation,
|
||||
} from 'librechat-data-provider';
|
||||
import {
|
||||
getDefaultEndpoint,
|
||||
clearMessagesCache,
|
||||
buildDefaultConvo,
|
||||
getEndpointField,
|
||||
logger,
|
||||
} from '~/utils';
|
||||
import { getDefaultEndpoint, clearMessagesCache, buildDefaultConvo, logger } from '~/utils';
|
||||
import { useApplyModelSpecEffects } from '~/hooks/Agents';
|
||||
import store from '~/store';
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import {
|
|||
alternateName,
|
||||
EModelEndpoint,
|
||||
PermissionTypes,
|
||||
getEndpointField,
|
||||
} from 'librechat-data-provider';
|
||||
import type {
|
||||
TEndpointsConfig,
|
||||
|
|
@ -14,8 +15,8 @@ import type {
|
|||
Agent,
|
||||
} from 'librechat-data-provider';
|
||||
import type { Endpoint } from '~/common';
|
||||
import { mapEndpoints, getIconKey, getEndpointField } from '~/utils';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { mapEndpoints, getIconKey } from '~/utils';
|
||||
import { useHasAccess } from '~/hooks';
|
||||
import { icons } from './Icons';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { useState, useMemo, useCallback, useRef } from 'react';
|
||||
import { useDrop } from 'react-dnd';
|
||||
import { useToastContext } from '@librechat/client';
|
||||
import { NativeTypes } from 'react-dnd-html5-backend';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
|
@ -7,10 +8,12 @@ import {
|
|||
Tools,
|
||||
QueryKeys,
|
||||
Constants,
|
||||
EModelEndpoint,
|
||||
EToolResources,
|
||||
EModelEndpoint,
|
||||
mergeFileConfig,
|
||||
AgentCapabilities,
|
||||
isAssistantsEndpoint,
|
||||
getEndpointFileConfig,
|
||||
defaultAgentCapabilities,
|
||||
} from 'librechat-data-provider';
|
||||
import type { DropTargetMonitor } from 'react-dnd';
|
||||
|
|
@ -18,9 +21,12 @@ import type * as t from 'librechat-data-provider';
|
|||
import store, { ephemeralAgentByConvoId } from '~/store';
|
||||
import useFileHandling from './useFileHandling';
|
||||
import { isEphemeralAgent } from '~/common';
|
||||
import useLocalize from '../useLocalize';
|
||||
|
||||
export default function useDragHelpers() {
|
||||
const queryClient = useQueryClient();
|
||||
const { showToast } = useToastContext();
|
||||
const localize = useLocalize();
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
const [draggedFiles, setDraggedFiles] = useState<File[]>([]);
|
||||
const conversation = useRecoilValue(store.conversationByIndex(0)) || undefined;
|
||||
|
|
@ -33,9 +39,7 @@ export default function useDragHelpers() {
|
|||
[conversation?.endpoint],
|
||||
);
|
||||
|
||||
const { handleFiles } = useFileHandling({
|
||||
overrideEndpoint: isAssistants ? undefined : EModelEndpoint.agents,
|
||||
});
|
||||
const { handleFiles } = useFileHandling();
|
||||
|
||||
const handleOptionSelect = useCallback(
|
||||
(toolResource: EToolResources | undefined) => {
|
||||
|
|
@ -62,6 +66,26 @@ export default function useDragHelpers() {
|
|||
|
||||
const handleDrop = useCallback(
|
||||
(item: { files: File[] }) => {
|
||||
/** Early block: leverage endpoint file config to prevent drag/drop on disabled endpoints */
|
||||
const currentEndpoint = conversationRef.current?.endpoint ?? 'default';
|
||||
const currentEndpointType = conversationRef.current?.endpointType ?? undefined;
|
||||
const cfg = queryClient.getQueryData<t.FileConfig>([QueryKeys.fileConfig]);
|
||||
if (cfg) {
|
||||
const mergedCfg = mergeFileConfig(cfg);
|
||||
const endpointCfg = getEndpointFileConfig({
|
||||
fileConfig: mergedCfg,
|
||||
endpoint: currentEndpoint,
|
||||
endpointType: currentEndpointType,
|
||||
});
|
||||
if (endpointCfg?.disabled === true) {
|
||||
showToast({
|
||||
message: localize('com_ui_attach_error_disabled'),
|
||||
status: 'error',
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (isAssistants) {
|
||||
handleFilesRef.current(item.files);
|
||||
return;
|
||||
|
|
@ -110,7 +134,7 @@ export default function useDragHelpers() {
|
|||
setDraggedFiles(item.files);
|
||||
setShowModal(true);
|
||||
},
|
||||
[isAssistants, queryClient],
|
||||
[isAssistants, queryClient, showToast, localize],
|
||||
);
|
||||
|
||||
const [{ canDrop, isOver }, drop] = useDrop(
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import React, { useCallback, useEffect, useRef, useMemo, useState } from 'react';
|
||||
import { v4 } from 'uuid';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { useToastContext } from '@librechat/client';
|
||||
|
|
@ -6,16 +6,14 @@ import { useQueryClient } from '@tanstack/react-query';
|
|||
import {
|
||||
QueryKeys,
|
||||
Constants,
|
||||
EModelEndpoint,
|
||||
EToolResources,
|
||||
mergeFileConfig,
|
||||
isAgentsEndpoint,
|
||||
isAssistantsEndpoint,
|
||||
getEndpointFileConfig,
|
||||
defaultAssistantsVersion,
|
||||
fileConfig as defaultFileConfig,
|
||||
} from 'librechat-data-provider';
|
||||
import debounce from 'lodash/debounce';
|
||||
import type { EndpointFileConfig, TEndpointsConfig, TError } from 'librechat-data-provider';
|
||||
import type { TEndpointsConfig, TError } from 'librechat-data-provider';
|
||||
import type { ExtendedFile, FileSetter } from '~/common';
|
||||
import { useGetFileConfig, useUploadFileMutation } from '~/data-provider';
|
||||
import useLocalize, { TranslationKeys } from '~/hooks/useLocalize';
|
||||
|
|
@ -29,9 +27,7 @@ import useUpdateFiles from './useUpdateFiles';
|
|||
|
||||
type UseFileHandling = {
|
||||
fileSetter?: FileSetter;
|
||||
overrideEndpoint?: EModelEndpoint;
|
||||
fileFilter?: (file: File) => boolean;
|
||||
overrideEndpointFileConfig?: EndpointFileConfig;
|
||||
additionalMetadata?: Record<string, string | undefined>;
|
||||
};
|
||||
|
||||
|
|
@ -54,17 +50,13 @@ const useFileHandling = (params?: UseFileHandling) => {
|
|||
|
||||
const agent_id = params?.additionalMetadata?.agent_id ?? '';
|
||||
const assistant_id = params?.additionalMetadata?.assistant_id ?? '';
|
||||
const endpointType = useMemo(() => conversation?.endpointType, [conversation?.endpointType]);
|
||||
const endpoint = useMemo(() => conversation?.endpoint ?? 'default', [conversation?.endpoint]);
|
||||
|
||||
const { data: fileConfig = null } = useGetFileConfig({
|
||||
select: (data) => mergeFileConfig(data),
|
||||
});
|
||||
|
||||
const endpoint = useMemo(
|
||||
() =>
|
||||
params?.overrideEndpoint ?? conversation?.endpointType ?? conversation?.endpoint ?? 'default',
|
||||
[params?.overrideEndpoint, conversation?.endpointType, conversation?.endpoint],
|
||||
);
|
||||
|
||||
const displayToast = useCallback(() => {
|
||||
if (errors.length > 1) {
|
||||
// TODO: this should not be a dynamic localize input!!
|
||||
|
|
@ -169,10 +161,7 @@ const useFileHandling = (params?: UseFileHandling) => {
|
|||
|
||||
const formData = new FormData();
|
||||
formData.append('endpoint', endpoint);
|
||||
formData.append(
|
||||
'original_endpoint',
|
||||
conversation?.endpointType || conversation?.endpoint || '',
|
||||
);
|
||||
formData.append('endpointType', endpointType ?? '');
|
||||
formData.append('file', extendedFile.file as File, encodeURIComponent(filename));
|
||||
formData.append('file_id', extendedFile.file_id);
|
||||
|
||||
|
|
@ -194,7 +183,7 @@ const useFileHandling = (params?: UseFileHandling) => {
|
|||
}
|
||||
}
|
||||
|
||||
if (isAgentsEndpoint(endpoint)) {
|
||||
if (!isAssistantsEndpoint(endpointType ?? endpoint)) {
|
||||
if (!agent_id) {
|
||||
formData.append('message_file', 'true');
|
||||
}
|
||||
|
|
@ -205,9 +194,7 @@ const useFileHandling = (params?: UseFileHandling) => {
|
|||
if (conversation?.agent_id != null && formData.get('agent_id') == null) {
|
||||
formData.append('agent_id', conversation.agent_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isAssistantsEndpoint(endpoint)) {
|
||||
uploadFile.mutate(formData);
|
||||
return;
|
||||
}
|
||||
|
|
@ -264,18 +251,19 @@ const useFileHandling = (params?: UseFileHandling) => {
|
|||
/* Validate files */
|
||||
let filesAreValid: boolean;
|
||||
try {
|
||||
const endpointFileConfig = getEndpointFileConfig({
|
||||
endpoint,
|
||||
fileConfig,
|
||||
endpointType,
|
||||
});
|
||||
|
||||
filesAreValid = validateFiles({
|
||||
files,
|
||||
fileList,
|
||||
setError,
|
||||
endpointFileConfig:
|
||||
params?.overrideEndpointFileConfig ??
|
||||
fileConfig?.endpoints?.[endpoint] ??
|
||||
fileConfig?.endpoints?.default ??
|
||||
defaultFileConfig.endpoints[endpoint] ??
|
||||
defaultFileConfig.endpoints.default,
|
||||
fileConfig,
|
||||
endpointFileConfig,
|
||||
toolResource: _toolResource,
|
||||
fileConfig: fileConfig,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('file validation error', error);
|
||||
|
|
|
|||
|
|
@ -5,11 +5,9 @@ import type { SharePointFile } from '~/data-provider/Files/sharepoint';
|
|||
|
||||
interface UseSharePointFileHandlingProps {
|
||||
fileSetter?: any;
|
||||
toolResource?: string;
|
||||
fileFilter?: (file: File) => boolean;
|
||||
additionalMetadata?: Record<string, string | undefined>;
|
||||
overrideEndpoint?: any;
|
||||
overrideEndpointFileConfig?: any;
|
||||
toolResource?: string;
|
||||
}
|
||||
|
||||
interface UseSharePointFileHandlingReturn {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { getEndpointField } from 'librechat-data-provider';
|
||||
import { useChatContext } from '~/Providers/ChatContext';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { getEndpointField } from '~/utils';
|
||||
import useUserKey from './useUserKey';
|
||||
|
||||
export default function useRequiresKey() {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
import { useCallback } from 'react';
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import { useGetModelsQuery } from 'librechat-data-provider/react-query';
|
||||
import { useRecoilState, useRecoilValue, useSetRecoilState, useRecoilCallback } from 'recoil';
|
||||
import {
|
||||
Constants,
|
||||
FileSources,
|
||||
EModelEndpoint,
|
||||
isParamEndpoint,
|
||||
getEndpointField,
|
||||
LocalStorageKeys,
|
||||
isAssistantsEndpoint,
|
||||
} from 'librechat-data-provider';
|
||||
import { useRecoilState, useRecoilValue, useSetRecoilState, useRecoilCallback } from 'recoil';
|
||||
import type {
|
||||
TPreset,
|
||||
TSubmission,
|
||||
|
|
@ -19,19 +20,18 @@ import type {
|
|||
} from 'librechat-data-provider';
|
||||
import type { AssistantListItem } from '~/common';
|
||||
import {
|
||||
getEndpointField,
|
||||
buildDefaultConvo,
|
||||
updateLastSelectedModel,
|
||||
getDefaultModelSpec,
|
||||
getDefaultEndpoint,
|
||||
getModelSpecPreset,
|
||||
getDefaultModelSpec,
|
||||
updateLastSelectedModel,
|
||||
buildDefaultConvo,
|
||||
logger,
|
||||
} from '~/utils';
|
||||
import { useDeleteFilesMutation, useGetEndpointsQuery, useGetStartupConfig } from '~/data-provider';
|
||||
import useAssistantListMap from './Assistants/useAssistantListMap';
|
||||
import { useResetChatBadges } from './useChatBadges';
|
||||
import { useApplyModelSpecEffects } from './Agents';
|
||||
import { usePauseGlobalAudio } from './Audio';
|
||||
import { logger } from '~/utils';
|
||||
import store from '~/store';
|
||||
|
||||
const useNewConvo = (index = 0) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue