From 0e719592c685881e11c2ec0091b99eabf93c9dc3 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Sun, 23 Feb 2025 14:01:36 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=BC=20feat:=20"Run=20Code"=20Button=20?= =?UTF-8?q?Toggle=20(#5988)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: Add 'Run Code' and 'Temporary Chat' permissions to role management * feat: Add NextFunction typedef to api/typedefs.js * feat: Add temporary chat and run code permissions to role schema * refactor: Enhance access check middleware with logging for permission errors and better typing * refactor: Set default value of USE permission to true in multiConvoPermissionsSchema * refactor: Implement checkAccess function for separation of permission validation logic from middleware * feat: Integrate permission checks for tool execution and enhance Markdown code block with execution capability * fix: Convert REDIS_MAX_LISTENERS to a number, closes #5979 --- api/cache/keyvRedis.js | 2 +- api/models/Role.js | 4 + api/models/schema/roleSchema.js | 12 +++ api/server/controllers/tools.js | 26 +++++- .../middleware/roles/generateCheckAccess.js | 81 +++++++++++++------ api/server/middleware/roles/index.js | 3 +- api/server/services/start/interface.js | 5 ++ api/server/services/start/interface.spec.js | 36 +++++++++ api/typedefs.js | 6 ++ .../Chat/Messages/Content/Markdown.tsx | 15 +++- package-lock.json | 2 +- packages/data-provider/package.json | 2 +- packages/data-provider/src/config.ts | 2 + packages/data-provider/src/roles.ts | 34 +++++++- 14 files changed, 197 insertions(+), 33 deletions(-) diff --git a/api/cache/keyvRedis.js b/api/cache/keyvRedis.js index 816dcd29b2e..49620c49aef 100644 --- a/api/cache/keyvRedis.js +++ b/api/cache/keyvRedis.js @@ -9,7 +9,7 @@ const { REDIS_URI, USE_REDIS, USE_REDIS_CLUSTER, REDIS_CA, REDIS_KEY_PREFIX, RED let keyvRedis; const redis_prefix = REDIS_KEY_PREFIX || ''; -const redis_max_listeners = REDIS_MAX_LISTENERS || 10; +const redis_max_listeners = Number(REDIS_MAX_LISTENERS) || 10; function mapURI(uri) { const regex = diff --git a/api/models/Role.js b/api/models/Role.js index 9c160512b7d..3f025707184 100644 --- a/api/models/Role.js +++ b/api/models/Role.js @@ -6,8 +6,10 @@ const { removeNullishValues, agentPermissionsSchema, promptPermissionsSchema, + runCodePermissionsSchema, bookmarkPermissionsSchema, multiConvoPermissionsSchema, + temporaryChatPermissionsSchema, } = require('librechat-data-provider'); const getLogStores = require('~/cache/getLogStores'); const Role = require('~/models/schema/roleSchema'); @@ -77,6 +79,8 @@ const permissionSchemas = { [PermissionTypes.PROMPTS]: promptPermissionsSchema, [PermissionTypes.BOOKMARKS]: bookmarkPermissionsSchema, [PermissionTypes.MULTI_CONVO]: multiConvoPermissionsSchema, + [PermissionTypes.TEMPORARY_CHAT]: temporaryChatPermissionsSchema, + [PermissionTypes.RUN_CODE]: runCodePermissionsSchema, }; /** diff --git a/api/models/schema/roleSchema.js b/api/models/schema/roleSchema.js index 36e9d3f7b6e..5e6729bd88a 100644 --- a/api/models/schema/roleSchema.js +++ b/api/models/schema/roleSchema.js @@ -48,6 +48,18 @@ const roleSchema = new mongoose.Schema({ default: true, }, }, + [PermissionTypes.TEMPORARY_CHAT]: { + [Permissions.USE]: { + type: Boolean, + default: true, + }, + }, + [PermissionTypes.RUN_CODE]: { + [Permissions.USE]: { + type: Boolean, + default: true, + }, + }, }); const Role = mongoose.model('Role', roleSchema); diff --git a/api/server/controllers/tools.js b/api/server/controllers/tools.js index 9460e661369..1c5330af352 100644 --- a/api/server/controllers/tools.js +++ b/api/server/controllers/tools.js @@ -1,10 +1,17 @@ const { nanoid } = require('nanoid'); const { EnvVar } = require('@librechat/agents'); -const { Tools, AuthType, ToolCallTypes } = require('librechat-data-provider'); +const { + Tools, + AuthType, + Permissions, + ToolCallTypes, + PermissionTypes, +} = require('librechat-data-provider'); const { processFileURL, uploadImageBuffer } = require('~/server/services/Files/process'); const { processCodeOutput } = require('~/server/services/Files/Code/process'); -const { loadAuthValues, loadTools } = require('~/app/clients/tools/util'); const { createToolCall, getToolCallsByConvo } = require('~/models/ToolCall'); +const { loadAuthValues, loadTools } = require('~/app/clients/tools/util'); +const { checkAccess } = require('~/server/middleware'); const { getMessage } = require('~/models/Message'); const { logger } = require('~/config'); @@ -12,6 +19,10 @@ const fieldsMap = { [Tools.execute_code]: [EnvVar.CODE_API_KEY], }; +const toolAccessPermType = { + [Tools.execute_code]: PermissionTypes.RUN_CODE, +}; + /** * @param {ServerRequest} req - The request object, containing information about the HTTP request. * @param {ServerResponse} res - The response object, used to send back the desired HTTP response. @@ -58,6 +69,7 @@ const verifyToolAuth = async (req, res) => { /** * @param {ServerRequest} req - The request object, containing information about the HTTP request. * @param {ServerResponse} res - The response object, used to send back the desired HTTP response. + * @param {NextFunction} next - The next middleware function to call. * @returns {Promise} A promise that resolves when the function has completed. */ const callTool = async (req, res) => { @@ -83,6 +95,16 @@ const callTool = async (req, res) => { return; } logger.debug(`[${toolId}/call] User: ${req.user.id}`); + let hasAccess = true; + if (toolAccessPermType[toolId]) { + hasAccess = await checkAccess(req.user, toolAccessPermType[toolId], [Permissions.USE]); + } + if (!hasAccess) { + logger.warn( + `[${toolAccessPermType[toolId]}] Forbidden: Insufficient permissions for User ${req.user.id}: ${Permissions.USE}`, + ); + return res.status(403).json({ message: 'Forbidden: Insufficient permissions' }); + } const { loadedTools } = await loadTools({ user: req.user.id, tools: [toolId], diff --git a/api/server/middleware/roles/generateCheckAccess.js b/api/server/middleware/roles/generateCheckAccess.js index ffc0ddc6133..0f137c3c84d 100644 --- a/api/server/middleware/roles/generateCheckAccess.js +++ b/api/server/middleware/roles/generateCheckAccess.js @@ -1,4 +1,42 @@ const { getRoleByName } = require('~/models/Role'); +const { logger } = require('~/config'); + +/** + * Core function to check if a user has one or more required permissions + * + * @param {object} user - The user object + * @param {PermissionTypes} permissionType - The type of permission to check + * @param {Permissions[]} permissions - The list of specific permissions to check + * @param {Record} [bodyProps] - An optional object where keys are permissions and values are arrays of properties to check + * @param {object} [checkObject] - The object to check properties against + * @returns {Promise} Whether the user has the required permissions + */ +const checkAccess = async (user, permissionType, permissions, bodyProps = {}, checkObject = {}) => { + if (!user) { + return false; + } + + const role = await getRoleByName(user.role); + if (role && role[permissionType]) { + const hasAnyPermission = permissions.some((permission) => { + if (role[permissionType][permission]) { + return true; + } + + if (bodyProps[permission] && checkObject) { + return bodyProps[permission].some((prop) => + Object.prototype.hasOwnProperty.call(checkObject, prop), + ); + } + + return false; + }); + + return hasAnyPermission; + } + + return false; +}; /** * Middleware to check if a user has one or more required permissions, optionally based on `req.body` properties. @@ -6,42 +44,35 @@ const { getRoleByName } = require('~/models/Role'); * @param {PermissionTypes} permissionType - The type of permission to check. * @param {Permissions[]} permissions - The list of specific permissions to check. * @param {Record} [bodyProps] - An optional object where keys are permissions and values are arrays of `req.body` properties to check. - * @returns {Function} Express middleware function. + * @returns {(req: ServerRequest, res: ServerResponse, next: NextFunction) => Promise} Express middleware function. */ const generateCheckAccess = (permissionType, permissions, bodyProps = {}) => { return async (req, res, next) => { try { - const { user } = req; - if (!user) { - return res.status(401).json({ message: 'Authorization required' }); - } + const hasAccess = await checkAccess( + req.user, + permissionType, + permissions, + bodyProps, + req.body, + ); - const role = await getRoleByName(user.role); - if (role && role[permissionType]) { - const hasAnyPermission = permissions.some((permission) => { - if (role[permissionType][permission]) { - return true; - } - - if (bodyProps[permission] && req.body) { - return bodyProps[permission].some((prop) => - Object.prototype.hasOwnProperty.call(req.body, prop), - ); - } - - return false; - }); - - if (hasAnyPermission) { - return next(); - } + if (hasAccess) { + return next(); } + logger.warn( + `[${permissionType}] Forbidden: Insufficient permissions for User ${req.user.id}: ${permissions.join(', ')}`, + ); return res.status(403).json({ message: 'Forbidden: Insufficient permissions' }); } catch (error) { + logger.error(error); return res.status(500).json({ message: `Server error: ${error.message}` }); } }; }; -module.exports = generateCheckAccess; +module.exports = { + checkAccess, + generateCheckAccess, +}; diff --git a/api/server/middleware/roles/index.js b/api/server/middleware/roles/index.js index 999c36481e0..a9fc5b2a08f 100644 --- a/api/server/middleware/roles/index.js +++ b/api/server/middleware/roles/index.js @@ -1,7 +1,8 @@ const checkAdmin = require('./checkAdmin'); -const generateCheckAccess = require('./generateCheckAccess'); +const { checkAccess, generateCheckAccess } = require('./generateCheckAccess'); module.exports = { checkAdmin, + checkAccess, generateCheckAccess, }; diff --git a/api/server/services/start/interface.js b/api/server/services/start/interface.js index bdb151ec349..5365c4af7fb 100644 --- a/api/server/services/start/interface.js +++ b/api/server/services/start/interface.js @@ -34,6 +34,7 @@ async function loadDefaultInterface(config, configDefaults, roleName = SystemRol multiConvo: interfaceConfig?.multiConvo ?? defaults.multiConvo, agents: interfaceConfig?.agents ?? defaults.agents, temporaryChat: interfaceConfig?.temporaryChat ?? defaults.temporaryChat, + runCode: interfaceConfig?.runCode ?? defaults.runCode, customWelcome: interfaceConfig?.customWelcome ?? defaults.customWelcome, }); @@ -42,12 +43,16 @@ async function loadDefaultInterface(config, configDefaults, roleName = SystemRol [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: loadedInterface.bookmarks }, [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: loadedInterface.multiConvo }, [PermissionTypes.AGENTS]: { [Permissions.USE]: loadedInterface.agents }, + [PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: loadedInterface.temporaryChat }, + [PermissionTypes.RUN_CODE]: { [Permissions.USE]: loadedInterface.runCode }, }); await updateAccessPermissions(SystemRoles.ADMIN, { [PermissionTypes.PROMPTS]: { [Permissions.USE]: loadedInterface.prompts }, [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: loadedInterface.bookmarks }, [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: loadedInterface.multiConvo }, [PermissionTypes.AGENTS]: { [Permissions.USE]: loadedInterface.agents }, + [PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: loadedInterface.temporaryChat }, + [PermissionTypes.RUN_CODE]: { [Permissions.USE]: loadedInterface.runCode }, }); let i = 0; diff --git a/api/server/services/start/interface.spec.js b/api/server/services/start/interface.spec.js index 0041246433a..7e248d3dfe6 100644 --- a/api/server/services/start/interface.spec.js +++ b/api/server/services/start/interface.spec.js @@ -14,6 +14,8 @@ describe('loadDefaultInterface', () => { bookmarks: true, multiConvo: true, agents: true, + temporaryChat: true, + runCode: true, }, }; const configDefaults = { interface: {} }; @@ -25,6 +27,8 @@ describe('loadDefaultInterface', () => { [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: true }, [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: true }, [PermissionTypes.AGENTS]: { [Permissions.USE]: true }, + [PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: true }, + [PermissionTypes.RUN_CODE]: { [Permissions.USE]: true }, }); }); @@ -35,6 +39,8 @@ describe('loadDefaultInterface', () => { bookmarks: false, multiConvo: false, agents: false, + temporaryChat: false, + runCode: false, }, }; const configDefaults = { interface: {} }; @@ -46,6 +52,8 @@ describe('loadDefaultInterface', () => { [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: false }, [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: false }, [PermissionTypes.AGENTS]: { [Permissions.USE]: false }, + [PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: false }, + [PermissionTypes.RUN_CODE]: { [Permissions.USE]: false }, }); }); @@ -60,6 +68,8 @@ describe('loadDefaultInterface', () => { [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: undefined }, [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: undefined }, [PermissionTypes.AGENTS]: { [Permissions.USE]: undefined }, + [PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: undefined }, + [PermissionTypes.RUN_CODE]: { [Permissions.USE]: undefined }, }); }); @@ -70,6 +80,8 @@ describe('loadDefaultInterface', () => { bookmarks: undefined, multiConvo: undefined, agents: undefined, + temporaryChat: undefined, + runCode: undefined, }, }; const configDefaults = { interface: {} }; @@ -81,6 +93,8 @@ describe('loadDefaultInterface', () => { [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: undefined }, [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: undefined }, [PermissionTypes.AGENTS]: { [Permissions.USE]: undefined }, + [PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: undefined }, + [PermissionTypes.RUN_CODE]: { [Permissions.USE]: undefined }, }); }); @@ -91,6 +105,8 @@ describe('loadDefaultInterface', () => { bookmarks: false, multiConvo: undefined, agents: true, + temporaryChat: undefined, + runCode: false, }, }; const configDefaults = { interface: {} }; @@ -102,6 +118,8 @@ describe('loadDefaultInterface', () => { [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: false }, [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: undefined }, [PermissionTypes.AGENTS]: { [Permissions.USE]: true }, + [PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: undefined }, + [PermissionTypes.RUN_CODE]: { [Permissions.USE]: false }, }); }); @@ -113,6 +131,8 @@ describe('loadDefaultInterface', () => { bookmarks: true, multiConvo: true, agents: true, + temporaryChat: true, + runCode: true, }, }; @@ -123,6 +143,8 @@ describe('loadDefaultInterface', () => { [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: true }, [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: true }, [PermissionTypes.AGENTS]: { [Permissions.USE]: true }, + [PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: true }, + [PermissionTypes.RUN_CODE]: { [Permissions.USE]: true }, }); }); @@ -137,6 +159,8 @@ describe('loadDefaultInterface', () => { [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: undefined }, [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: true }, [PermissionTypes.AGENTS]: { [Permissions.USE]: undefined }, + [PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: undefined }, + [PermissionTypes.RUN_CODE]: { [Permissions.USE]: undefined }, }); }); @@ -151,6 +175,8 @@ describe('loadDefaultInterface', () => { [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: undefined }, [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: false }, [PermissionTypes.AGENTS]: { [Permissions.USE]: undefined }, + [PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: undefined }, + [PermissionTypes.RUN_CODE]: { [Permissions.USE]: undefined }, }); }); @@ -165,6 +191,8 @@ describe('loadDefaultInterface', () => { [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: undefined }, [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: undefined }, [PermissionTypes.AGENTS]: { [Permissions.USE]: undefined }, + [PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: undefined }, + [PermissionTypes.RUN_CODE]: { [Permissions.USE]: undefined }, }); }); @@ -175,6 +203,8 @@ describe('loadDefaultInterface', () => { bookmarks: false, multiConvo: true, agents: false, + temporaryChat: true, + runCode: false, }, }; const configDefaults = { interface: {} }; @@ -186,6 +216,8 @@ describe('loadDefaultInterface', () => { [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: false }, [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: true }, [PermissionTypes.AGENTS]: { [Permissions.USE]: false }, + [PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: true }, + [PermissionTypes.RUN_CODE]: { [Permissions.USE]: false }, }); }); @@ -197,6 +229,8 @@ describe('loadDefaultInterface', () => { bookmarks: true, multiConvo: false, agents: undefined, + temporaryChat: undefined, + runCode: undefined, }, }; @@ -207,6 +241,8 @@ describe('loadDefaultInterface', () => { [PermissionTypes.BOOKMARKS]: { [Permissions.USE]: true }, [PermissionTypes.MULTI_CONVO]: { [Permissions.USE]: false }, [PermissionTypes.AGENTS]: { [Permissions.USE]: undefined }, + [PermissionTypes.TEMPORARY_CHAT]: { [Permissions.USE]: undefined }, + [PermissionTypes.RUN_CODE]: { [Permissions.USE]: undefined }, }); }); }); diff --git a/api/typedefs.js b/api/typedefs.js index bd97bd93fa8..cc7ae41895f 100644 --- a/api/typedefs.js +++ b/api/typedefs.js @@ -20,6 +20,12 @@ * @memberof typedefs */ +/** + * @exports NextFunction + * @typedef {import('express').NextFunction} NextFunction + * @memberof typedefs + */ + /** * @exports AgentRun * @typedef {import('@librechat/agents').Run} AgentRun diff --git a/client/src/components/Chat/Messages/Content/Markdown.tsx b/client/src/components/Chat/Messages/Content/Markdown.tsx index 34b46b9d3dd..e01de091c7a 100644 --- a/client/src/components/Chat/Messages/Content/Markdown.tsx +++ b/client/src/components/Chat/Messages/Content/Markdown.tsx @@ -7,6 +7,7 @@ import { useRecoilValue } from 'recoil'; import ReactMarkdown from 'react-markdown'; import rehypeHighlight from 'rehype-highlight'; import remarkDirective from 'remark-directive'; +import { PermissionTypes, Permissions } from 'librechat-data-provider'; import type { Pluggable } from 'unified'; import { useToastContext, @@ -17,6 +18,7 @@ import { import { Artifact, artifactPlugin } from '~/components/Artifacts/Artifact'; import { langSubset, preprocessLaTeX, handleDoubleClick } from '~/utils'; import CodeBlock from '~/components/Messages/Content/CodeBlock'; +import useHasAccess from '~/hooks/Roles/useHasAccess'; import { useFileDownload } from '~/data-provider'; import useLocalize from '~/hooks/useLocalize'; import store from '~/store'; @@ -28,6 +30,10 @@ type TCodeProps = { }; export const code: React.ElementType = memo(({ className, children }: TCodeProps) => { + const canRunCode = useHasAccess({ + permissionType: PermissionTypes.RUN_CODE, + permission: Permissions.USE, + }); const match = /language-(\w+)/.exec(className ?? ''); const lang = match && match[1]; const isMath = lang === 'math'; @@ -49,7 +55,14 @@ export const code: React.ElementType = memo(({ className, children }: TCodeProps ); } else { - return ; + return ( + + ); } }); diff --git a/package-lock.json b/package-lock.json index 85f835fbcfa..7b920f17005 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38885,7 +38885,7 @@ }, "packages/data-provider": { "name": "librechat-data-provider", - "version": "0.7.6991", + "version": "0.7.6992", "license": "ISC", "dependencies": { "axios": "^1.7.7", diff --git a/packages/data-provider/package.json b/packages/data-provider/package.json index 240d099e07e..9f6d2edbf20 100644 --- a/packages/data-provider/package.json +++ b/packages/data-provider/package.json @@ -1,6 +1,6 @@ { "name": "librechat-data-provider", - "version": "0.7.6991", + "version": "0.7.6992", "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 6b9d08e165e..3134a7ea9a1 100644 --- a/packages/data-provider/src/config.ts +++ b/packages/data-provider/src/config.ts @@ -457,6 +457,7 @@ export const intefaceSchema = z prompts: z.boolean().optional(), agents: z.boolean().optional(), temporaryChat: z.boolean().optional(), + runCode: z.boolean().optional(), }) .default({ endpointsMenu: true, @@ -469,6 +470,7 @@ export const intefaceSchema = z prompts: true, agents: true, temporaryChat: true, + runCode: true, }); export type TInterfaceConfig = z.infer; diff --git a/packages/data-provider/src/roles.ts b/packages/data-provider/src/roles.ts index 1a0d53f3cec..b7a8752e884 100644 --- a/packages/data-provider/src/roles.ts +++ b/packages/data-provider/src/roles.ts @@ -34,6 +34,14 @@ export enum PermissionTypes { * Type for Multi-Conversation Permissions */ MULTI_CONVO = 'MULTI_CONVO', + /** + * Type for Temporary Chat + */ + TEMPORARY_CHAT = 'TEMPORARY_CHAT', + /** + * Type for using the "Run Code" LC Code Interpreter API feature + */ + RUN_CODE = 'RUN_CODE', } /** @@ -68,7 +76,15 @@ export const agentPermissionsSchema = z.object({ }); export const multiConvoPermissionsSchema = z.object({ - [Permissions.USE]: z.boolean().default(false), + [Permissions.USE]: z.boolean().default(true), +}); + +export const temporaryChatPermissionsSchema = z.object({ + [Permissions.USE]: z.boolean().default(true), +}); + +export const runCodePermissionsSchema = z.object({ + [Permissions.USE]: z.boolean().default(true), }); export const roleSchema = z.object({ @@ -77,6 +93,8 @@ export const roleSchema = z.object({ [PermissionTypes.BOOKMARKS]: bookmarkPermissionsSchema, [PermissionTypes.AGENTS]: agentPermissionsSchema, [PermissionTypes.MULTI_CONVO]: multiConvoPermissionsSchema, + [PermissionTypes.TEMPORARY_CHAT]: temporaryChatPermissionsSchema, + [PermissionTypes.RUN_CODE]: runCodePermissionsSchema, }); export type TRole = z.infer; @@ -84,6 +102,8 @@ export type TAgentPermissions = z.infer; export type TPromptPermissions = z.infer; export type TBookmarkPermissions = z.infer; export type TMultiConvoPermissions = z.infer; +export type TTemporaryChatPermissions = z.infer; +export type TRunCodePermissions = z.infer; const defaultRolesSchema = z.object({ [SystemRoles.ADMIN]: roleSchema.extend({ @@ -106,6 +126,12 @@ const defaultRolesSchema = z.object({ [PermissionTypes.MULTI_CONVO]: multiConvoPermissionsSchema.extend({ [Permissions.USE]: z.boolean().default(true), }), + [PermissionTypes.TEMPORARY_CHAT]: temporaryChatPermissionsSchema.extend({ + [Permissions.USE]: z.boolean().default(true), + }), + [PermissionTypes.RUN_CODE]: runCodePermissionsSchema.extend({ + [Permissions.USE]: z.boolean().default(true), + }), }), [SystemRoles.USER]: roleSchema.extend({ name: z.literal(SystemRoles.USER), @@ -113,6 +139,8 @@ const defaultRolesSchema = z.object({ [PermissionTypes.BOOKMARKS]: bookmarkPermissionsSchema, [PermissionTypes.AGENTS]: agentPermissionsSchema, [PermissionTypes.MULTI_CONVO]: multiConvoPermissionsSchema, + [PermissionTypes.TEMPORARY_CHAT]: temporaryChatPermissionsSchema, + [PermissionTypes.RUN_CODE]: runCodePermissionsSchema, }), }); @@ -123,6 +151,8 @@ export const roleDefaults = defaultRolesSchema.parse({ [PermissionTypes.BOOKMARKS]: {}, [PermissionTypes.AGENTS]: {}, [PermissionTypes.MULTI_CONVO]: {}, + [PermissionTypes.TEMPORARY_CHAT]: {}, + [PermissionTypes.RUN_CODE]: {}, }, [SystemRoles.USER]: { name: SystemRoles.USER, @@ -130,5 +160,7 @@ export const roleDefaults = defaultRolesSchema.parse({ [PermissionTypes.BOOKMARKS]: {}, [PermissionTypes.AGENTS]: {}, [PermissionTypes.MULTI_CONVO]: {}, + [PermissionTypes.TEMPORARY_CHAT]: {}, + [PermissionTypes.RUN_CODE]: {}, }, });