WIP: first pass for DB Configs

This commit is contained in:
Danny Avila 2026-01-11 17:53:35 -05:00
parent c9bbb737a5
commit 429f742c85
No known key found for this signature in database
GPG key ID: BF31EEB2C5CA0956
15 changed files with 765 additions and 44 deletions

View file

@ -1,6 +1,8 @@
const { CacheKeys } = require('librechat-data-provider');
const { buildUserConfig } = require('@librechat/api');
const { logger, AppService } = require('@librechat/data-schemas');
const { CacheKeys, PrincipalType } = require('librechat-data-provider');
const { loadAndFormatTools } = require('~/server/services/start/tools');
const { getUserPrincipals, getApplicableConfigs } = require('~/models');
const loadCustomConfig = require('./loadCustomConfig');
const { setCachedTools } = require('./getCachedTools');
const getLogStores = require('~/cache/getLogStores');
@ -23,26 +25,19 @@ const loadBaseConfig = async () => {
/**
* Get the app configuration based on user context
* @param {Object} [options]
* @param {string} [options.userId] - User ID (used to determine role if role not provided)
* @param {string} [options.role] - User role for role-based config
* @param {boolean} [options.refresh] - Force refresh the cache
* @returns {Promise<AppConfig>}
*/
async function getAppConfig(options = {}) {
const { role, refresh } = options;
const { userId, role, refresh } = options;
const cache = getLogStores(CacheKeys.APP_CONFIG);
const cacheKey = role ? role : BASE_CONFIG_KEY;
if (!refresh) {
const cached = await cache.get(cacheKey);
if (cached) {
return cached;
}
}
let baseConfig = await cache.get(BASE_CONFIG_KEY);
if (!baseConfig) {
logger.info('[getAppConfig] App configuration not initialized. Initializing AppService...');
if (!baseConfig || refresh) {
logger.info('[getAppConfig] Loading base configuration from YAML...');
baseConfig = await loadBaseConfig();
if (!baseConfig) {
@ -56,16 +51,67 @@ async function getAppConfig(options = {}) {
await cache.set(BASE_CONFIG_KEY, baseConfig);
}
// For now, return the base config
// In the future, this is where we'll apply role-based modifications
if (role) {
// TODO: Apply role-based config modifications
// const roleConfig = await applyRoleBasedConfig(baseConfig, role);
// await cache.set(cacheKey, roleConfig);
// return roleConfig;
if (!role && !userId) {
return baseConfig;
}
return baseConfig;
const principals = await getUserPrincipals({ userId, role, includeGroups: false });
if (principals.length === 0) {
return baseConfig;
}
const configs = [];
const missingPrincipals = [];
for (const principal of principals) {
const configCacheKey = `config:${principal.principalType}:${principal.principalId}`;
if (!refresh) {
const cachedConfig = await cache.get(configCacheKey);
if (cachedConfig) {
configs.push(cachedConfig);
continue;
}
}
// Track which principals we need to fetch from DB, only roles for now
if (principal.principalType === PrincipalType.ROLE) {
missingPrincipals.push(principal);
}
}
// Fetch missing configs from DB with single optimized query
if (missingPrincipals.length > 0) {
try {
// Single $or query fetches all missing configs at once
const dbConfigs = await getApplicableConfigs(missingPrincipals);
// Cache each returned config individually
for (const config of dbConfigs) {
const configCacheKey = `config:${config.principalType}:${config.principalId}`;
await cache.set(configCacheKey, config);
configs.push(config);
}
} catch (error) {
logger.error('[getAppConfig] Error fetching configs from DB:', error);
}
}
// No configs found, return base config
if (configs.length === 0) {
return baseConfig;
}
// Merge fresh baseConfig with configs on each request
try {
return await buildUserConfig({
baseConfig,
cachedConfigs: configs,
});
} catch (error) {
logger.error('[getAppConfig] Error merging configs, falling back to base:', error);
return baseConfig;
}
}
/**