🔐 feat: Granular Role-based Permissions + Entra ID Group Discovery (#7804)

WIP: pre-granular-permissions commit

feat: Add category and support contact fields to Agent schema and UI components

Revert "feat: Add category and support contact fields to Agent schema and UI components"

This reverts commit c43a52b4c9.

Fix: Update import for renderHook in useAgentCategories.spec.tsx

fix: Update icon rendering in AgentCategoryDisplay tests to use empty spans

refactor: Improve category synchronization logic and clean up AgentConfig component

refactor: Remove unused UI flow translations from translation.json

feat: agent marketplace features

🔐 feat: Granular Role-based Permissions + Entra ID Group Discovery (#7804)
This commit is contained in:
Danny Avila 2025-06-23 10:22:27 -04:00
parent 3e1591d404
commit 658480d7cd
No known key found for this signature in database
GPG key ID: BF31EEB2C5CA0956
143 changed files with 17592 additions and 632 deletions

View file

@ -8,6 +8,7 @@ import {
SystemRoles,
EModelEndpoint,
TAgentsEndpoint,
PERMISSION_BITS,
TEndpointsConfig,
isAssistantsEndpoint,
} from 'librechat-data-provider';
@ -16,8 +17,10 @@ import {
useCreateAgentMutation,
useUpdateAgentMutation,
useGetAgentByIdQuery,
useGetExpandedAgentByIdQuery,
} from '~/data-provider';
import { createProviderOption, getDefaultAgentFormValues } from '~/utils';
import { useResourcePermissions } from '~/hooks/useResourcePermissions';
import { useSelectAgent, useLocalize, useAuthContext } from '~/hooks';
import { useAgentPanelContext } from '~/Providers/AgentPanelContext';
import AgentPanelSkeleton from './AgentPanelSkeleton';
@ -50,10 +53,29 @@ export default function AgentPanel({
const { onSelect: onSelectAgent } = useSelectAgent();
const modelsQuery = useGetModelsQuery();
const agentQuery = useGetAgentByIdQuery(current_agent_id ?? '', {
// Basic agent query for initial permission check
const basicAgentQuery = useGetAgentByIdQuery(current_agent_id ?? '', {
enabled: !!(current_agent_id ?? '') && current_agent_id !== Constants.EPHEMERAL_AGENT_ID,
});
const { hasPermission, isLoading: permissionsLoading } = useResourcePermissions(
'agent',
basicAgentQuery.data?._id || '',
);
const canEdit = hasPermission(PERMISSION_BITS.EDIT);
const expandedAgentQuery = useGetExpandedAgentByIdQuery(current_agent_id ?? '', {
enabled:
!!(current_agent_id ?? '') &&
current_agent_id !== Constants.EPHEMERAL_AGENT_ID &&
canEdit &&
!permissionsLoading,
});
const agentQuery = canEdit && expandedAgentQuery.data ? expandedAgentQuery : basicAgentQuery;
const models = useMemo(() => modelsQuery.data ?? {}, [modelsQuery.data]);
const methods = useForm<AgentForm>({
defaultValues: getDefaultAgentFormValues(),
@ -183,6 +205,8 @@ export default function AgentPanel({
end_after_tools,
hide_sequential_outputs,
recursion_limit,
category,
support_contact,
} = data;
const model = _model ?? '';
@ -205,6 +229,8 @@ export default function AgentPanel({
end_after_tools,
hide_sequential_outputs,
recursion_limit,
category,
support_contact,
},
});
return;
@ -230,6 +256,8 @@ export default function AgentPanel({
end_after_tools,
hide_sequential_outputs,
recursion_limit,
category,
support_contact,
});
},
[agent_id, create, update, showToast, localize],
@ -242,19 +270,16 @@ export default function AgentPanel({
}, [agent_id, onSelectAgent]);
const canEditAgent = useMemo(() => {
const canEdit =
(agentQuery.data?.isCollaborative ?? false)
? true
: agentQuery.data?.author === user?.id || user?.role === SystemRoles.ADMIN;
if (!agentQuery.data?.id) {
return true;
}
return agentQuery.data?.id != null && agentQuery.data.id ? canEdit : true;
}, [
agentQuery.data?.isCollaborative,
agentQuery.data?.author,
agentQuery.data?.id,
user?.id,
user?.role,
]);
if (agentQuery.data?.author === user?.id || user?.role === SystemRoles.ADMIN) {
return true;
}
return canEdit;
}, [agentQuery.data?.author, agentQuery.data?.id, user?.id, user?.role, canEdit]);
return (
<FormProvider {...methods}>
@ -263,7 +288,7 @@ export default function AgentPanel({
className="scrollbar-gutter-stable h-auto w-full flex-shrink-0 overflow-x-hidden"
aria-label="Agent configuration form"
>
<div className="mt-2 flex w-full flex-wrap gap-2">
<div className="mx-1 mt-2 flex w-full flex-wrap gap-2">
<div className="w-full">
<AgentSelect
createMutation={create}