feat: agent marketplace categories synced through librechat.yaml

This commit is contained in:
Educg550 2025-09-16 13:57:02 -03:00
parent 6738360051
commit 84c6721d91
3 changed files with 110 additions and 1 deletions

View file

@ -13,6 +13,7 @@ const {
validateSettingDefinitions,
} = require('librechat-data-provider');
const getLogStores = require('~/cache/getLogStores');
const { syncCategories } = require('~/server/utils/agentCategory');
const projectRoot = path.resolve(__dirname, '..', '..', '..', '..');
const defaultConfigPath = path.resolve(projectRoot, 'librechat.yaml');
@ -115,6 +116,24 @@ https://www.librechat.ai/docs/configuration/stt_tts`);
}
}
// Injecting custom marketplace categories
logger.info('Checking for custom marketplace categories to sync.');
if (customConfig.interface?.marketplace?.use) {
logger.info('Marketplace is enabled in config.');
const marketplaceConfig = customConfig.interface.marketplace;
if (marketplaceConfig.categories) {
logger.info('Marketplace categories configuration found.');
// enableDefaultCategories should be set as a boolean, defaulting to true if not specified
const enableDefaultCategories =
typeof marketplaceConfig.categories.enableDefaultCategories === 'boolean'
? marketplaceConfig.categories.enableDefaultCategories
: true;
const customCategoriesList = marketplaceConfig.categories.list || [];
logger.info(`Found ${customCategoriesList.length} custom categories to sync.`);
await syncCategories(customCategoriesList, enableDefaultCategories);
}
}
(customConfig.endpoints?.custom ?? [])
.filter((endpoint) => endpoint.customParams)
.forEach((endpoint) => parseCustomParams(endpoint.name, endpoint.customParams));

View file

@ -0,0 +1,82 @@
const { logger } = require('@librechat/data-schemas');
const { getAllCategories, createCategory, updateCategory, deleteCategory } = require('~/models');
/**
* Synchronizes custom agent categories with the database.
* @param {Array} customCategoriesList - List of custom categories to be synchronized.
* @param {boolean} enableDefaultCategories - Flag indicating whether to enable default categories.
*/
async function syncCategories(customCategoriesList, enableDefaultCategories) {
logger.info('Syncing custom agent categories...');
// Get all categories from DB
const dbCategories = await getAllCategories();
logger.info(`Found ${dbCategories.length} categories in the database.`);
logger.info(
`${enableDefaultCategories ? 'Enabling' : 'Disabling'} default agent categories as per configuration.`,
);
for (const cat of dbCategories.filter((c) => !c.custom)) {
logger.info(`${enableDefaultCategories ? 'Enabling' : 'Disabling'} category: ${cat.value}`);
await updateCategory(cat.value, { isActive: enableDefaultCategories });
}
// Initial order takes the max value of existing default categories + 1
const defaultCategoriesInDb = dbCategories.filter((cat) => !cat.custom);
const initialOrder =
defaultCategoriesInDb.reduce((max, cat) => Math.max(max, cat.order || 0), 0) + 1;
logger.info(`Current order for new custom categories starts at ${initialOrder}.`);
// Inject order to custom categories
logger.info('Assigning order to custom categories.');
customCategoriesList = customCategoriesList.map((cat, index) => ({
...cat,
order: initialOrder + index,
}));
// Delete custom categories not in the config file
const customCategoryValues = new Set(customCategoriesList.map((cat) => cat.value.toLowerCase()));
const categoriesToDelete = dbCategories.filter(
(cat) => cat.custom && !customCategoryValues.has(cat.value.toLowerCase()),
);
for (const cat of categoriesToDelete) {
logger.info(`Deleting custom category not in config: ${cat.value}`);
await deleteCategory(cat.value);
}
// Sync custom categories
for (const category of customCategoriesList) {
let formattedCategory;
try {
formattedCategory = {
value: category.value.toLowerCase() || 'unnamed',
label: category.value || 'Unnamed',
description: category.description || '',
isActive: true,
custom: true,
order: category.order,
};
} catch (error) {
logger.error('Error formatting category: ', category, error);
continue;
}
// Check if category exists by value
const existing = dbCategories.find(
(cat) => cat.value.toLowerCase() === formattedCategory.value,
);
if (existing) {
logger.info(`Updating category: ${formattedCategory.value}`);
await updateCategory(existing.value, formattedCategory);
} else {
logger.info(`Creating category: ${formattedCategory.value}`);
await createCategory(formattedCategory);
}
}
logger.info('Custom categories synchronized successfully.');
}
module.exports = {
syncCategories,
};

View file

@ -94,7 +94,15 @@ interface:
groups: true
roles: true
marketplace:
use: false
use: false
categories:
enableDefaultCategories: false
# list:
# - value: "Education"
# description: "Educational agents."
# - value: "Productivity"
# description: "Productivity agents."
fileCitations: true
# Temporary chat retention period in hours (default: 720, min: 1, max: 8760)
# temporaryChatRetention: 1