mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 17:00:15 +01:00
🔒 feat: RBAC for Multi-Convo Feature (#3964)
* fix: remove duplicate keys in German language translations * wip: multi-convo role permissions * ci: Update loadDefaultInterface tests due to MULTI_CONVO * ci: update Role.spec.js with tests for MULTI_CONVO permission type * fix: Update ContentParts component to handle undefined content array * feat: render Multi-Convo based on UI permissions
This commit is contained in:
parent
d59b62174f
commit
748b41eda4
18 changed files with 302 additions and 56 deletions
|
|
@ -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,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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() {
|
|||
{<HeaderOptions interfaceConfig={interfaceConfig} />}
|
||||
{interfaceConfig.presets === true && <PresetsMenu />}
|
||||
{hasAccessToBookmarks === true && <BookmarkMenu />}
|
||||
<AddMultiConvo />
|
||||
{hasAccessToMultiConvo === true && <AddMultiConvo />}
|
||||
{isSmallScreen && (
|
||||
<ExportAndShareMenu
|
||||
isSharedButtonEnabled={startupConfig?.sharedLinksEnabled ?? false}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import type { TMessageContentParts } from 'librechat-data-provider';
|
|||
import Part from './Part';
|
||||
|
||||
type ContentPartsProps = {
|
||||
content: Array<TMessageContentParts | undefined>;
|
||||
content: Array<TMessageContentParts | undefined> | 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
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -1,27 +1,53 @@
|
|||
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 (
|
||||
<Tabs.Content
|
||||
value={SettingsTabValues.COMMANDS}
|
||||
role="tabpanel"
|
||||
className="w-full md:min-h-[271px]"
|
||||
>
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<h3 className="text-lg font-medium text-text-primary">
|
||||
{localize('com_nav_chat_commands')}
|
||||
</h3>
|
||||
<HoverCardSettings side="bottom" text="com_nav_chat_commands_info" />
|
||||
</div>
|
||||
<div className="flex flex-col gap-3 text-sm text-text-primary">
|
||||
<div className="border-b border-border-medium pb-3 last-of-type:border-b-0">
|
||||
<AtCommandSwitch />
|
||||
</div>
|
||||
{hasAccessToMultiConvo === true && (
|
||||
<div className="border-b border-border-medium pb-3 last-of-type:border-b-0">
|
||||
<PlusCommandSwitch />
|
||||
</div>
|
||||
)}
|
||||
{hasAccessToPrompts === true && (
|
||||
<div className="border-b border-border-medium pb-3 last-of-type:border-b-0">
|
||||
<SlashCommandSwitch />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -9,12 +9,12 @@ const HoverCardSettings = ({ side, text }) => {
|
|||
return (
|
||||
<HoverCard openDelay={500}>
|
||||
<HoverCardTrigger>
|
||||
<CircleHelpIcon className="h-5 w-5 text-gray-500" />{' '}
|
||||
<CircleHelpIcon className="h-5 w-5 text-text-tertiary" />{' '}
|
||||
</HoverCardTrigger>
|
||||
<HoverCardPortal>
|
||||
<HoverCardContent side={side} className="z-[999] w-80">
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm text-gray-600 dark:text-gray-300">{localize(text)}</p>
|
||||
<p className="text-sm text-text-secondary">{localize(text)}</p>
|
||||
</div>
|
||||
</HoverCardContent>
|
||||
</HoverCardPortal>
|
||||
|
|
|
|||
|
|
@ -46,10 +46,14 @@ const useHandleKeyUp = ({
|
|||
setShowPlusPopover: SetterOrUpdater<boolean>;
|
||||
setShowMentionPopover: SetterOrUpdater<boolean>;
|
||||
}) => {
|
||||
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(
|
||||
() => ({
|
||||
|
|
|
|||
|
|
@ -728,39 +728,35 @@ export default {
|
|||
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}}`',
|
||||
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',
|
||||
com_nav_command_settings_description:
|
||||
'Passen Sie an, welche Tastaturbefehle im Chat verfügbar sind',
|
||||
};
|
||||
|
||||
export const comparisons = {
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
2
package-lock.json
generated
2
package-lock.json
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -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<typeof roleSchema>;
|
||||
export type TAgentPermissions = z.infer<typeof agentPermissionsSchema>;
|
||||
export type TPromptPermissions = z.infer<typeof promptPermissionsSchema>;
|
||||
export type TBookmarkPermissions = z.infer<typeof bookmarkPermissionsSchema>;
|
||||
export type TMultiConvoPermissions = z.infer<typeof multiConvoPermissionsSchema>;
|
||||
|
||||
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]: {},
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue