🔒 feat: View/Delete Shared Agent Files (#8419)

* 🔧 fix: Add localized message for delete operation not allowed

* refactor: improve file deletion operations ux

* feat: agent-based file access control and enhance file retrieval logic

* feat: implement agent-specific file retrieval

* feat: enhance agent file retrieval logic for authors and shared access

* ci: include userId and agentId in mockGetFiles call for OCR file retrieval
This commit is contained in:
Danny Avila 2025-07-12 01:52:46 -04:00 committed by GitHub
parent 6aa4bb5a4a
commit f1b29ffb45
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 1216 additions and 35 deletions

View file

@ -2,6 +2,8 @@ import { useEffect } from 'react';
import { EToolResources } from 'librechat-data-provider';
import type { ExtendedFile } from '~/common';
import { useDeleteFilesMutation } from '~/data-provider';
import { useToastContext } from '~/Providers';
import { useLocalize } from '~/hooks';
import { useFileDeletion } from '~/hooks/Files';
import FileContainer from './FileContainer';
import { logger } from '~/utils';
@ -30,6 +32,8 @@ export default function FileRow({
isRTL?: boolean;
Wrapper?: React.FC<{ children: React.ReactNode }>;
}) {
const localize = useLocalize();
const { showToast } = useToastContext();
const files = Array.from(_files?.values() ?? []).filter((file) =>
fileFilter ? fileFilter(file) : true,
);
@ -105,6 +109,10 @@ export default function FileRow({
)
.uniqueFiles.map((file: ExtendedFile, index: number) => {
const handleDelete = () => {
showToast({
message: localize('com_ui_deleting_file'),
status: 'info',
});
if (abortUpload && file.progress < 1) {
abortUpload();
}

View file

@ -7,6 +7,7 @@ import { useToastContext, useFileMapContext, useAgentPanelContext } from '~/Prov
import useAgentCapabilities from '~/hooks/Agents/useAgentCapabilities';
import Action from '~/components/SidePanel/Builder/Action';
import { ToolSelectDialog } from '~/components/Tools';
import { useGetAgentFiles } from '~/data-provider';
import { icons } from '~/hooks/Endpoint/Icons';
import { processAgentOption } from '~/utils';
import Instructions from './Instructions';
@ -49,6 +50,18 @@ export default function AgentConfig({ createMutation }: Pick<AgentPanelProps, 'c
const tools = useWatch({ control, name: 'tools' });
const agent_id = useWatch({ control, name: 'id' });
const { data: agentFiles = [] } = useGetAgentFiles(agent_id);
const mergedFileMap = useMemo(() => {
const newFileMap = { ...fileMap };
agentFiles.forEach((file) => {
if (file.file_id) {
newFileMap[file.file_id] = file;
}
});
return newFileMap;
}, [fileMap, agentFiles]);
const {
ocrEnabled,
codeEnabled,
@ -74,10 +87,10 @@ export default function AgentConfig({ createMutation }: Pick<AgentPanelProps, 'c
const _agent = processAgentOption({
agent,
fileMap,
fileMap: mergedFileMap,
});
return _agent.context_files ?? [];
}, [agent, agent_id, fileMap]);
}, [agent, agent_id, mergedFileMap]);
const knowledge_files = useMemo(() => {
if (typeof agent === 'string') {
@ -94,10 +107,10 @@ export default function AgentConfig({ createMutation }: Pick<AgentPanelProps, 'c
const _agent = processAgentOption({
agent,
fileMap,
fileMap: mergedFileMap,
});
return _agent.knowledge_files ?? [];
}, [agent, agent_id, fileMap]);
}, [agent, agent_id, mergedFileMap]);
const code_files = useMemo(() => {
if (typeof agent === 'string') {
@ -114,10 +127,10 @@ export default function AgentConfig({ createMutation }: Pick<AgentPanelProps, 'c
const _agent = processAgentOption({
agent,
fileMap,
fileMap: mergedFileMap,
});
return _agent.code_files ?? [];
}, [agent, agent_id, fileMap]);
}, [agent, agent_id, mergedFileMap]);
const handleAddActions = useCallback(() => {
if (!agent_id) {

View file

@ -135,10 +135,9 @@ export default function ShareAgent({
'btn btn-neutral border-token-border-light relative h-9 rounded-lg font-medium',
removeFocusOutlines,
)}
aria-label={localize(
'com_ui_share_var',
{ 0: agentName != null && agentName !== '' ? `"${agentName}"` : localize('com_ui_agent') },
)}
aria-label={localize('com_ui_share_var', {
0: agentName != null && agentName !== '' ? `"${agentName}"` : localize('com_ui_agent'),
})}
type="button"
>
<div className="flex items-center justify-center gap-2 text-blue-500">
@ -148,10 +147,9 @@ export default function ShareAgent({
</OGDialogTrigger>
<OGDialogContent className="w-11/12 md:max-w-xl">
<OGDialogTitle>
{localize(
'com_ui_share_var',
{ 0: agentName != null && agentName !== '' ? `"${agentName}"` : localize('com_ui_agent') },
)}
{localize('com_ui_share_var', {
0: agentName != null && agentName !== '' ? `"${agentName}"` : localize('com_ui_agent'),
})}
</OGDialogTitle>
<form
className="p-2"