⚙️ 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:
Danny Avila 2024-05-13 10:07:10 -04:00 committed by GitHub
parent 89899164ed
commit 6fc664e4a3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 94 additions and 79 deletions

View file

@ -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);
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);

View file

@ -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 = {
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,

View file

@ -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) {

View file

@ -39,17 +39,28 @@ 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);
if (included.size > 0 && adminFilter.length > 0) {
logger.warn(
'Both `includedTools` and `filteredTools` are defined; `filteredTools` will be ignored.',
);
}
for (const file of files) {
if (file.endsWith('.js') && !filter.has(file)) {
const filePath = path.join(directory, file);
if (!file.endsWith('.js') || (filter.has(file) && included.size === 0)) {
continue;
}
let ToolClass = null;
try {
ToolClass = require(filePath);
@ -58,12 +69,14 @@ function loadAndFormatTools({ directory, adminFilter = [] }) {
continue;
}
if (!ToolClass) {
if (!ToolClass || !(ToolClass.prototype instanceof StructuredTool)) {
continue;
}
if (included.size > 0 && !included.has(file)) {
continue;
}
if (ToolClass.prototype instanceof StructuredTool) {
/** @type {StructuredTool | null} */
let toolInstance = null;
try {
toolInstance = new ToolClass({ override: true });
@ -82,14 +95,9 @@ function loadAndFormatTools({ directory, adminFilter = [] }) {
const formattedTool = formatToOpenAIAssistantTool(toolInstance);
tools.push(formattedTool);
}
}
}
/**
* Basic Tools; schema: { input: string }
*/
/** Basic Tools; schema: { input: string } */
const basicToolInstances = [new Calculator()];
for (const toolInstance of basicToolInstances) {
const formattedTool = formatToOpenAIAssistantTool(toolInstance);
tools.push(formattedTool);

View file

@ -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`,
);
}
}

View file

@ -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`);
}
}

View file

@ -24,6 +24,7 @@ const connect = require('./connect');
userData.push({
User: user.name,
Email: user.email,
Conversations: conversationsCount,
Messages: messagesCount,
});

View file

@ -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

View file

@ -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. */