mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-20 10:20:15 +01:00
💽 fix: Memory Permissions Handling (#9701)
This commit is contained in:
parent
81139046e5
commit
3fec63e597
2 changed files with 164 additions and 15 deletions
|
|
@ -1311,6 +1311,142 @@ describe('updateInterfacePermissions - permissions', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should re-enable memory permissions when memory.disabled changes from true to false', async () => {
|
||||||
|
// Mock existing memory permissions that are disabled
|
||||||
|
mockGetRoleByName.mockResolvedValue({
|
||||||
|
permissions: {
|
||||||
|
[PermissionTypes.MEMORIES]: {
|
||||||
|
[Permissions.USE]: false,
|
||||||
|
[Permissions.CREATE]: false,
|
||||||
|
[Permissions.READ]: false,
|
||||||
|
[Permissions.UPDATE]: false,
|
||||||
|
[Permissions.OPT_OUT]: false,
|
||||||
|
},
|
||||||
|
// Other existing permissions
|
||||||
|
[PermissionTypes.PROMPTS]: { [Permissions.USE]: true },
|
||||||
|
[PermissionTypes.BOOKMARKS]: { [Permissions.USE]: true },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
interface: {
|
||||||
|
// Not explicitly configuring memories in interface
|
||||||
|
prompts: true,
|
||||||
|
bookmarks: true,
|
||||||
|
},
|
||||||
|
memory: {
|
||||||
|
disabled: false, // Memory is explicitly enabled (changed from true to false)
|
||||||
|
agent: {
|
||||||
|
id: 'test-agent-id',
|
||||||
|
},
|
||||||
|
personalize: true,
|
||||||
|
} as unknown as TCustomConfig['memory'],
|
||||||
|
};
|
||||||
|
const configDefaults = {
|
||||||
|
interface: {
|
||||||
|
memories: true,
|
||||||
|
prompts: true,
|
||||||
|
bookmarks: true,
|
||||||
|
},
|
||||||
|
} as TConfigDefaults;
|
||||||
|
const interfaceConfig = await loadDefaultInterface({ config, configDefaults });
|
||||||
|
const appConfig = { config, interfaceConfig } as unknown as AppConfig;
|
||||||
|
|
||||||
|
await updateInterfacePermissions({
|
||||||
|
appConfig,
|
||||||
|
getRoleByName: mockGetRoleByName,
|
||||||
|
updateAccessPermissions: mockUpdateAccessPermissions,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check USER role call
|
||||||
|
const userCall = mockUpdateAccessPermissions.mock.calls.find(
|
||||||
|
(call) => call[0] === SystemRoles.USER,
|
||||||
|
);
|
||||||
|
// Memory permissions should be re-enabled
|
||||||
|
expect(userCall[1][PermissionTypes.MEMORIES]).toEqual({
|
||||||
|
[Permissions.USE]: true,
|
||||||
|
[Permissions.CREATE]:
|
||||||
|
roleDefaults[SystemRoles.USER].permissions[PermissionTypes.MEMORIES]?.[Permissions.CREATE],
|
||||||
|
[Permissions.READ]:
|
||||||
|
roleDefaults[SystemRoles.USER].permissions[PermissionTypes.MEMORIES]?.[Permissions.READ],
|
||||||
|
[Permissions.UPDATE]:
|
||||||
|
roleDefaults[SystemRoles.USER].permissions[PermissionTypes.MEMORIES]?.[Permissions.UPDATE],
|
||||||
|
[Permissions.OPT_OUT]: true, // Should be true when personalize is enabled
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check ADMIN role call
|
||||||
|
const adminCall = mockUpdateAccessPermissions.mock.calls.find(
|
||||||
|
(call) => call[0] === SystemRoles.ADMIN,
|
||||||
|
);
|
||||||
|
expect(adminCall[1][PermissionTypes.MEMORIES]).toEqual({
|
||||||
|
[Permissions.USE]: true,
|
||||||
|
[Permissions.CREATE]:
|
||||||
|
roleDefaults[SystemRoles.ADMIN].permissions[PermissionTypes.MEMORIES]?.[Permissions.CREATE],
|
||||||
|
[Permissions.READ]:
|
||||||
|
roleDefaults[SystemRoles.ADMIN].permissions[PermissionTypes.MEMORIES]?.[Permissions.READ],
|
||||||
|
[Permissions.UPDATE]:
|
||||||
|
roleDefaults[SystemRoles.ADMIN].permissions[PermissionTypes.MEMORIES]?.[Permissions.UPDATE],
|
||||||
|
[Permissions.OPT_OUT]: true, // Should be true when personalize is enabled
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verify the existing role data was passed to updateAccessPermissions
|
||||||
|
expect(userCall[2]).toMatchObject({
|
||||||
|
permissions: expect.objectContaining({
|
||||||
|
[PermissionTypes.MEMORIES]: expect.any(Object),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should re-enable memory permissions when valid memory config exists without disabled field', async () => {
|
||||||
|
// Mock existing memory permissions that are disabled
|
||||||
|
mockGetRoleByName.mockResolvedValue({
|
||||||
|
permissions: {
|
||||||
|
[PermissionTypes.MEMORIES]: {
|
||||||
|
[Permissions.USE]: false,
|
||||||
|
[Permissions.CREATE]: false,
|
||||||
|
[Permissions.READ]: false,
|
||||||
|
[Permissions.UPDATE]: false,
|
||||||
|
[Permissions.OPT_OUT]: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
memory: {
|
||||||
|
// No disabled field, but valid config
|
||||||
|
agent: {
|
||||||
|
id: 'test-agent-id',
|
||||||
|
provider: 'openai',
|
||||||
|
},
|
||||||
|
personalize: false,
|
||||||
|
} as unknown as TCustomConfig['memory'],
|
||||||
|
};
|
||||||
|
const configDefaults = { interface: {} } as TConfigDefaults;
|
||||||
|
const interfaceConfig = await loadDefaultInterface({ config, configDefaults });
|
||||||
|
const appConfig = { config, interfaceConfig } as unknown as AppConfig;
|
||||||
|
|
||||||
|
await updateInterfacePermissions({
|
||||||
|
appConfig,
|
||||||
|
getRoleByName: mockGetRoleByName,
|
||||||
|
updateAccessPermissions: mockUpdateAccessPermissions,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check USER role call - memory should be re-enabled
|
||||||
|
const userCall = mockUpdateAccessPermissions.mock.calls.find(
|
||||||
|
(call) => call[0] === SystemRoles.USER,
|
||||||
|
);
|
||||||
|
expect(userCall[1][PermissionTypes.MEMORIES]).toEqual({
|
||||||
|
[Permissions.USE]: true,
|
||||||
|
[Permissions.CREATE]:
|
||||||
|
roleDefaults[SystemRoles.USER].permissions[PermissionTypes.MEMORIES]?.[Permissions.CREATE],
|
||||||
|
[Permissions.READ]:
|
||||||
|
roleDefaults[SystemRoles.USER].permissions[PermissionTypes.MEMORIES]?.[Permissions.READ],
|
||||||
|
[Permissions.UPDATE]:
|
||||||
|
roleDefaults[SystemRoles.USER].permissions[PermissionTypes.MEMORIES]?.[Permissions.UPDATE],
|
||||||
|
[Permissions.OPT_OUT]: undefined, // Should be undefined when personalize is false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should override existing memory permissions when memory.disabled is true', async () => {
|
it('should override existing memory permissions when memory.disabled is true', async () => {
|
||||||
// Mock existing memory permissions that are enabled
|
// Mock existing memory permissions that are enabled
|
||||||
mockGetRoleByName.mockResolvedValue({
|
mockGetRoleByName.mockResolvedValue({
|
||||||
|
|
|
||||||
|
|
@ -69,8 +69,12 @@ export async function updateInterfacePermissions({
|
||||||
const interfaceConfig = appConfig?.config?.interface;
|
const interfaceConfig = appConfig?.config?.interface;
|
||||||
const memoryConfig = appConfig?.config?.memory;
|
const memoryConfig = appConfig?.config?.memory;
|
||||||
const memoryEnabled = isMemoryEnabled(memoryConfig);
|
const memoryEnabled = isMemoryEnabled(memoryConfig);
|
||||||
/** Check if memory is explicitly disabled */
|
/** Check if memory is explicitly disabled (memory.disabled === true) */
|
||||||
const isMemoryExplicitlyDisabled = memoryConfig && !memoryEnabled;
|
const isMemoryExplicitlyDisabled = memoryConfig?.disabled === true;
|
||||||
|
/** Check if memory should be enabled (explicitly enabled or valid config) */
|
||||||
|
const shouldEnableMemory =
|
||||||
|
memoryConfig?.disabled === false ||
|
||||||
|
(memoryConfig && memoryEnabled && memoryConfig.disabled === undefined);
|
||||||
/** Check if personalization is enabled (defaults to true if memory is configured and enabled) */
|
/** Check if personalization is enabled (defaults to true if memory is configured and enabled) */
|
||||||
const isPersonalizationEnabled =
|
const isPersonalizationEnabled =
|
||||||
memoryConfig && memoryEnabled && memoryConfig.personalize !== false;
|
memoryConfig && memoryEnabled && memoryConfig.personalize !== false;
|
||||||
|
|
@ -111,19 +115,24 @@ export async function updateInterfacePermissions({
|
||||||
const permTypeExists = existingPermissions?.[permType];
|
const permTypeExists = existingPermissions?.[permType];
|
||||||
const isExplicitlyConfigured =
|
const isExplicitlyConfigured =
|
||||||
interfaceConfig && hasExplicitConfig(interfaceConfig, permType);
|
interfaceConfig && hasExplicitConfig(interfaceConfig, permType);
|
||||||
const isMemoryDisabled =
|
const isMemoryDisabled = permType === PermissionTypes.MEMORIES && isMemoryExplicitlyDisabled;
|
||||||
permType === PermissionTypes.MEMORIES && isMemoryExplicitlyDisabled === true;
|
const isMemoryReenabling =
|
||||||
|
permType === PermissionTypes.MEMORIES &&
|
||||||
|
shouldEnableMemory &&
|
||||||
|
existingPermissions?.[PermissionTypes.MEMORIES]?.[Permissions.USE] === false;
|
||||||
|
|
||||||
// Only update if: doesn't exist OR explicitly configured
|
// Only update if: doesn't exist OR explicitly configured OR memory state change
|
||||||
if (!permTypeExists || isExplicitlyConfigured || isMemoryDisabled) {
|
if (!permTypeExists || isExplicitlyConfigured || isMemoryDisabled || isMemoryReenabling) {
|
||||||
permissionsToUpdate[permType] = permissions;
|
permissionsToUpdate[permType] = permissions;
|
||||||
if (!permTypeExists) {
|
if (!permTypeExists) {
|
||||||
logger.debug(`Role '${roleName}': Setting up default permissions for '${permType}'`);
|
logger.debug(`Role '${roleName}': Setting up default permissions for '${permType}'`);
|
||||||
} else if (isExplicitlyConfigured) {
|
} else if (isExplicitlyConfigured) {
|
||||||
logger.debug(`Role '${roleName}': Applying explicit config for '${permType}'`);
|
logger.debug(`Role '${roleName}': Applying explicit config for '${permType}'`);
|
||||||
} else if (isMemoryDisabled) {
|
} else if (isMemoryDisabled) {
|
||||||
|
logger.debug(`Role '${roleName}': Disabling memories as memory.disabled is true`);
|
||||||
|
} else if (isMemoryReenabling) {
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`Role '${roleName}': Disabling memories as it is explicitly disabled in config`,
|
`Role '${roleName}': Re-enabling memories due to valid memory configuration`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -147,13 +156,15 @@ export async function updateInterfacePermissions({
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
[PermissionTypes.MEMORIES]: {
|
[PermissionTypes.MEMORIES]: {
|
||||||
[Permissions.USE]: isMemoryExplicitlyDisabled
|
[Permissions.USE]: (() => {
|
||||||
? false
|
if (isMemoryExplicitlyDisabled) return false;
|
||||||
: getPermissionValue(
|
if (shouldEnableMemory) return true;
|
||||||
|
return getPermissionValue(
|
||||||
loadedInterface.memories,
|
loadedInterface.memories,
|
||||||
defaultPerms[PermissionTypes.MEMORIES]?.[Permissions.USE],
|
defaultPerms[PermissionTypes.MEMORIES]?.[Permissions.USE],
|
||||||
defaults.memories,
|
defaults.memories,
|
||||||
),
|
);
|
||||||
|
})(),
|
||||||
...(defaultPerms[PermissionTypes.MEMORIES]?.[Permissions.CREATE] !== undefined && {
|
...(defaultPerms[PermissionTypes.MEMORIES]?.[Permissions.CREATE] !== undefined && {
|
||||||
[Permissions.CREATE]: isMemoryExplicitlyDisabled
|
[Permissions.CREATE]: isMemoryExplicitlyDisabled
|
||||||
? false
|
? false
|
||||||
|
|
@ -169,7 +180,9 @@ export async function updateInterfacePermissions({
|
||||||
? false
|
? false
|
||||||
: defaultPerms[PermissionTypes.MEMORIES][Permissions.UPDATE],
|
: defaultPerms[PermissionTypes.MEMORIES][Permissions.UPDATE],
|
||||||
}),
|
}),
|
||||||
[Permissions.OPT_OUT]: isPersonalizationEnabled,
|
[Permissions.OPT_OUT]: isMemoryExplicitlyDisabled
|
||||||
|
? false
|
||||||
|
: isPersonalizationEnabled || undefined,
|
||||||
},
|
},
|
||||||
[PermissionTypes.MULTI_CONVO]: {
|
[PermissionTypes.MULTI_CONVO]: {
|
||||||
[Permissions.USE]: getPermissionValue(
|
[Permissions.USE]: getPermissionValue(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue