diff --git a/api/models/Role.js b/api/models/Role.js index 62ec8dfe29..9c160512b7 100644 --- a/api/models/Role.js +++ b/api/models/Role.js @@ -7,6 +7,7 @@ const { agentPermissionsSchema, promptPermissionsSchema, bookmarkPermissionsSchema, + multiConvoPermissionsSchema, } = require('librechat-data-provider'); const getLogStores = require('~/cache/getLogStores'); const Role = require('~/models/schema/roleSchema'); @@ -75,6 +76,7 @@ const permissionSchemas = { [PermissionTypes.AGENTS]: agentPermissionsSchema, [PermissionTypes.PROMPTS]: promptPermissionsSchema, [PermissionTypes.BOOKMARKS]: bookmarkPermissionsSchema, + [PermissionTypes.MULTI_CONVO]: multiConvoPermissionsSchema, }; /** diff --git a/api/models/Role.spec.js b/api/models/Role.spec.js index 753df77e67..92386f0fa9 100644 --- a/api/models/Role.spec.js +++ b/api/models/Role.spec.js @@ -199,6 +199,75 @@ describe('updateAccessPermissions', () => { SHARED_GLOBAL: true, }); }); + + it('should update MULTI_CONVO permissions', async () => { + await new Role({ + name: SystemRoles.USER, + [PermissionTypes.MULTI_CONVO]: { + USE: false, + }, + }).save(); + + await updateAccessPermissions(SystemRoles.USER, { + [PermissionTypes.MULTI_CONVO]: { + USE: true, + }, + }); + + const updatedRole = await Role.findOne({ name: SystemRoles.USER }).lean(); + expect(updatedRole[PermissionTypes.MULTI_CONVO]).toEqual({ + USE: true, + }); + }); + + it('should update MULTI_CONVO permissions along with other permission types', async () => { + await new Role({ + name: SystemRoles.USER, + [PermissionTypes.PROMPTS]: { + CREATE: true, + USE: true, + SHARED_GLOBAL: false, + }, + [PermissionTypes.MULTI_CONVO]: { + USE: false, + }, + }).save(); + + await updateAccessPermissions(SystemRoles.USER, { + [PermissionTypes.PROMPTS]: { SHARED_GLOBAL: true }, + [PermissionTypes.MULTI_CONVO]: { USE: true }, + }); + + const updatedRole = await Role.findOne({ name: SystemRoles.USER }).lean(); + expect(updatedRole[PermissionTypes.PROMPTS]).toEqual({ + CREATE: true, + USE: true, + SHARED_GLOBAL: true, + }); + expect(updatedRole[PermissionTypes.MULTI_CONVO]).toEqual({ + USE: true, + }); + }); + + it('should not update MULTI_CONVO permissions when no changes are needed', async () => { + await new Role({ + name: SystemRoles.USER, + [PermissionTypes.MULTI_CONVO]: { + USE: true, + }, + }).save(); + + await updateAccessPermissions(SystemRoles.USER, { + [PermissionTypes.MULTI_CONVO]: { + USE: true, + }, + }); + + const updatedRole = await Role.findOne({ name: SystemRoles.USER }).lean(); + expect(updatedRole[PermissionTypes.MULTI_CONVO]).toEqual({ + USE: true, + }); + }); }); describe('initializeRoles', () => { @@ -313,4 +382,39 @@ describe('initializeRoles', () => { expect(adminRole[PermissionTypes.AGENTS].USE).toBeDefined(); expect(adminRole[PermissionTypes.AGENTS].SHARED_GLOBAL).toBeDefined(); }); + + it('should include MULTI_CONVO permissions when creating default roles', async () => { + await initializeRoles(); + + const adminRole = await Role.findOne({ name: SystemRoles.ADMIN }).lean(); + const userRole = await Role.findOne({ name: SystemRoles.USER }).lean(); + + expect(adminRole[PermissionTypes.MULTI_CONVO]).toBeDefined(); + expect(userRole[PermissionTypes.MULTI_CONVO]).toBeDefined(); + + // Check if MULTI_CONVO permissions match defaults + expect(adminRole[PermissionTypes.MULTI_CONVO].USE).toBe( + roleDefaults[SystemRoles.ADMIN][PermissionTypes.MULTI_CONVO].USE, + ); + expect(userRole[PermissionTypes.MULTI_CONVO].USE).toBe( + roleDefaults[SystemRoles.USER][PermissionTypes.MULTI_CONVO].USE, + ); + }); + + it('should add MULTI_CONVO permissions to existing roles without them', async () => { + const partialUserRole = { + name: SystemRoles.USER, + [PermissionTypes.PROMPTS]: roleDefaults[SystemRoles.USER][PermissionTypes.PROMPTS], + [PermissionTypes.BOOKMARKS]: roleDefaults[SystemRoles.USER][PermissionTypes.BOOKMARKS], + }; + + await new Role(partialUserRole).save(); + + await initializeRoles(); + + const userRole = await Role.findOne({ name: SystemRoles.USER }).lean(); + + expect(userRole[PermissionTypes.MULTI_CONVO]).toBeDefined(); + expect(userRole[PermissionTypes.MULTI_CONVO].USE).toBeDefined(); + }); }); diff --git a/api/models/schema/roleSchema.js b/api/models/schema/roleSchema.js index b0cbeb8c2c..36e9d3f7b6 100644 --- a/api/models/schema/roleSchema.js +++ b/api/models/schema/roleSchema.js @@ -42,6 +42,12 @@ const roleSchema = new mongoose.Schema({ default: true, }, }, + [PermissionTypes.MULTI_CONVO]: { + [Permissions.USE]: { + type: Boolean, + default: true, + }, + }, }); const Role = mongoose.model('Role', roleSchema); diff --git a/api/server/services/start/interface.js b/api/server/services/start/interface.js index 314babbcf5..54e8b38237 100644 --- a/api/server/services/start/interface.js +++ b/api/server/services/start/interface.js @@ -31,11 +31,13 @@ async function loadDefaultInterface(config, configDefaults, roleName = SystemRol termsOfService: interfaceConfig?.termsOfService ?? defaults.termsOfService, bookmarks: interfaceConfig?.bookmarks ?? defaults.bookmarks, prompts: interfaceConfig?.prompts ?? defaults.prompts, + multiConvo: interfaceConfig?.multiConvo ?? defaults.multiConvo, }); await updateAccessPermissions(roleName, { [PermissionTypes.PROMPTS]: { [Permissions.USE]: loadedInterface.prompts }, [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: loadedInterface.bookmarks }, + [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: loadedInterface.multiConvo }, }); let i = 0; diff --git a/api/server/services/start/interface.spec.js b/api/server/services/start/interface.spec.js index 2009e043cc..62239a6a29 100644 --- a/api/server/services/start/interface.spec.js +++ b/api/server/services/start/interface.spec.js @@ -16,6 +16,7 @@ describe('loadDefaultInterface', () => { expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, { [PermissionTypes.PROMPTS]: { [Permissions.USE]: true }, [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: true }, + [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: undefined }, }); }); @@ -28,6 +29,7 @@ describe('loadDefaultInterface', () => { expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, { [PermissionTypes.PROMPTS]: { [Permissions.USE]: false }, [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: false }, + [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: undefined }, }); }); @@ -40,6 +42,7 @@ describe('loadDefaultInterface', () => { expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, { [PermissionTypes.PROMPTS]: { [Permissions.USE]: undefined }, [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: undefined }, + [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: undefined }, }); }); @@ -52,6 +55,7 @@ describe('loadDefaultInterface', () => { expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, { [PermissionTypes.PROMPTS]: { [Permissions.USE]: undefined }, [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: undefined }, + [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: undefined }, }); }); @@ -64,6 +68,7 @@ describe('loadDefaultInterface', () => { expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, { [PermissionTypes.PROMPTS]: { [Permissions.USE]: true }, [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: false }, + [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: undefined }, }); }); @@ -76,6 +81,72 @@ describe('loadDefaultInterface', () => { expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, { [PermissionTypes.PROMPTS]: { [Permissions.USE]: true }, [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: true }, + [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: undefined }, + }); + }); + + it('should call updateAccessPermissions with the correct parameters when multiConvo is true', async () => { + const config = { interface: { multiConvo: true } }; + const configDefaults = { interface: {} }; + + await loadDefaultInterface(config, configDefaults); + + expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, { + [PermissionTypes.PROMPTS]: { [Permissions.USE]: undefined }, + [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: undefined }, + [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: true }, + }); + }); + + it('should call updateAccessPermissions with false when multiConvo is false', async () => { + const config = { interface: { multiConvo: false } }; + const configDefaults = { interface: {} }; + + await loadDefaultInterface(config, configDefaults); + + expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, { + [PermissionTypes.PROMPTS]: { [Permissions.USE]: undefined }, + [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: undefined }, + [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: false }, + }); + }); + + it('should call updateAccessPermissions with undefined when multiConvo is not specified in config', async () => { + const config = {}; + const configDefaults = { interface: {} }; + + await loadDefaultInterface(config, configDefaults); + + expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, { + [PermissionTypes.PROMPTS]: { [Permissions.USE]: undefined }, + [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: undefined }, + [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: undefined }, + }); + }); + + it('should call updateAccessPermissions with all interface options including multiConvo', async () => { + const config = { interface: { prompts: true, bookmarks: false, multiConvo: true } }; + const configDefaults = { interface: {} }; + + await loadDefaultInterface(config, configDefaults); + + expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, { + [PermissionTypes.PROMPTS]: { [Permissions.USE]: true }, + [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: false }, + [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: true }, + }); + }); + + it('should use default values for multiConvo when config is undefined', async () => { + const config = undefined; + const configDefaults = { interface: { prompts: true, bookmarks: true, multiConvo: false } }; + + await loadDefaultInterface(config, configDefaults); + + expect(updateAccessPermissions).toHaveBeenCalledWith(SystemRoles.USER, { + [PermissionTypes.PROMPTS]: { [Permissions.USE]: true }, + [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: true }, + [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: false }, }); }); }); diff --git a/client/src/components/Chat/Header.tsx b/client/src/components/Chat/Header.tsx index 759fa57b02..4333dc393e 100644 --- a/client/src/components/Chat/Header.tsx +++ b/client/src/components/Chat/Header.tsx @@ -26,6 +26,11 @@ export default function Header() { permission: Permissions.USE, }); + const hasAccessToMultiConvo = useHasAccess({ + permissionType: PermissionTypes.MULTI_CONVO, + permission: Permissions.USE, + }); + const isSmallScreen = useMediaQuery('(max-width: 768px)'); return ( @@ -38,7 +43,7 @@ export default function Header() { {} {interfaceConfig.presets === true && } {hasAccessToBookmarks === true && } - + {hasAccessToMultiConvo === true && } {isSmallScreen && ( ; + content: Array | undefined; messageId: string; isCreatedByUser: boolean; isLast: boolean; @@ -12,6 +12,9 @@ type ContentPartsProps = { const ContentParts = memo( ({ content, messageId, isCreatedByUser, isLast, isSubmitting }: ContentPartsProps) => { + if (!content) { + return null; + } return ( <> {content diff --git a/client/src/components/Nav/SettingsTabs/Beta/CodeArtifacts.tsx b/client/src/components/Nav/SettingsTabs/Beta/CodeArtifacts.tsx index 804899cedd..a37b96866c 100644 --- a/client/src/components/Nav/SettingsTabs/Beta/CodeArtifacts.tsx +++ b/client/src/components/Nav/SettingsTabs/Beta/CodeArtifacts.tsx @@ -1,5 +1,5 @@ import { useRecoilState } from 'recoil'; -import HoverCardSettings from '../HoverCardSettings'; +import HoverCardSettings from '~/components/Nav/SettingsTabs/HoverCardSettings'; import { Switch } from '~/components/ui'; import { useLocalize } from '~/hooks'; import store from '~/store'; diff --git a/client/src/components/Nav/SettingsTabs/Commands/Commands.tsx b/client/src/components/Nav/SettingsTabs/Commands/Commands.tsx index a67cbbada1..bbec995aa3 100644 --- a/client/src/components/Nav/SettingsTabs/Commands/Commands.tsx +++ b/client/src/components/Nav/SettingsTabs/Commands/Commands.tsx @@ -1,26 +1,52 @@ import { memo } from 'react'; import * as Tabs from '@radix-ui/react-tabs'; -import { SettingsTabValues } from 'librechat-data-provider'; +import { SettingsTabValues, PermissionTypes, Permissions } from 'librechat-data-provider'; +import HoverCardSettings from '~/components/Nav/SettingsTabs/HoverCardSettings'; +import { useLocalize, useHasAccess } from '~/hooks'; import SlashCommandSwitch from './SlashCommandSwitch'; import PlusCommandSwitch from './PlusCommandSwitch'; import AtCommandSwitch from './AtCommandSwitch'; function Commands() { + const localize = useLocalize(); + + const hasAccessToPrompts = useHasAccess({ + permissionType: PermissionTypes.PROMPTS, + permission: Permissions.USE, + }); + + const hasAccessToMultiConvo = useHasAccess({ + permissionType: PermissionTypes.MULTI_CONVO, + permission: Permissions.USE, + }); + return ( -
-
- +
+
+

+ {localize('com_nav_chat_commands')} +

+
-
- -
-
- +
+
+ +
+ {hasAccessToMultiConvo === true && ( +
+ +
+ )} + {hasAccessToPrompts === true && ( +
+ +
+ )}
diff --git a/client/src/components/Nav/SettingsTabs/HoverCardSettings.tsx b/client/src/components/Nav/SettingsTabs/HoverCardSettings.tsx index 0e267c0778..27d4ba7db5 100644 --- a/client/src/components/Nav/SettingsTabs/HoverCardSettings.tsx +++ b/client/src/components/Nav/SettingsTabs/HoverCardSettings.tsx @@ -9,12 +9,12 @@ const HoverCardSettings = ({ side, text }) => { return ( - {' '} + {' '}
-

{localize(text)}

+

{localize(text)}

diff --git a/client/src/hooks/Input/useHandleKeyUp.ts b/client/src/hooks/Input/useHandleKeyUp.ts index 98f6e77eb6..5990df2408 100644 --- a/client/src/hooks/Input/useHandleKeyUp.ts +++ b/client/src/hooks/Input/useHandleKeyUp.ts @@ -46,10 +46,14 @@ const useHandleKeyUp = ({ setShowPlusPopover: SetterOrUpdater; setShowMentionPopover: SetterOrUpdater; }) => { - const hasAccess = useHasAccess({ + const hasPromptsAccess = useHasAccess({ permissionType: PermissionTypes.PROMPTS, permission: Permissions.USE, }); + const hasMultiConvoAccess = useHasAccess({ + permissionType: PermissionTypes.MULTI_CONVO, + permission: Permissions.USE, + }); const setShowPromptsPopover = useSetRecoilState(store.showPromptsPopoverFamily(index)); // Get the current state of command toggles @@ -64,19 +68,22 @@ const useHandleKeyUp = ({ }, [textAreaRef, setShowMentionPopover, atCommandEnabled]); const handlePlusCommand = useCallback(() => { - if (plusCommandEnabled && shouldTriggerCommand(textAreaRef, '+')) { + if (!hasMultiConvoAccess || !plusCommandEnabled) { + return; + } + if (shouldTriggerCommand(textAreaRef, '+')) { setShowPlusPopover(true); } - }, [textAreaRef, setShowPlusPopover, plusCommandEnabled]); + }, [textAreaRef, setShowPlusPopover, plusCommandEnabled, hasMultiConvoAccess]); const handlePromptsCommand = useCallback(() => { - if (!hasAccess || !slashCommandEnabled) { + if (!hasPromptsAccess || !slashCommandEnabled) { return; } if (shouldTriggerCommand(textAreaRef, '/')) { setShowPromptsPopover(true); } - }, [textAreaRef, hasAccess, setShowPromptsPopover, slashCommandEnabled]); + }, [textAreaRef, hasPromptsAccess, setShowPromptsPopover, slashCommandEnabled]); const commandHandlers = useMemo( () => ({ diff --git a/client/src/localization/languages/De.ts b/client/src/localization/languages/De.ts index 91f7218772..eeaa70b450 100644 --- a/client/src/localization/languages/De.ts +++ b/client/src/localization/languages/De.ts @@ -157,7 +157,7 @@ export default { 'Verwende doppelte geschweifte Klammern in Ihrem Text, um Variablen zu erstellen, z.B. {{Beispielvariable}}, die du später beim Verwenden des Prompts ausfüllen kannst.', com_ui_special_variables: 'Spezielle Variablen:', com_ui_special_variables_info: - 'Verwende `{{current_date}}` für das aktuelle Datum und `{{current_user}}` für deinen angegebenen Kontonamen.', + 'Verwende `{{current_date}}` für das aktuelle Datum und `{{current_user}}` für deinen angegebenen Kontonamen.', com_ui_showing: 'Anzeige von', com_ui_of: 'von', com_ui_entries: 'Einträgen', @@ -727,40 +727,36 @@ export default { com_ui_clear_all: 'Auswahl löschen', com_ui_dropdown_variables: 'Dropdown-Variablen:', com_ui_dropdown_variables_info: - 'Erstellen Sie benutzerdefinierte Dropdown-Menüs für Ihre Eingabeaufforderungen: `{{variable_name:option1|option2|option3}}`', + 'Erstellen Sie benutzerdefinierte Dropdown-Menüs für Ihre Eingabeaufforderungen: `{{variable_name:option1|option2|option3}}`', + com_nav_plus_command: '+-Befehl', + com_nav_plus_command_description: + 'Schaltet den Befehl "+" zum Hinzufügen einer Mehrfachantwort-Einstellung um', + com_nav_slash_command: '/-Befehl', + com_nav_slash_command_description: + 'Schaltet den Befehl "/" zur Auswahl einer Eingabeaufforderung über die Tastatur um', + com_nav_command_settings: 'Befehlseinstellungen', + com_nav_convo_menu_options: 'Optionen des Gesprächsmenüs', + com_ui_artifacts: 'Artefakte', + com_ui_artifacts_toggle: 'Artefakte-Funktion einschalten', + com_nav_info_code_artifacts: + 'Aktiviert die Anzeige experimenteller Code-Artefakte neben dem Chat', + com_ui_include_shadcnui: 'Anweisungen für shadcn/ui-Komponenten einschließen', + com_nav_info_include_shadcnui: + 'Wenn aktiviert, werden Anweisungen zur Verwendung von shadcn/ui-Komponenten eingeschlossen. shadcn/ui ist eine Sammlung wiederverwendbarer Komponenten, die mit Radix UI und Tailwind CSS erstellt wurden. Hinweis: Dies sind umfangreiche Anweisungen, die Sie nur aktivieren sollten, wenn es Ihnen wichtig ist, das KI-Modell über die korrekten Importe und Komponenten zu informieren. Weitere Informationen zu diesen Komponenten finden Sie unter: https://ui.shadcn.com/', + com_ui_custom_prompt_mode: 'Benutzerdefinierter Promptmodus für Artefakte', + com_nav_info_custom_prompt_mode: + 'Wenn aktiviert, wird die Standard-Systemaufforderung für Artefakte nicht eingeschlossen. Alle Anweisungen zur Erzeugung von Artefakten müssen in diesem Modus manuell bereitgestellt werden.', + com_ui_artifact_click: 'Zum Öffnen klicken', + com_a11y_start: 'Die KI hat mit ihrer Antwort begonnen.', + com_a11y_ai_composing: 'Die KI erstellt noch ihre Antwort.', + com_a11y_end: 'Die KI hat ihre Antwort beendet.', + com_nav_commands: 'Befehle', + com_nav_commands_tab: 'Befehlseinstellungen', + com_nav_at_command: '@-Befehl', com_nav_at_command_description: - 'Schaltet den Befehl "@" zum Wechseln von Endpunkten, Modellen, Voreinstellungen usw. um.', -com_nav_plus_command: '+-Befehl', -com_nav_plus_command_description: 'Schaltet den Befehl "+" zum Hinzufügen einer Mehrfachantwort-Einstellung um', -com_nav_slash_command: '/-Befehl', -com_nav_slash_command_description: 'Schaltet den Befehl "/" zur Auswahl einer Eingabeaufforderung über die Tastatur um', -com_nav_command_settings: 'Befehlseinstellungen', -com_nav_convo_menu_options: 'Optionen des Gesprächsmenüs', -com_ui_artifacts: 'Artefakte', -com_ui_artifacts_toggle: 'Artefakte-Funktion einschalten', -com_nav_info_code_artifacts: - 'Aktiviert die Anzeige experimenteller Code-Artefakte neben dem Chat', -com_ui_include_shadcnui: 'Anweisungen für shadcn/ui-Komponenten einschließen', -com_nav_info_include_shadcnui: - 'Wenn aktiviert, werden Anweisungen zur Verwendung von shadcn/ui-Komponenten eingeschlossen. shadcn/ui ist eine Sammlung wiederverwendbarer Komponenten, die mit Radix UI und Tailwind CSS erstellt wurden. Hinweis: Dies sind umfangreiche Anweisungen, die Sie nur aktivieren sollten, wenn es Ihnen wichtig ist, das KI-Modell über die korrekten Importe und Komponenten zu informieren. Weitere Informationen zu diesen Komponenten finden Sie unter: https://ui.shadcn.com/', -com_ui_custom_prompt_mode: 'Benutzerdefinierter Promptmodus für Artefakte', -com_nav_info_custom_prompt_mode: - 'Wenn aktiviert, wird die Standard-Systemaufforderung für Artefakte nicht eingeschlossen. Alle Anweisungen zur Erzeugung von Artefakten müssen in diesem Modus manuell bereitgestellt werden.', -com_ui_artifact_click: 'Zum Öffnen klicken', -com_a11y_start: 'Die KI hat mit ihrer Antwort begonnen.', -com_a11y_ai_composing: 'Die KI erstellt noch ihre Antwort.', -com_a11y_end: 'Die KI hat ihre Antwort beendet.', -com_nav_commands: 'Befehle', -com_nav_commands_tab: 'Befehlseinstellungen', -com_nav_at_command: '@-Befehl', -com_nav_at_command_description: - 'Schaltet den Befehl "@" zum Wechseln von Endpunkten, Modellen, Voreinstellungen usw. um.', -com_nav_plus_command: '+-Befehl', -com_nav_plus_command_description: 'Schaltet den Befehl "+" zum Hinzufügen einer Mehrfachantwort-Einstellung um', -com_nav_slash_command: '/-Befehl', -com_nav_slash_command_description: 'Schaltet den Befehl "/" zur Auswahl einer Eingabeaufforderung über die Tastatur um', -com_nav_command_settings: 'Tastaturbefehl-Einstellungen', -com_nav_command_settings_description: 'Passen Sie an, welche Tastaturbefehle im Chat verfügbar sind', + 'Schaltet den Befehl "@" zum Wechseln von Endpunkten, Modellen, Voreinstellungen usw. um.', + com_nav_command_settings_description: + 'Passen Sie an, welche Tastaturbefehle im Chat verfügbar sind', }; export const comparisons = { diff --git a/client/src/localization/languages/Eng.ts b/client/src/localization/languages/Eng.ts index e2f346891d..cfb16c16b8 100644 --- a/client/src/localization/languages/Eng.ts +++ b/client/src/localization/languages/Eng.ts @@ -753,6 +753,9 @@ export default { com_nav_info_delete_cache_storage: 'This action will delete all cached TTS (Text-to-Speech) audio files stored on your device. Cached audio files are used to speed up playback of previously generated TTS audio, but they can consume storage space on your device.', // Command Settings Tab + com_nav_chat_commands: 'Chat Commands', + com_nav_chat_commands_info: + 'These commands are activated by typing specific characters at the beginning of your message. Each command is triggered by its designated prefix. You can disable them if you frequently use these characters to start messages.', com_nav_commands: 'Commands', com_nav_commands_tab: 'Command Settings', com_nav_at_command: '@-Command', diff --git a/package-lock.json b/package-lock.json index 18fbe341e3..f63604f10f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36399,7 +36399,7 @@ }, "packages/data-provider": { "name": "librechat-data-provider", - "version": "0.7.420", + "version": "0.7.421", "license": "ISC", "dependencies": { "@types/js-yaml": "^4.0.9", diff --git a/packages/data-provider/package.json b/packages/data-provider/package.json index 4b381dacc0..1a04033860 100644 --- a/packages/data-provider/package.json +++ b/packages/data-provider/package.json @@ -1,6 +1,6 @@ { "name": "librechat-data-provider", - "version": "0.7.420", + "version": "0.7.421", "description": "data services for librechat apps", "main": "dist/index.js", "module": "dist/index.es.js", diff --git a/packages/data-provider/src/config.ts b/packages/data-provider/src/config.ts index d0bd5aa1ad..7b60632fb5 100644 --- a/packages/data-provider/src/config.ts +++ b/packages/data-provider/src/config.ts @@ -460,6 +460,7 @@ export const configSchema = z.object({ modelSelect: z.boolean().optional(), parameters: z.boolean().optional(), sidePanel: z.boolean().optional(), + multiConvo: z.boolean().optional(), bookmarks: z.boolean().optional(), presets: z.boolean().optional(), prompts: z.boolean().optional(), @@ -470,6 +471,7 @@ export const configSchema = z.object({ parameters: true, sidePanel: true, presets: true, + multiConvo: true, bookmarks: true, prompts: true, }), diff --git a/packages/data-provider/src/roles.ts b/packages/data-provider/src/roles.ts index 0da92c212c..fca276b00e 100644 --- a/packages/data-provider/src/roles.ts +++ b/packages/data-provider/src/roles.ts @@ -30,6 +30,10 @@ export enum PermissionTypes { * Type for Agent Permissions */ AGENTS = 'AGENTS', + /** + * Type for Multi-Conversation Permissions + */ + MULTI_CONVO = 'MULTI_CONVO', } /** @@ -60,17 +64,23 @@ export const agentPermissionsSchema = z.object({ // [Permissions.SHARE]: z.boolean().default(false), }); +export const multiConvoPermissionsSchema = z.object({ + [Permissions.USE]: z.boolean().default(false), +}); + export const roleSchema = z.object({ name: z.string(), [PermissionTypes.PROMPTS]: promptPermissionsSchema, [PermissionTypes.BOOKMARKS]: bookmarkPermissionsSchema, [PermissionTypes.AGENTS]: agentPermissionsSchema, + [PermissionTypes.MULTI_CONVO]: multiConvoPermissionsSchema, }); export type TRole = z.infer; export type TAgentPermissions = z.infer; export type TPromptPermissions = z.infer; export type TBookmarkPermissions = z.infer; +export type TMultiConvoPermissions = z.infer; const defaultRolesSchema = z.object({ [SystemRoles.ADMIN]: roleSchema.extend({ @@ -90,12 +100,16 @@ const defaultRolesSchema = z.object({ [Permissions.CREATE]: z.boolean().default(true), // [Permissions.SHARE]: z.boolean().default(true), }), + [PermissionTypes.MULTI_CONVO]: multiConvoPermissionsSchema.extend({ + [Permissions.USE]: z.boolean().default(true), + }), }), [SystemRoles.USER]: roleSchema.extend({ name: z.literal(SystemRoles.USER), [PermissionTypes.PROMPTS]: promptPermissionsSchema, [PermissionTypes.BOOKMARKS]: bookmarkPermissionsSchema, [PermissionTypes.AGENTS]: agentPermissionsSchema, + [PermissionTypes.MULTI_CONVO]: multiConvoPermissionsSchema, }), }); @@ -105,11 +119,13 @@ export const roleDefaults = defaultRolesSchema.parse({ [PermissionTypes.PROMPTS]: {}, [PermissionTypes.BOOKMARKS]: {}, [PermissionTypes.AGENTS]: {}, + [PermissionTypes.MULTI_CONVO]: {}, }, [SystemRoles.USER]: { name: SystemRoles.USER, [PermissionTypes.PROMPTS]: {}, [PermissionTypes.BOOKMARKS]: {}, [PermissionTypes.AGENTS]: {}, + [PermissionTypes.MULTI_CONVO]: {}, }, }); diff --git a/packages/data-provider/src/types.ts b/packages/data-provider/src/types.ts index a14d09104d..9f65ae8b20 100644 --- a/packages/data-provider/src/types.ts +++ b/packages/data-provider/src/types.ts @@ -303,13 +303,16 @@ export type TInterfaceConfig = { openNewTab?: boolean; modalAcceptance?: boolean; modalTitle?: string; - modalContent?: string; + modalContent?: string | string[]; }; endpointsMenu: boolean; modelSelect: boolean; parameters: boolean; sidePanel: boolean; presets: boolean; + multiConvo: boolean; + bookmarks: boolean; + prompts: boolean; }; export type TStartupConfig = {