🛜 refactor: Streamline App Config Usage (#9234)

* WIP: app.locals refactoring

WIP: appConfig

fix: update memory configuration retrieval to use getAppConfig based on user role

fix: update comment for AppConfig interface to clarify purpose

🏷️ refactor: Update tests to use getAppConfig for endpoint configurations

ci: Update AppService tests to initialize app config instead of app.locals

ci: Integrate getAppConfig into remaining tests

refactor: Update multer storage destination to use promise-based getAppConfig and improve error handling in tests

refactor: Rename initializeAppConfig to setAppConfig and update related tests

ci: Mock getAppConfig in various tests to provide default configurations

refactor: Update convertMCPToolsToPlugins to use mcpManager for server configuration and adjust related tests

chore: rename `Config/getAppConfig` -> `Config/app`

fix: streamline OpenAI image tools configuration by removing direct appConfig dependency and using function parameters

chore: correct parameter documentation for imageOutputType in ToolService.js

refactor: remove `getCustomConfig` dependency in config route

refactor: update domain validation to use appConfig for allowed domains

refactor: use appConfig registration property

chore: remove app parameter from AppService invocation

refactor: update AppConfig interface to correct registration and turnstile configurations

refactor: remove getCustomConfig dependency and use getAppConfig in PluginController, multer, and MCP services

refactor: replace getCustomConfig with getAppConfig in STTService, TTSService, and related files

refactor: replace getCustomConfig with getAppConfig in Conversation and Message models, update tempChatRetention functions to use AppConfig type

refactor: update getAppConfig calls in Conversation and Message models to include user role for temporary chat expiration

ci: update related tests

refactor: update getAppConfig call in getCustomConfigSpeech to include user role

fix: update appConfig usage to access allowedDomains from actions instead of registration

refactor: enhance AppConfig to include fileStrategies and update related file strategy logic

refactor: update imports to use normalizeEndpointName from @librechat/api and remove redundant definitions

chore: remove deprecated unused RunManager

refactor: get balance config primarily from appConfig

refactor: remove customConfig dependency for appConfig and streamline loadConfigModels logic

refactor: remove getCustomConfig usage and use app config in file citations

refactor: consolidate endpoint loading logic into loadEndpoints function

refactor: update appConfig access to use endpoints structure across various services

refactor: implement custom endpoints configuration and streamline endpoint loading logic

refactor: update getAppConfig call to include user role parameter

refactor: streamline endpoint configuration and enhance appConfig usage across services

refactor: replace getMCPAuthMap with getUserMCPAuthMap and remove unused getCustomConfig file

refactor: add type annotation for loadedEndpoints in loadEndpoints function

refactor: move /services/Files/images/parse to TS API

chore: add missing FILE_CITATIONS permission to IRole interface

refactor: restructure toolkits to TS API

refactor: separate manifest logic into its own module

refactor: consolidate tool loading logic into a new tools module for startup logic

refactor: move interface config logic to TS API

refactor: migrate checkEmailConfig to TypeScript and update imports

refactor: add FunctionTool interface and availableTools to AppConfig

refactor: decouple caching and DB operations from AppService, make part of consolidated `getAppConfig`

WIP: fix tests

* fix: rebase conflicts

* refactor: remove app.locals references

* refactor: replace getBalanceConfig with getAppConfig in various strategies and middleware

* refactor: replace appConfig?.balance with getBalanceConfig in various controllers and clients

* test: add balance configuration to titleConvo method in AgentClient tests

* chore: remove unused `openai-chat-tokens` package

* chore: remove unused imports in initializeMCPs.js

* refactor: update balance configuration to use getAppConfig instead of getBalanceConfig

* refactor: integrate configMiddleware for centralized configuration handling

* refactor: optimize email domain validation by removing unnecessary async calls

* refactor: simplify multer storage configuration by removing async calls

* refactor: reorder imports for better readability in user.js

* refactor: replace getAppConfig calls with req.config for improved performance

* chore: replace getAppConfig calls with req.config in tests for centralized configuration handling

* chore: remove unused override config

* refactor: add configMiddleware to endpoint route and replace getAppConfig with req.config

* chore: remove customConfig parameter from TTSService constructor

* refactor: pass appConfig from request to processFileCitations for improved configuration handling

* refactor: remove configMiddleware from endpoint route and retrieve appConfig directly in getEndpointsConfig if not in `req.config`

* test: add mockAppConfig to processFileCitations tests for improved configuration handling

* fix: pass req.config to hasCustomUserVars and call without await after synchronous refactor

* fix: type safety in useExportConversation

* refactor: retrieve appConfig using getAppConfig in PluginController and remove configMiddleware from plugins route, to avoid always retrieving when plugins are cached

* chore: change `MongoUser` typedef to `IUser`

* fix: Add `user` and `config` fields to ServerRequest and update JSDoc type annotations from Express.Request to ServerRequest

* fix: remove unused setAppConfig mock from Server configuration tests
This commit is contained in:
Danny Avila 2025-08-26 12:10:18 -04:00 committed by GitHub
parent e1ad235f17
commit 9a210971f5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
210 changed files with 4102 additions and 3465 deletions

View file

@ -1,9 +1,11 @@
import { primeResources } from './resources';
import { logger } from '@librechat/data-schemas';
import { EModelEndpoint, EToolResources, AgentCapabilities } from 'librechat-data-provider';
import type { TAgentsEndpoint, TFile } from 'librechat-data-provider';
import type { Request as ServerRequest } from 'express';
import type { TFile } from 'librechat-data-provider';
import type { IUser } from '@librechat/data-schemas';
import type { TGetFiles } from './resources';
import type { AppConfig } from '~/types';
// Mock logger
jest.mock('@librechat/data-schemas', () => ({
@ -13,7 +15,8 @@ jest.mock('@librechat/data-schemas', () => ({
}));
describe('primeResources', () => {
let mockReq: ServerRequest;
let mockReq: ServerRequest & { user?: IUser };
let mockAppConfig: AppConfig;
let mockGetFiles: jest.MockedFunction<TGetFiles>;
let requestFileSet: Set<string>;
@ -22,15 +25,16 @@ describe('primeResources', () => {
jest.clearAllMocks();
// Setup mock request
mockReq = {
app: {
locals: {
[EModelEndpoint.agents]: {
capabilities: [AgentCapabilities.ocr],
},
},
mockReq = {} as unknown as ServerRequest & { user?: IUser };
// Setup mock appConfig
mockAppConfig = {
endpoints: {
[EModelEndpoint.agents]: {
capabilities: [AgentCapabilities.ocr],
} as TAgentsEndpoint,
},
} as unknown as ServerRequest;
} as AppConfig;
// Setup mock getFiles function
mockGetFiles = jest.fn();
@ -65,6 +69,7 @@ describe('primeResources', () => {
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments: undefined,
@ -84,7 +89,7 @@ describe('primeResources', () => {
describe('when OCR is disabled', () => {
it('should not fetch OCR files even if tool_resources has OCR file_ids', async () => {
(mockReq.app as ServerRequest['app']).locals[EModelEndpoint.agents].capabilities = [];
(mockAppConfig.endpoints![EModelEndpoint.agents] as TAgentsEndpoint).capabilities = [];
const tool_resources = {
[EToolResources.ocr]: {
@ -94,6 +99,7 @@ describe('primeResources', () => {
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments: undefined,
@ -129,6 +135,7 @@ describe('primeResources', () => {
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments,
@ -158,6 +165,7 @@ describe('primeResources', () => {
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments,
@ -189,6 +197,7 @@ describe('primeResources', () => {
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments,
@ -220,6 +229,7 @@ describe('primeResources', () => {
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments,
@ -250,6 +260,7 @@ describe('primeResources', () => {
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments,
@ -291,6 +302,7 @@ describe('primeResources', () => {
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments,
@ -342,6 +354,7 @@ describe('primeResources', () => {
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments,
@ -399,6 +412,7 @@ describe('primeResources', () => {
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments,
@ -450,6 +464,7 @@ describe('primeResources', () => {
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments,
@ -492,6 +507,7 @@ describe('primeResources', () => {
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments,
@ -560,6 +576,7 @@ describe('primeResources', () => {
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments,
@ -618,6 +635,7 @@ describe('primeResources', () => {
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments,
@ -671,6 +689,7 @@ describe('primeResources', () => {
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments,
@ -724,6 +743,7 @@ describe('primeResources', () => {
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments,
@ -764,6 +784,7 @@ describe('primeResources', () => {
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments,
@ -838,6 +859,7 @@ describe('primeResources', () => {
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments,
@ -888,6 +910,7 @@ describe('primeResources', () => {
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments,
@ -906,6 +929,7 @@ describe('primeResources', () => {
// The function should now handle rejected attachment promises gracefully
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments,
@ -926,11 +950,13 @@ describe('primeResources', () => {
});
describe('edge cases', () => {
it('should handle missing app.locals gracefully', async () => {
const reqWithoutLocals = {} as ServerRequest;
it('should handle missing appConfig agents endpoint gracefully', async () => {
const reqWithoutLocals = {} as ServerRequest & { user?: IUser };
const emptyAppConfig = {} as AppConfig;
const result = await primeResources({
req: reqWithoutLocals,
appConfig: emptyAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments: undefined,
@ -942,14 +968,15 @@ describe('primeResources', () => {
});
expect(mockGetFiles).not.toHaveBeenCalled();
// When app.locals is missing and there's an error accessing properties,
// the function falls back to the catch block which returns an empty array
expect(result.attachments).toEqual([]);
// When appConfig agents endpoint is missing, OCR is disabled
// and no attachments are provided, the function returns undefined
expect(result.attachments).toBeUndefined();
});
it('should handle undefined tool_resources', async () => {
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet,
attachments: undefined,
@ -982,6 +1009,7 @@ describe('primeResources', () => {
const result = await primeResources({
req: mockReq,
appConfig: mockAppConfig,
getFiles: mockGetFiles,
requestFileSet: emptyRequestFileSet,
attachments,