| import { logger } from '@librechat/data-schemas'; |
| import { AccessRoleIds, ResourceType, PrincipalType, Constants } from 'librechat-data-provider'; |
| import { ensureRequiredCollectionsExist } from '../db/utils'; |
| import type { AccessRoleMethods, IAgent } from '@librechat/data-schemas'; |
| import type { Model, Mongoose } from 'mongoose'; |
|
|
| const { GLOBAL_PROJECT_NAME } = Constants; |
|
|
| export interface MigrationCheckDbMethods { |
| findRoleByIdentifier: AccessRoleMethods['findRoleByIdentifier']; |
| getProjectByName: ( |
| projectName: string, |
| fieldsToSelect?: string[] | null, |
| ) => Promise<{ |
| agentIds?: string[]; |
| [key: string]: unknown; |
| } | null>; |
| } |
|
|
| export interface MigrationCheckParams { |
| mongoose: Mongoose; |
| methods: MigrationCheckDbMethods; |
| AgentModel: Model<IAgent>; |
| } |
|
|
| interface AgentMigrationData { |
| _id: string; |
| id: string; |
| name: string; |
| author: string; |
| isCollaborative: boolean; |
| } |
|
|
| export interface MigrationCheckResult { |
| totalToMigrate: number; |
| globalEditAccess: number; |
| globalViewAccess: number; |
| privateAgents: number; |
| details?: { |
| globalEditAccess: Array<{ name: string; id: string }>; |
| globalViewAccess: Array<{ name: string; id: string }>; |
| privateAgents: Array<{ name: string; id: string }>; |
| }; |
| } |
|
|
| |
| |
| |
| |
| export async function checkAgentPermissionsMigration({ |
| methods, |
| mongoose, |
| AgentModel, |
| }: MigrationCheckParams): Promise<MigrationCheckResult> { |
| logger.debug('Checking if agent permissions migration is needed'); |
|
|
| try { |
| const db = mongoose.connection.db; |
| if (db) { |
| await ensureRequiredCollectionsExist(db); |
| } |
|
|
| |
| const ownerRole = await methods.findRoleByIdentifier(AccessRoleIds.AGENT_OWNER); |
| const viewerRole = await methods.findRoleByIdentifier(AccessRoleIds.AGENT_VIEWER); |
| const editorRole = await methods.findRoleByIdentifier(AccessRoleIds.AGENT_EDITOR); |
|
|
| if (!ownerRole || !viewerRole || !editorRole) { |
| logger.warn( |
| 'Required agent roles not found. Permission system may not be fully initialized.', |
| ); |
| return { |
| totalToMigrate: 0, |
| globalEditAccess: 0, |
| globalViewAccess: 0, |
| privateAgents: 0, |
| }; |
| } |
|
|
| |
| const globalProject = await methods.getProjectByName(GLOBAL_PROJECT_NAME, ['agentIds']); |
| const globalAgentIds = new Set(globalProject?.agentIds || []); |
|
|
| |
| const agentsToMigrate: AgentMigrationData[] = await AgentModel.aggregate([ |
| { |
| $lookup: { |
| from: 'aclentries', |
| localField: '_id', |
| foreignField: 'resourceId', |
| as: 'aclEntries', |
| }, |
| }, |
| { |
| $addFields: { |
| userAclEntries: { |
| $filter: { |
| input: '$aclEntries', |
| as: 'aclEntry', |
| cond: { |
| $and: [ |
| { $eq: ['$$aclEntry.resourceType', ResourceType.AGENT] }, |
| { $eq: ['$$aclEntry.principalType', PrincipalType.USER] }, |
| ], |
| }, |
| }, |
| }, |
| }, |
| }, |
| { |
| $match: { |
| author: { $exists: true, $ne: null }, |
| userAclEntries: { $size: 0 }, |
| }, |
| }, |
| { |
| $project: { |
| _id: 1, |
| id: 1, |
| name: 1, |
| author: 1, |
| isCollaborative: 1, |
| }, |
| }, |
| ]); |
|
|
| const categories: { |
| globalEditAccess: AgentMigrationData[]; |
| globalViewAccess: AgentMigrationData[]; |
| privateAgents: AgentMigrationData[]; |
| } = { |
| globalEditAccess: [], |
| globalViewAccess: [], |
| privateAgents: [], |
| }; |
|
|
| agentsToMigrate.forEach((agent) => { |
| const isGlobal = globalAgentIds.has(agent.id); |
| const isCollab = agent.isCollaborative; |
|
|
| if (isGlobal && isCollab) { |
| categories.globalEditAccess.push(agent); |
| } else if (isGlobal && !isCollab) { |
| categories.globalViewAccess.push(agent); |
| } else { |
| categories.privateAgents.push(agent); |
| } |
| }); |
|
|
| const result: MigrationCheckResult = { |
| totalToMigrate: agentsToMigrate.length, |
| globalEditAccess: categories.globalEditAccess.length, |
| globalViewAccess: categories.globalViewAccess.length, |
| privateAgents: categories.privateAgents.length, |
| }; |
|
|
| |
| if (agentsToMigrate.length > 0) { |
| result.details = { |
| globalEditAccess: categories.globalEditAccess.map((a) => ({ |
| name: a.name, |
| id: a.id, |
| })), |
| globalViewAccess: categories.globalViewAccess.map((a) => ({ |
| name: a.name, |
| id: a.id, |
| })), |
| privateAgents: categories.privateAgents.map((a) => ({ |
| name: a.name, |
| id: a.id, |
| })), |
| }; |
| } |
|
|
| logger.debug('Agent migration check completed', { |
| totalToMigrate: result.totalToMigrate, |
| globalEditAccess: result.globalEditAccess, |
| globalViewAccess: result.globalViewAccess, |
| privateAgents: result.privateAgents, |
| }); |
|
|
| return result; |
| } catch (error) { |
| logger.error('Failed to check agent permissions migration', error); |
| |
| return { |
| totalToMigrate: 0, |
| globalEditAccess: 0, |
| globalViewAccess: 0, |
| privateAgents: 0, |
| }; |
| } |
| } |
|
|
| |
| |
| |
| export function logAgentMigrationWarning(result: MigrationCheckResult): void { |
| if (result.totalToMigrate === 0) { |
| return; |
| } |
|
|
| |
| const border = '='.repeat(80); |
| const warning = [ |
| '', |
| border, |
| ' IMPORTANT: AGENT PERMISSIONS MIGRATION REQUIRED', |
| border, |
| '', |
| ` Total agents to migrate: ${result.totalToMigrate}`, |
| ` - Global Edit Access: ${result.globalEditAccess} agents`, |
| ` - Global View Access: ${result.globalViewAccess} agents`, |
| ` - Private Agents: ${result.privateAgents} agents`, |
| '', |
| ' The new agent sharing system requires migrating existing agents.', |
| ' Please run the following command to migrate your agents:', |
| '', |
| ' npm run migrate:agent-permissions', |
| '', |
| ' For a dry run (preview) of what will be migrated:', |
| '', |
| ' npm run migrate:agent-permissions:dry-run', |
| '', |
| ' This migration will:', |
| ' 1. Grant owner permissions to agent authors', |
| ' 2. Set appropriate public permissions based on global project status', |
| ' 3. Preserve existing collaborative settings', |
| '', |
| border, |
| '', |
| ]; |
|
|
| |
| console.log('\n' + warning.join('\n') + '\n'); |
|
|
| |
| logger.warn('Agent permissions migration required', { |
| totalToMigrate: result.totalToMigrate, |
| globalEditAccess: result.globalEditAccess, |
| globalViewAccess: result.globalViewAccess, |
| privateAgents: result.privateAgents, |
| }); |
| } |
|
|