mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-24 12:20:14 +01:00
fix: deletion doesn't cause reference loss in versioning anymore - file reference maintained in db
This commit is contained in:
parent
d4fd0047cb
commit
7c3356e10b
2 changed files with 75 additions and 26 deletions
|
|
@ -11,6 +11,7 @@ import {
|
|||
ResourceType,
|
||||
PermissionBits,
|
||||
PermissionTypes,
|
||||
EToolResources,
|
||||
} from 'librechat-data-provider';
|
||||
import type { TCreatePrompt, TPrompt, TPromptGroup } from 'librechat-data-provider';
|
||||
import {
|
||||
|
|
@ -193,16 +194,18 @@ const PromptForm = () => {
|
|||
handleFileRemove,
|
||||
setFiles,
|
||||
} = usePromptFileHandling({
|
||||
onFileChange: () => {
|
||||
onFileChange: (updatedFiles) => {
|
||||
// Auto-save when files are added/removed
|
||||
console.log('onFileChange called', { canEdit, selectedPrompt: !!selectedPrompt });
|
||||
console.log('onFileChange called', {
|
||||
canEdit,
|
||||
selectedPrompt: !!selectedPrompt,
|
||||
updatedFiles,
|
||||
});
|
||||
if (canEdit && selectedPrompt) {
|
||||
const currentPromptText = getValues('prompt');
|
||||
console.log('Calling onSave with:', currentPromptText);
|
||||
// Use setTimeout to ensure file state is updated before calling onSave
|
||||
setTimeout(() => {
|
||||
onSave(currentPromptText);
|
||||
}, 100);
|
||||
console.log('Calling onSave with:', currentPromptText, 'and updated files:', updatedFiles);
|
||||
// Call onSave with the updated files to ensure correct tool_resources
|
||||
onSave(currentPromptText, updatedFiles);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
@ -280,8 +283,33 @@ const PromptForm = () => {
|
|||
},
|
||||
});
|
||||
|
||||
// Helper function to get tool resources from a specific files array
|
||||
const getToolResourcesFromFiles = useCallback((files: ExtendedFile[]) => {
|
||||
if (files.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const toolResources: AgentToolResources = {};
|
||||
|
||||
files.forEach((file) => {
|
||||
if (!file.file_id) return; // Skip files that haven't been uploaded yet
|
||||
|
||||
// Initialize the tool resource if it doesn't exist
|
||||
if (!toolResources[file.tool_resource]) {
|
||||
toolResources[file.tool_resource] = { file_ids: [] };
|
||||
}
|
||||
|
||||
// Add file_id to the appropriate tool resource
|
||||
if (!toolResources[file.tool_resource]!.file_ids!.includes(file.file_id)) {
|
||||
toolResources[file.tool_resource]!.file_ids!.push(file.file_id);
|
||||
}
|
||||
});
|
||||
|
||||
return Object.keys(toolResources).length > 0 ? toolResources : undefined;
|
||||
}, []);
|
||||
|
||||
const onSave = useCallback(
|
||||
(value: string) => {
|
||||
(value: string, updatedFiles?: ExtendedFile[]) => {
|
||||
if (!canEdit) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -299,7 +327,10 @@ const PromptForm = () => {
|
|||
return;
|
||||
}
|
||||
|
||||
const toolResources = getToolResources();
|
||||
// Use updated files if provided, otherwise use current hook state
|
||||
const toolResources = updatedFiles
|
||||
? getToolResourcesFromFiles(updatedFiles)
|
||||
: getToolResources();
|
||||
const tempPrompt: TCreatePrompt = {
|
||||
prompt: {
|
||||
type: selectedPrompt.type ?? 'text',
|
||||
|
|
|
|||
|
|
@ -4,14 +4,14 @@ import { useToastContext } from '@librechat/client';
|
|||
import { EModelEndpoint, EToolResources, FileSources } from 'librechat-data-provider';
|
||||
import type { AgentToolResources, TFile } from 'librechat-data-provider';
|
||||
import type { ExtendedFile } from '~/common';
|
||||
import { useUploadFileMutation, useGetFiles, useDeleteFilesMutation } from '~/data-provider';
|
||||
import { useUploadFileMutation, useGetFiles } from '~/data-provider';
|
||||
import { useAuthContext } from '~/hooks';
|
||||
import { logger } from '~/utils';
|
||||
|
||||
interface UsePromptFileHandling {
|
||||
fileSetter?: (files: ExtendedFile[]) => void;
|
||||
initialFiles?: ExtendedFile[];
|
||||
onFileChange?: () => void; // Callback when files are added/removed
|
||||
onFileChange?: (updatedFiles: ExtendedFile[]) => void; // Callback when files are added/removed
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -38,16 +38,6 @@ export const usePromptFileHandling = (params?: UsePromptFileHandling) => {
|
|||
const [filesLoading, setFilesLoading] = useState(false);
|
||||
const abortControllerRef = useRef<AbortController | null>(null);
|
||||
|
||||
const deleteFileMutation = useDeleteFilesMutation({
|
||||
onSuccess: () => {
|
||||
params?.onFileChange?.();
|
||||
},
|
||||
onError: (error) => {
|
||||
logger.error('Error deleting file:', error);
|
||||
params?.onFileChange?.();
|
||||
},
|
||||
});
|
||||
|
||||
const uploadFile = useUploadFileMutation({
|
||||
onSuccess: (data) => {
|
||||
logger.log('File uploaded successfully', data);
|
||||
|
|
@ -80,8 +70,27 @@ export const usePromptFileHandling = (params?: UsePromptFileHandling) => {
|
|||
status: 'success',
|
||||
});
|
||||
|
||||
// Call the onFileChange callback to trigger save
|
||||
params?.onFileChange?.();
|
||||
// Call the onFileChange callback to trigger save with updated files
|
||||
const updatedFiles = files.map((file) => {
|
||||
if (file.temp_file_id === data.temp_file_id) {
|
||||
return {
|
||||
...file,
|
||||
file_id: data.file_id,
|
||||
filepath: data.filepath,
|
||||
progress: 1,
|
||||
attached: true,
|
||||
preview: data.filepath || file.preview,
|
||||
filename: data.filename || file.filename,
|
||||
type: data.type || file.type,
|
||||
size: data.bytes || file.size,
|
||||
width: data.width || file.width,
|
||||
height: data.height || file.height,
|
||||
source: data.source || file.source,
|
||||
};
|
||||
}
|
||||
return file;
|
||||
});
|
||||
params?.onFileChange?.(updatedFiles);
|
||||
},
|
||||
onError: (error, body) => {
|
||||
logger.error('File upload error:', error);
|
||||
|
|
@ -228,8 +237,8 @@ export const usePromptFileHandling = (params?: UsePromptFileHandling) => {
|
|||
// Handle file removal
|
||||
const handleFileRemove = useCallback(
|
||||
(fileId: string) => {
|
||||
// Call delete API to remove from database
|
||||
deleteFileMutation.mutate([fileId]);
|
||||
// For prompts, we only remove the file from the current prompt's tool_resources
|
||||
// We don't delete the file from the database to preserve previous versions
|
||||
|
||||
setFiles((prev) => {
|
||||
return prev.filter((file) => {
|
||||
|
|
@ -243,8 +252,17 @@ export const usePromptFileHandling = (params?: UsePromptFileHandling) => {
|
|||
return true; // Keep this file
|
||||
});
|
||||
});
|
||||
|
||||
// Call the onFileChange callback to trigger prompt version update with updated files
|
||||
const updatedFiles = files.filter((file) => {
|
||||
if (file.file_id === fileId || file.temp_file_id === fileId) {
|
||||
return false; // Remove this file
|
||||
}
|
||||
return true; // Keep this file
|
||||
});
|
||||
params?.onFileChange?.(updatedFiles);
|
||||
},
|
||||
[deleteFileMutation, params?.onFileChange],
|
||||
[params?.onFileChange],
|
||||
);
|
||||
|
||||
// Sync with external fileSetter when files change
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue