mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-20 10:20:15 +01:00
feat: add agent roles/permissions
This commit is contained in:
parent
e54352e4c7
commit
2931d1d9cb
5 changed files with 84 additions and 13 deletions
|
|
@ -4,6 +4,7 @@ const {
|
|||
roleDefaults,
|
||||
PermissionTypes,
|
||||
removeNullishValues,
|
||||
agentPermissionsSchema,
|
||||
promptPermissionsSchema,
|
||||
bookmarkPermissionsSchema,
|
||||
} = require('librechat-data-provider');
|
||||
|
|
@ -71,6 +72,7 @@ const updateRoleByName = async function (roleName, updates) {
|
|||
};
|
||||
|
||||
const permissionSchemas = {
|
||||
[PermissionTypes.AGENTS]: agentPermissionsSchema,
|
||||
[PermissionTypes.PROMPTS]: promptPermissionsSchema,
|
||||
[PermissionTypes.BOOKMARKS]: bookmarkPermissionsSchema,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -28,6 +28,20 @@ const roleSchema = new mongoose.Schema({
|
|||
default: true,
|
||||
},
|
||||
},
|
||||
[PermissionTypes.AGENTS]: {
|
||||
[Permissions.SHARED_GLOBAL]: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
[Permissions.USE]: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
[Permissions.CREATE]: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const Role = mongoose.model('Role', roleSchema);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const { nanoid } = require('nanoid');
|
||||
const { FileContext } = require('librechat-data-provider');
|
||||
const { FileContext, Constants } = require('librechat-data-provider');
|
||||
const {
|
||||
getAgent,
|
||||
createAgent,
|
||||
|
|
@ -9,6 +9,7 @@ const {
|
|||
} = require('~/models/Agent');
|
||||
const { getStrategyFunctions } = require('~/server/services/Files/strategies');
|
||||
const { uploadImageBuffer } = require('~/server/services/Files/process');
|
||||
const { getProjectByName } = require('~/models/Project');
|
||||
const { updateAgentProjects } = require('~/models/Agent');
|
||||
const { deleteFileByFilter } = require('~/models/File');
|
||||
const { logger } = require('~/config');
|
||||
|
|
@ -54,16 +55,31 @@ const createAgentHandler = async (req, res) => {
|
|||
* @param {object} req - Express Request
|
||||
* @param {object} req.params - Request params
|
||||
* @param {string} req.params.id - Agent identifier.
|
||||
* @returns {Agent} 200 - success response - application/json
|
||||
* @param {object} req.user - Authenticated user information
|
||||
* @param {string} req.user.id - User ID
|
||||
* @returns {Promise<Agent>} 200 - success response - application/json
|
||||
* @returns {Error} 404 - Agent not found
|
||||
*/
|
||||
const getAgentHandler = async (req, res) => {
|
||||
try {
|
||||
const id = req.params.id;
|
||||
const agent = await getAgent({ id });
|
||||
const author = req.user.id;
|
||||
|
||||
let query = { id, author };
|
||||
|
||||
const globalProject = await getProjectByName(Constants.GLOBAL_PROJECT_NAME, ['agentIds']);
|
||||
if (globalProject && (globalProject.agentIds?.length ?? 0) > 0) {
|
||||
query = {
|
||||
$or: [{ id, $in: globalProject.agentIds }, query],
|
||||
};
|
||||
}
|
||||
|
||||
const agent = await getAgent(query);
|
||||
|
||||
if (!agent) {
|
||||
return res.status(404).json({ error: 'Agent not found' });
|
||||
}
|
||||
|
||||
return res.status(200).json(agent);
|
||||
} catch (error) {
|
||||
logger.error('[/Agents/:id] Error retrieving agent', error);
|
||||
|
|
@ -127,7 +143,7 @@ const deleteAgentHandler = async (req, res) => {
|
|||
* @param {object} req - Express Request
|
||||
* @param {object} req.query - Request query
|
||||
* @param {string} [req.query.user] - The user ID of the agent's author.
|
||||
* @returns {AgentListResponse} 200 - success response - application/json
|
||||
* @returns {Promise<AgentListResponse>} 200 - success response - application/json
|
||||
*/
|
||||
const getListAgentsHandler = async (req, res) => {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,30 @@
|
|||
const multer = require('multer');
|
||||
const express = require('express');
|
||||
const { PermissionTypes, Permissions } = require('librechat-data-provider');
|
||||
const { requireJwtAuth, generateCheckAccess } = require('~/server/middleware');
|
||||
const v1 = require('~/server/controllers/agents/v1');
|
||||
const actions = require('./actions');
|
||||
|
||||
const upload = multer();
|
||||
const router = express.Router();
|
||||
|
||||
const checkAgentAccess = generateCheckAccess(PermissionTypes.AGENTS, [Permissions.USE]);
|
||||
const checkAgentCreate = generateCheckAccess(PermissionTypes.AGENTS, [
|
||||
Permissions.USE,
|
||||
Permissions.CREATE,
|
||||
]);
|
||||
|
||||
const checkGlobalAgentShare = generateCheckAccess(
|
||||
PermissionTypes.AGENTS,
|
||||
[Permissions.USE, Permissions.CREATE],
|
||||
{
|
||||
[Permissions.SHARED_GLOBAL]: ['projectIds', 'removeProjectIds'],
|
||||
},
|
||||
);
|
||||
|
||||
router.use(requireJwtAuth);
|
||||
router.use(checkAgentAccess);
|
||||
|
||||
/**
|
||||
* Agent actions route.
|
||||
* @route GET|POST /agents/actions
|
||||
|
|
@ -27,7 +46,7 @@ router.use('/tools', (req, res) => {
|
|||
* @param {AgentCreateParams} req.body - The agent creation parameters.
|
||||
* @returns {Agent} 201 - Success response - application/json
|
||||
*/
|
||||
router.post('/', v1.createAgent);
|
||||
router.post('/', checkAgentCreate, v1.createAgent);
|
||||
|
||||
/**
|
||||
* Retrieves an agent.
|
||||
|
|
@ -35,7 +54,7 @@ router.post('/', v1.createAgent);
|
|||
* @param {string} req.params.id - Agent identifier.
|
||||
* @returns {Agent} 200 - Success response - application/json
|
||||
*/
|
||||
router.get('/:id', v1.getAgent);
|
||||
router.get('/:id', checkAgentAccess, v1.getAgent);
|
||||
|
||||
/**
|
||||
* Updates an agent.
|
||||
|
|
@ -44,7 +63,7 @@ router.get('/:id', v1.getAgent);
|
|||
* @param {AgentUpdateParams} req.body - The agent update parameters.
|
||||
* @returns {Agent} 200 - Success response - application/json
|
||||
*/
|
||||
router.patch('/:id', v1.updateAgent);
|
||||
router.patch('/:id', checkGlobalAgentShare, v1.updateAgent);
|
||||
|
||||
/**
|
||||
* Deletes an agent.
|
||||
|
|
@ -52,7 +71,7 @@ router.patch('/:id', v1.updateAgent);
|
|||
* @param {string} req.params.id - Agent identifier.
|
||||
* @returns {Agent} 200 - success response - application/json
|
||||
*/
|
||||
router.delete('/:id', v1.deleteAgent);
|
||||
router.delete('/:id', checkAgentCreate, v1.deleteAgent);
|
||||
|
||||
/**
|
||||
* Returns a list of agents.
|
||||
|
|
@ -60,9 +79,7 @@ router.delete('/:id', v1.deleteAgent);
|
|||
* @param {AgentListParams} req.query - The agent list parameters for pagination and sorting.
|
||||
* @returns {AgentListResponse} 200 - success response - application/json
|
||||
*/
|
||||
router.get('/', v1.getListAgents);
|
||||
|
||||
// TODO: handle private agents
|
||||
router.get('/', checkAgentAccess, v1.getListAgents);
|
||||
|
||||
/**
|
||||
* Uploads and updates an avatar for a specific agent.
|
||||
|
|
@ -72,6 +89,6 @@ router.get('/', v1.getListAgents);
|
|||
* @param {string} [req.body.metadata] - Optional metadata for the agent's avatar.
|
||||
* @returns {Object} 200 - success response - application/json
|
||||
*/
|
||||
router.post('/avatar/:agent_id', upload.single('file'), v1.uploadAgentAvatar);
|
||||
router.post('/avatar/:agent_id', checkAgentAccess, upload.single('file'), v1.uploadAgentAvatar);
|
||||
|
||||
module.exports = router;
|
||||
|
|
|
|||
|
|
@ -23,9 +23,13 @@ export enum PermissionTypes {
|
|||
*/
|
||||
PROMPTS = 'PROMPTS',
|
||||
/**
|
||||
* Type for Bookmarks Permissions
|
||||
* Type for Bookmark Permissions
|
||||
*/
|
||||
BOOKMARKS = 'BOOKMARKS',
|
||||
/**
|
||||
* Type for Agent Permissions
|
||||
*/
|
||||
AGENTS = 'AGENTS',
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -49,13 +53,22 @@ export const bookmarkPermissionsSchema = z.object({
|
|||
[Permissions.USE]: z.boolean().default(true),
|
||||
});
|
||||
|
||||
export const agentPermissionsSchema = z.object({
|
||||
[Permissions.SHARED_GLOBAL]: z.boolean().default(false),
|
||||
[Permissions.USE]: z.boolean().default(true),
|
||||
[Permissions.CREATE]: z.boolean().default(true),
|
||||
[Permissions.SHARE]: z.boolean().default(false),
|
||||
});
|
||||
|
||||
export const roleSchema = z.object({
|
||||
name: z.string(),
|
||||
[PermissionTypes.PROMPTS]: promptPermissionsSchema,
|
||||
[PermissionTypes.BOOKMARKS]: bookmarkPermissionsSchema,
|
||||
[PermissionTypes.AGENTS]: agentPermissionsSchema,
|
||||
});
|
||||
|
||||
export type TRole = z.infer<typeof roleSchema>;
|
||||
export type TAgentPermissions = z.infer<typeof agentPermissionsSchema>;
|
||||
export type TPromptPermissions = z.infer<typeof promptPermissionsSchema>;
|
||||
export type TBookmarkPermissions = z.infer<typeof bookmarkPermissionsSchema>;
|
||||
|
||||
|
|
@ -71,11 +84,18 @@ const defaultRolesSchema = z.object({
|
|||
[PermissionTypes.BOOKMARKS]: bookmarkPermissionsSchema.extend({
|
||||
[Permissions.USE]: z.boolean().default(true),
|
||||
}),
|
||||
[PermissionTypes.AGENTS]: agentPermissionsSchema.extend({
|
||||
[Permissions.SHARED_GLOBAL]: z.boolean().default(true),
|
||||
[Permissions.USE]: z.boolean().default(true),
|
||||
[Permissions.CREATE]: z.boolean().default(true),
|
||||
[Permissions.SHARE]: z.boolean().default(true),
|
||||
}),
|
||||
}),
|
||||
[SystemRoles.USER]: roleSchema.extend({
|
||||
name: z.literal(SystemRoles.USER),
|
||||
[PermissionTypes.PROMPTS]: promptPermissionsSchema,
|
||||
[PermissionTypes.BOOKMARKS]: bookmarkPermissionsSchema,
|
||||
[PermissionTypes.AGENTS]: agentPermissionsSchema,
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
@ -84,10 +104,12 @@ export const roleDefaults = defaultRolesSchema.parse({
|
|||
name: SystemRoles.ADMIN,
|
||||
[PermissionTypes.PROMPTS]: {},
|
||||
[PermissionTypes.BOOKMARKS]: {},
|
||||
[PermissionTypes.AGENTS]: {},
|
||||
},
|
||||
[SystemRoles.USER]: {
|
||||
name: SystemRoles.USER,
|
||||
[PermissionTypes.PROMPTS]: {},
|
||||
[PermissionTypes.BOOKMARKS]: {},
|
||||
[PermissionTypes.AGENTS]: {},
|
||||
},
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue