mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-09-21 21:50:49 +02:00
⚙️ feat: includedTools
and script changes (#2690)
* chore: add email to npm scripts (user-stats and list-balances) * feat: included tools * chore: update console terminal links * chore: add back typing
This commit is contained in:
parent
89899164ed
commit
6fc664e4a3
9 changed files with 94 additions and 79 deletions
|
@ -55,24 +55,26 @@ const getAvailablePluginsController = async (req, res) => {
|
|||
return;
|
||||
}
|
||||
|
||||
/** @type {{ filteredTools: string[] }} */
|
||||
const { filteredTools = [] } = req.app.locals;
|
||||
|
||||
/** @type {{ filteredTools: string[], includedTools: string[] }} */
|
||||
const { filteredTools = [], includedTools = [] } = req.app.locals;
|
||||
const pluginManifest = await fs.readFile(req.app.locals.paths.pluginManifest, 'utf8');
|
||||
|
||||
const jsonData = JSON.parse(pluginManifest);
|
||||
/** @type {TPlugin[]} */
|
||||
|
||||
const uniquePlugins = filterUniquePlugins(jsonData);
|
||||
const authenticatedPlugins = uniquePlugins.map((plugin) => {
|
||||
if (isPluginAuthenticated(plugin)) {
|
||||
return { ...plugin, authenticated: true };
|
||||
} else {
|
||||
return plugin;
|
||||
}
|
||||
});
|
||||
let authenticatedPlugins = [];
|
||||
for (const plugin of uniquePlugins) {
|
||||
authenticatedPlugins.push(
|
||||
isPluginAuthenticated(plugin) ? { ...plugin, authenticated: true } : plugin,
|
||||
);
|
||||
}
|
||||
|
||||
let plugins = await addOpenAPISpecs(authenticatedPlugins);
|
||||
plugins = plugins.filter((plugin) => !filteredTools.includes(plugin.pluginKey));
|
||||
|
||||
if (includedTools.length > 0) {
|
||||
plugins = plugins.filter((plugin) => includedTools.includes(plugin.pluginKey));
|
||||
} else {
|
||||
plugins = plugins.filter((plugin) => !filteredTools.includes(plugin.pluginKey));
|
||||
}
|
||||
|
||||
await cache.set(CacheKeys.PLUGINS, plugins);
|
||||
res.status(200).json(plugins);
|
||||
|
|
|
@ -21,6 +21,7 @@ const AppService = async (app) => {
|
|||
const configDefaults = getConfigDefaults();
|
||||
|
||||
const filteredTools = config.filteredTools;
|
||||
const includedTools = config.includedTools;
|
||||
const fileStrategy = config.fileStrategy ?? configDefaults.fileStrategy;
|
||||
const imageOutputType = config?.imageOutputType ?? configDefaults.imageOutputType;
|
||||
|
||||
|
@ -37,23 +38,26 @@ const AppService = async (app) => {
|
|||
const availableTools = loadAndFormatTools({
|
||||
directory: paths.structuredTools,
|
||||
adminFilter: filteredTools,
|
||||
adminIncluded: includedTools,
|
||||
});
|
||||
|
||||
const socialLogins =
|
||||
config?.registration?.socialLogins ?? configDefaults?.registration?.socialLogins;
|
||||
const interfaceConfig = loadDefaultInterface(config, configDefaults);
|
||||
|
||||
if (!Object.keys(config).length) {
|
||||
app.locals = {
|
||||
paths,
|
||||
fileStrategy,
|
||||
socialLogins,
|
||||
filteredTools,
|
||||
availableTools,
|
||||
imageOutputType,
|
||||
interfaceConfig,
|
||||
};
|
||||
const defaultLocals = {
|
||||
paths,
|
||||
fileStrategy,
|
||||
socialLogins,
|
||||
filteredTools,
|
||||
includedTools,
|
||||
availableTools,
|
||||
imageOutputType,
|
||||
interfaceConfig,
|
||||
};
|
||||
|
||||
if (!Object.keys(config).length) {
|
||||
app.locals = defaultLocals;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -79,13 +83,7 @@ const AppService = async (app) => {
|
|||
}
|
||||
|
||||
app.locals = {
|
||||
paths,
|
||||
socialLogins,
|
||||
fileStrategy,
|
||||
filteredTools,
|
||||
availableTools,
|
||||
imageOutputType,
|
||||
interfaceConfig,
|
||||
...defaultLocals,
|
||||
modelSpecs: config.modelSpecs,
|
||||
fileConfig: config?.fileConfig,
|
||||
secureImageLinks: config?.secureImageLinks,
|
||||
|
|
|
@ -37,7 +37,7 @@ async function loadCustomConfig() {
|
|||
if (!customConfig) {
|
||||
i === 0 &&
|
||||
logger.info(
|
||||
'Custom config file missing or YAML format invalid.\n\nCheck out the latest config file guide for configurable options and features.\nhttps://docs.librechat.ai/install/configuration/custom_config.html\n\n',
|
||||
'Custom config file missing or YAML format invalid.\n\nCheck out the latest config file guide for configurable options and features.\nhttps://www.librechat.ai/docs/configuration/librechat_yaml\n\n',
|
||||
);
|
||||
i === 0 && i++;
|
||||
return null;
|
||||
|
@ -72,7 +72,7 @@ Please specify a correct \`imageOutputType\` value (case-sensitive).
|
|||
- ${EImageOutputType.WEBP}
|
||||
|
||||
Refer to the latest config file guide for more information:
|
||||
https://docs.librechat.ai/install/configuration/custom_config.html`,
|
||||
https://www.librechat.ai/docs/configuration/librechat_yaml`,
|
||||
);
|
||||
}
|
||||
if (!result.success) {
|
||||
|
|
|
@ -39,57 +39,65 @@ const filteredTools = new Set([
|
|||
* @param {object} params - The parameters for the function.
|
||||
* @param {string} params.directory - The directory path where the tools are located.
|
||||
* @param {Array<string>} [params.adminFilter=[]] - Array of admin-defined tool keys to exclude from loading.
|
||||
* @param {Array<string>} [params.adminIncluded=[]] - Array of admin-defined tool keys to include from loading.
|
||||
* @returns {Record<string, FunctionTool>} An object mapping each tool's plugin key to its instance.
|
||||
*/
|
||||
function loadAndFormatTools({ directory, adminFilter = [] }) {
|
||||
function loadAndFormatTools({ directory, adminFilter = [], adminIncluded = [] }) {
|
||||
const filter = new Set([...adminFilter, ...filteredTools]);
|
||||
const included = new Set(adminIncluded);
|
||||
const tools = [];
|
||||
/* Structured Tools Directory */
|
||||
const files = fs.readdirSync(directory);
|
||||
|
||||
for (const file of files) {
|
||||
if (file.endsWith('.js') && !filter.has(file)) {
|
||||
const filePath = path.join(directory, file);
|
||||
let ToolClass = null;
|
||||
try {
|
||||
ToolClass = require(filePath);
|
||||
} catch (error) {
|
||||
logger.error(`[loadAndFormatTools] Error loading tool from ${filePath}:`, error);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ToolClass) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ToolClass.prototype instanceof StructuredTool) {
|
||||
/** @type {StructuredTool | null} */
|
||||
let toolInstance = null;
|
||||
try {
|
||||
toolInstance = new ToolClass({ override: true });
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
`[loadAndFormatTools] Error initializing \`${file}\` tool; if it requires authentication, is the \`override\` field configured?`,
|
||||
error,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!toolInstance) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const formattedTool = formatToOpenAIAssistantTool(toolInstance);
|
||||
tools.push(formattedTool);
|
||||
}
|
||||
}
|
||||
if (included.size > 0 && adminFilter.length > 0) {
|
||||
logger.warn(
|
||||
'Both `includedTools` and `filteredTools` are defined; `filteredTools` will be ignored.',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic Tools; schema: { input: string }
|
||||
*/
|
||||
const basicToolInstances = [new Calculator()];
|
||||
for (const file of files) {
|
||||
const filePath = path.join(directory, file);
|
||||
if (!file.endsWith('.js') || (filter.has(file) && included.size === 0)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let ToolClass = null;
|
||||
try {
|
||||
ToolClass = require(filePath);
|
||||
} catch (error) {
|
||||
logger.error(`[loadAndFormatTools] Error loading tool from ${filePath}:`, error);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ToolClass || !(ToolClass.prototype instanceof StructuredTool)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (included.size > 0 && !included.has(file)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let toolInstance = null;
|
||||
try {
|
||||
toolInstance = new ToolClass({ override: true });
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
`[loadAndFormatTools] Error initializing \`${file}\` tool; if it requires authentication, is the \`override\` field configured?`,
|
||||
error,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!toolInstance) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const formattedTool = formatToOpenAIAssistantTool(toolInstance);
|
||||
tools.push(formattedTool);
|
||||
}
|
||||
|
||||
/** Basic Tools; schema: { input: string } */
|
||||
const basicToolInstances = [new Calculator()];
|
||||
for (const toolInstance of basicToolInstances) {
|
||||
const formattedTool = formatToOpenAIAssistantTool(toolInstance);
|
||||
tools.push(formattedTool);
|
||||
|
|
|
@ -99,7 +99,12 @@ function checkAzureVariables() {
|
|||
function checkConfig(config) {
|
||||
if (config.version !== Constants.CONFIG_VERSION) {
|
||||
logger.info(
|
||||
`\nOutdated Config version: ${config.version}. Current version: ${Constants.CONFIG_VERSION}\n\nCheck out the latest config file guide for new options and features.\nhttps://docs.librechat.ai/install/configuration/custom_config.html\n\n`,
|
||||
`\nOutdated Config version: ${config.version}
|
||||
Latest version: ${Constants.CONFIG_VERSION}
|
||||
|
||||
Check out the Config changelogs for the latest options and features added.
|
||||
|
||||
https://www.librechat.ai/changelog\n\n`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,9 +19,9 @@ const connect = require('./connect');
|
|||
for (const user of users) {
|
||||
let balance = await Balance.findOne({ user: user._id });
|
||||
if (balance !== null) {
|
||||
console.green(`User ${user.name} has a balance of ${balance.tokenCredits}`);
|
||||
console.green(`User ${user.name} (${user.email}) has a balance of ${balance.tokenCredits}`);
|
||||
} else {
|
||||
console.yellow(`User ${user.name} has no balance`);
|
||||
console.yellow(`User ${user.name} (${user.email}) has no balance`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ const connect = require('./connect');
|
|||
|
||||
userData.push({
|
||||
User: user.name,
|
||||
Email: user.email,
|
||||
Conversations: conversationsCount,
|
||||
Messages: messagesCount,
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# For more information, see the Configuration Guide:
|
||||
# https://docs.librechat.ai/install/configuration/custom_config.html
|
||||
# https://www.librechat.ai/docs/configuration/librechat_yaml
|
||||
|
||||
# Configuration version (required)
|
||||
version: 1.0.9
|
||||
|
@ -148,4 +148,4 @@ endpoints:
|
|||
# serverFileSizeLimit: 100 # Global server file size limit in MB
|
||||
# avatarSizeLimit: 2 # Limit for user avatar image size in MB
|
||||
# See the Custom Configuration Guide for more information:
|
||||
# https://docs.librechat.ai/install/configuration/custom_config.html
|
||||
# https://www.librechat.ai/docs/configuration/librechat_yaml
|
||||
|
|
|
@ -245,6 +245,7 @@ export const configSchema = z.object({
|
|||
cache: z.boolean().default(true),
|
||||
secureImageLinks: z.boolean().optional(),
|
||||
imageOutputType: z.nativeEnum(EImageOutputType).default(EImageOutputType.PNG),
|
||||
includedTools: z.array(z.string()).optional(),
|
||||
filteredTools: z.array(z.string()).optional(),
|
||||
interface: z
|
||||
.object({
|
||||
|
@ -677,7 +678,7 @@ export enum Constants {
|
|||
/** Key for the app's version. */
|
||||
VERSION = 'v0.7.2',
|
||||
/** Key for the Custom Config's version (librechat.yaml). */
|
||||
CONFIG_VERSION = '1.0.9',
|
||||
CONFIG_VERSION = '1.1.0',
|
||||
/** Standard value for the first message's `parentMessageId` value, to indicate no parent exists. */
|
||||
NO_PARENT = '00000000-0000-0000-0000-000000000000',
|
||||
/** Fixed, encoded domain length for Azure OpenAI Assistants Function name parsing. */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue