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

This commit is contained in:
Danny Avila 2025-08-17 17:11:50 -04:00
parent b992fed16c
commit 3ecb96149a
No known key found for this signature in database
GPG key ID: BF31EEB2C5CA0956

View file

@ -1,5 +1,6 @@
const { Providers } = require('@librechat/agents'); const { Providers } = require('@librechat/agents');
const { Constants, EModelEndpoint } = require('librechat-data-provider'); const { Constants, EModelEndpoint } = require('librechat-data-provider');
const { getAppConfig } = require('~/server/services/Config');
const AgentClient = require('./client'); const AgentClient = require('./client');
jest.mock('@librechat/agents', () => ({ jest.mock('@librechat/agents', () => ({
@ -10,6 +11,10 @@ jest.mock('@librechat/agents', () => ({
}), }),
})); }));
jest.mock('~/server/services/Config', () => ({
getAppConfig: jest.fn(),
}));
describe('AgentClient - titleConvo', () => { describe('AgentClient - titleConvo', () => {
let client; let client;
let mockRun; let mockRun;
@ -39,19 +44,19 @@ describe('AgentClient - titleConvo', () => {
}, },
}; };
// Mock getAppConfig to return endpoint configurations
getAppConfig.mockResolvedValue({
[EModelEndpoint.openAI]: {
// Match the agent endpoint
titleModel: 'gpt-3.5-turbo',
titlePrompt: 'Custom title prompt',
titleMethod: 'structured',
titlePromptTemplate: 'Template: {{content}}',
},
});
// Mock request and response // Mock request and response
mockReq = { mockReq = {
app: {
locals: {
[EModelEndpoint.openAI]: {
// Match the agent endpoint
titleModel: 'gpt-3.5-turbo',
titlePrompt: 'Custom title prompt',
titleMethod: 'structured',
titlePromptTemplate: 'Template: {{content}}',
},
},
},
user: { user: {
id: 'user-123', id: 'user-123',
}, },
@ -143,7 +148,7 @@ describe('AgentClient - titleConvo', () => {
it('should handle missing endpoint config gracefully', async () => { it('should handle missing endpoint config gracefully', async () => {
// Remove endpoint config // Remove endpoint config
mockReq.app.locals[EModelEndpoint.openAI] = undefined; getAppConfig.mockResolvedValue({});
const text = 'Test conversation text'; const text = 'Test conversation text';
const abortController = new AbortController(); const abortController = new AbortController();
@ -161,7 +166,14 @@ describe('AgentClient - titleConvo', () => {
it('should use agent model when titleModel is not provided', async () => { it('should use agent model when titleModel is not provided', async () => {
// Remove titleModel from config // Remove titleModel from config
delete mockReq.app.locals[EModelEndpoint.openAI].titleModel; getAppConfig.mockResolvedValue({
[EModelEndpoint.openAI]: {
titlePrompt: 'Custom title prompt',
titleMethod: 'structured',
titlePromptTemplate: 'Template: {{content}}',
// titleModel is omitted
},
});
const text = 'Test conversation text'; const text = 'Test conversation text';
const abortController = new AbortController(); const abortController = new AbortController();
@ -173,7 +185,14 @@ describe('AgentClient - titleConvo', () => {
}); });
it('should not use titleModel when it equals CURRENT_MODEL constant', async () => { it('should not use titleModel when it equals CURRENT_MODEL constant', async () => {
mockReq.app.locals[EModelEndpoint.openAI].titleModel = Constants.CURRENT_MODEL; getAppConfig.mockResolvedValue({
[EModelEndpoint.openAI]: {
titleModel: Constants.CURRENT_MODEL,
titlePrompt: 'Custom title prompt',
titleMethod: 'structured',
titlePromptTemplate: 'Template: {{content}}',
},
});
const text = 'Test conversation text'; const text = 'Test conversation text';
const abortController = new AbortController(); const abortController = new AbortController();
@ -245,10 +264,15 @@ describe('AgentClient - titleConvo', () => {
process.env.ANTHROPIC_API_KEY = 'test-api-key'; process.env.ANTHROPIC_API_KEY = 'test-api-key';
// Add titleEndpoint to the config // Add titleEndpoint to the config
mockReq.app.locals[EModelEndpoint.openAI].titleEndpoint = EModelEndpoint.anthropic; getAppConfig.mockResolvedValue({
mockReq.app.locals[EModelEndpoint.openAI].titleMethod = 'structured'; [EModelEndpoint.openAI]: {
mockReq.app.locals[EModelEndpoint.openAI].titlePrompt = 'Custom title prompt'; titleModel: 'gpt-3.5-turbo',
mockReq.app.locals[EModelEndpoint.openAI].titlePromptTemplate = 'Custom template'; titleEndpoint: EModelEndpoint.anthropic,
titleMethod: 'structured',
titlePrompt: 'Custom title prompt',
titlePromptTemplate: 'Custom template',
},
});
const text = 'Test conversation text'; const text = 'Test conversation text';
const abortController = new AbortController(); const abortController = new AbortController();
@ -274,19 +298,15 @@ describe('AgentClient - titleConvo', () => {
}); });
it('should use all config when endpoint config is missing', async () => { it('should use all config when endpoint config is missing', async () => {
// Remove endpoint-specific config // Set 'all' config without endpoint-specific config
delete mockReq.app.locals[EModelEndpoint.openAI].titleModel; getAppConfig.mockResolvedValue({
delete mockReq.app.locals[EModelEndpoint.openAI].titlePrompt; all: {
delete mockReq.app.locals[EModelEndpoint.openAI].titleMethod; titleModel: 'gpt-4o-mini',
delete mockReq.app.locals[EModelEndpoint.openAI].titlePromptTemplate; titlePrompt: 'All config title prompt',
titleMethod: 'completion',
// Set 'all' config titlePromptTemplate: 'All config template: {{content}}',
mockReq.app.locals.all = { },
titleModel: 'gpt-4o-mini', });
titlePrompt: 'All config title prompt',
titleMethod: 'completion',
titlePromptTemplate: 'All config template: {{content}}',
};
const text = 'Test conversation text'; const text = 'Test conversation text';
const abortController = new AbortController(); const abortController = new AbortController();
@ -309,18 +329,20 @@ describe('AgentClient - titleConvo', () => {
it('should prioritize all config over endpoint config for title settings', async () => { it('should prioritize all config over endpoint config for title settings', async () => {
// Set both endpoint and 'all' config // Set both endpoint and 'all' config
mockReq.app.locals[EModelEndpoint.openAI].titleModel = 'gpt-3.5-turbo'; getAppConfig.mockResolvedValue({
mockReq.app.locals[EModelEndpoint.openAI].titlePrompt = 'Endpoint title prompt'; [EModelEndpoint.openAI]: {
mockReq.app.locals[EModelEndpoint.openAI].titleMethod = 'structured'; titleModel: 'gpt-3.5-turbo',
// Remove titlePromptTemplate from endpoint config to test fallback titlePrompt: 'Endpoint title prompt',
delete mockReq.app.locals[EModelEndpoint.openAI].titlePromptTemplate; titleMethod: 'structured',
// titlePromptTemplate is omitted to test fallback
mockReq.app.locals.all = { },
titleModel: 'gpt-4o-mini', all: {
titlePrompt: 'All config title prompt', titleModel: 'gpt-4o-mini',
titleMethod: 'completion', titlePrompt: 'All config title prompt',
titlePromptTemplate: 'All config template', titleMethod: 'completion',
}; titlePromptTemplate: 'All config template',
},
});
const text = 'Test conversation text'; const text = 'Test conversation text';
const abortController = new AbortController(); const abortController = new AbortController();
@ -346,18 +368,17 @@ describe('AgentClient - titleConvo', () => {
const originalApiKey = process.env.ANTHROPIC_API_KEY; const originalApiKey = process.env.ANTHROPIC_API_KEY;
process.env.ANTHROPIC_API_KEY = 'test-anthropic-key'; process.env.ANTHROPIC_API_KEY = 'test-anthropic-key';
// Remove endpoint-specific config to test 'all' config
delete mockReq.app.locals[EModelEndpoint.openAI];
// Set comprehensive 'all' config with all new title options // Set comprehensive 'all' config with all new title options
mockReq.app.locals.all = { getAppConfig.mockResolvedValue({
titleConvo: true, all: {
titleModel: 'claude-3-haiku-20240307', titleConvo: true,
titleMethod: 'completion', // Testing the new default method titleModel: 'claude-3-haiku-20240307',
titlePrompt: 'Generate a concise, descriptive title for this conversation', titleMethod: 'completion', // Testing the new default method
titlePromptTemplate: 'Conversation summary: {{content}}', titlePrompt: 'Generate a concise, descriptive title for this conversation',
titleEndpoint: EModelEndpoint.anthropic, // Should switch provider to Anthropic titlePromptTemplate: 'Conversation summary: {{content}}',
}; titleEndpoint: EModelEndpoint.anthropic, // Should switch provider to Anthropic
},
});
const text = 'Test conversation about AI and machine learning'; const text = 'Test conversation about AI and machine learning';
const abortController = new AbortController(); const abortController = new AbortController();
@ -402,16 +423,15 @@ describe('AgentClient - titleConvo', () => {
// Clear previous calls // Clear previous calls
mockRun.generateTitle.mockClear(); mockRun.generateTitle.mockClear();
// Remove endpoint config
delete mockReq.app.locals[EModelEndpoint.openAI];
// Set 'all' config with specific titleMethod // Set 'all' config with specific titleMethod
mockReq.app.locals.all = { getAppConfig.mockResolvedValue({
titleModel: 'gpt-4o-mini', all: {
titleMethod: method, titleModel: 'gpt-4o-mini',
titlePrompt: `Testing ${method} method`, titleMethod: method,
titlePromptTemplate: `Template for ${method}: {{content}}`, titlePrompt: `Testing ${method} method`,
}; titlePromptTemplate: `Template for ${method}: {{content}}`,
},
});
const text = `Test conversation for ${method} method`; const text = `Test conversation for ${method} method`;
const abortController = new AbortController(); const abortController = new AbortController();
@ -455,32 +475,34 @@ describe('AgentClient - titleConvo', () => {
// Set up Azure endpoint with serverless config // Set up Azure endpoint with serverless config
mockAgent.endpoint = EModelEndpoint.azureOpenAI; mockAgent.endpoint = EModelEndpoint.azureOpenAI;
mockAgent.provider = EModelEndpoint.azureOpenAI; mockAgent.provider = EModelEndpoint.azureOpenAI;
mockReq.app.locals[EModelEndpoint.azureOpenAI] = { getAppConfig.mockResolvedValue({
titleConvo: true, [EModelEndpoint.azureOpenAI]: {
titleModel: 'grok-3', titleConvo: true,
titleMethod: 'completion', titleModel: 'grok-3',
titlePrompt: 'Azure serverless title prompt', titleMethod: 'completion',
streamRate: 35, titlePrompt: 'Azure serverless title prompt',
modelGroupMap: { streamRate: 35,
'grok-3': { modelGroupMap: {
group: 'Azure AI Foundry', 'grok-3': {
deploymentName: 'grok-3', group: 'Azure AI Foundry',
deploymentName: 'grok-3',
},
}, },
}, groupMap: {
groupMap: { 'Azure AI Foundry': {
'Azure AI Foundry': { apiKey: '${AZURE_API_KEY}',
apiKey: '${AZURE_API_KEY}', baseURL: 'https://test.services.ai.azure.com/models',
baseURL: 'https://test.services.ai.azure.com/models', version: '2024-05-01-preview',
version: '2024-05-01-preview', serverless: true,
serverless: true, models: {
models: { 'grok-3': {
'grok-3': { deploymentName: 'grok-3',
deploymentName: 'grok-3', },
}, },
}, },
}, },
}, },
}; });
mockReq.body.endpoint = EModelEndpoint.azureOpenAI; mockReq.body.endpoint = EModelEndpoint.azureOpenAI;
mockReq.body.model = 'grok-3'; mockReq.body.model = 'grok-3';
@ -503,31 +525,33 @@ describe('AgentClient - titleConvo', () => {
// Set up Azure endpoint // Set up Azure endpoint
mockAgent.endpoint = EModelEndpoint.azureOpenAI; mockAgent.endpoint = EModelEndpoint.azureOpenAI;
mockAgent.provider = EModelEndpoint.azureOpenAI; mockAgent.provider = EModelEndpoint.azureOpenAI;
mockReq.app.locals[EModelEndpoint.azureOpenAI] = { getAppConfig.mockResolvedValue({
titleConvo: true, [EModelEndpoint.azureOpenAI]: {
titleModel: 'gpt-4o', titleConvo: true,
titleMethod: 'structured', titleModel: 'gpt-4o',
titlePrompt: 'Azure instance title prompt', titleMethod: 'structured',
streamRate: 35, titlePrompt: 'Azure instance title prompt',
modelGroupMap: { streamRate: 35,
'gpt-4o': { modelGroupMap: {
group: 'eastus', 'gpt-4o': {
deploymentName: 'gpt-4o', group: 'eastus',
deploymentName: 'gpt-4o',
},
}, },
}, groupMap: {
groupMap: { eastus: {
eastus: { apiKey: '${EASTUS_API_KEY}',
apiKey: '${EASTUS_API_KEY}', instanceName: 'region-instance',
instanceName: 'region-instance', version: '2024-02-15-preview',
version: '2024-02-15-preview', models: {
models: { 'gpt-4o': {
'gpt-4o': { deploymentName: 'gpt-4o',
deploymentName: 'gpt-4o', },
}, },
}, },
}, },
}, },
}; });
mockReq.body.endpoint = EModelEndpoint.azureOpenAI; mockReq.body.endpoint = EModelEndpoint.azureOpenAI;
mockReq.body.model = 'gpt-4o'; mockReq.body.model = 'gpt-4o';
@ -551,32 +575,34 @@ describe('AgentClient - titleConvo', () => {
mockAgent.endpoint = EModelEndpoint.azureOpenAI; mockAgent.endpoint = EModelEndpoint.azureOpenAI;
mockAgent.provider = EModelEndpoint.azureOpenAI; mockAgent.provider = EModelEndpoint.azureOpenAI;
mockAgent.model_parameters.model = 'gpt-4o-latest'; mockAgent.model_parameters.model = 'gpt-4o-latest';
mockReq.app.locals[EModelEndpoint.azureOpenAI] = { getAppConfig.mockResolvedValue({
titleConvo: true, [EModelEndpoint.azureOpenAI]: {
titleModel: Constants.CURRENT_MODEL, titleConvo: true,
titleMethod: 'functions', titleModel: Constants.CURRENT_MODEL,
streamRate: 35, titleMethod: 'functions',
modelGroupMap: { streamRate: 35,
'gpt-4o-latest': { modelGroupMap: {
group: 'region-eastus', 'gpt-4o-latest': {
deploymentName: 'gpt-4o-mini', group: 'region-eastus',
version: '2024-02-15-preview', deploymentName: 'gpt-4o-mini',
version: '2024-02-15-preview',
},
}, },
}, groupMap: {
groupMap: { 'region-eastus': {
'region-eastus': { apiKey: '${EASTUS2_API_KEY}',
apiKey: '${EASTUS2_API_KEY}', instanceName: 'test-instance',
instanceName: 'test-instance', version: '2024-12-01-preview',
version: '2024-12-01-preview', models: {
models: { 'gpt-4o-latest': {
'gpt-4o-latest': { deploymentName: 'gpt-4o-mini',
deploymentName: 'gpt-4o-mini', version: '2024-02-15-preview',
version: '2024-02-15-preview', },
}, },
}, },
}, },
}, },
}; });
mockReq.body.endpoint = EModelEndpoint.azureOpenAI; mockReq.body.endpoint = EModelEndpoint.azureOpenAI;
mockReq.body.model = 'gpt-4o-latest'; mockReq.body.model = 'gpt-4o-latest';
@ -598,59 +624,61 @@ describe('AgentClient - titleConvo', () => {
// Set up Azure endpoint // Set up Azure endpoint
mockAgent.endpoint = EModelEndpoint.azureOpenAI; mockAgent.endpoint = EModelEndpoint.azureOpenAI;
mockAgent.provider = EModelEndpoint.azureOpenAI; mockAgent.provider = EModelEndpoint.azureOpenAI;
mockReq.app.locals[EModelEndpoint.azureOpenAI] = { getAppConfig.mockResolvedValue({
titleConvo: true, [EModelEndpoint.azureOpenAI]: {
titleModel: 'o1-mini', titleConvo: true,
titleMethod: 'completion', titleModel: 'o1-mini',
streamRate: 35, titleMethod: 'completion',
modelGroupMap: { streamRate: 35,
'gpt-4o': { modelGroupMap: {
group: 'eastus', 'gpt-4o': {
deploymentName: 'gpt-4o', group: 'eastus',
}, deploymentName: 'gpt-4o',
'o1-mini': { },
group: 'region-eastus', 'o1-mini': {
deploymentName: 'o1-mini', group: 'region-eastus',
}, deploymentName: 'o1-mini',
'codex-mini': { },
group: 'codex-mini', 'codex-mini': {
deploymentName: 'codex-mini', group: 'codex-mini',
}, deploymentName: 'codex-mini',
},
groupMap: {
eastus: {
apiKey: '${EASTUS_API_KEY}',
instanceName: 'region-eastus',
version: '2024-02-15-preview',
models: {
'gpt-4o': {
deploymentName: 'gpt-4o',
},
}, },
}, },
'region-eastus': { groupMap: {
apiKey: '${EASTUS2_API_KEY}', eastus: {
instanceName: 'region-eastus2', apiKey: '${EASTUS_API_KEY}',
version: '2024-12-01-preview', instanceName: 'region-eastus',
models: { version: '2024-02-15-preview',
'o1-mini': { models: {
deploymentName: 'o1-mini', 'gpt-4o': {
deploymentName: 'gpt-4o',
},
}, },
}, },
}, 'region-eastus': {
'codex-mini': { apiKey: '${EASTUS2_API_KEY}',
apiKey: '${AZURE_API_KEY}', instanceName: 'region-eastus2',
baseURL: 'https://example.cognitiveservices.azure.com/openai/', version: '2024-12-01-preview',
version: '2025-04-01-preview', models: {
serverless: true, 'o1-mini': {
models: { deploymentName: 'o1-mini',
'codex-mini': { },
deploymentName: 'codex-mini', },
},
'codex-mini': {
apiKey: '${AZURE_API_KEY}',
baseURL: 'https://example.cognitiveservices.azure.com/openai/',
version: '2025-04-01-preview',
serverless: true,
models: {
'codex-mini': {
deploymentName: 'codex-mini',
},
}, },
}, },
}, },
}, },
}; });
mockReq.body.endpoint = EModelEndpoint.azureOpenAI; mockReq.body.endpoint = EModelEndpoint.azureOpenAI;
mockReq.body.model = 'o1-mini'; mockReq.body.model = 'o1-mini';
@ -679,36 +707,35 @@ describe('AgentClient - titleConvo', () => {
mockReq.body.endpoint = EModelEndpoint.azureOpenAI; mockReq.body.endpoint = EModelEndpoint.azureOpenAI;
mockReq.body.model = 'gpt-4'; mockReq.body.model = 'gpt-4';
// Remove Azure-specific config
delete mockReq.app.locals[EModelEndpoint.azureOpenAI];
// Set 'all' config as fallback with a serverless Azure config // Set 'all' config as fallback with a serverless Azure config
mockReq.app.locals.all = { getAppConfig.mockResolvedValue({
titleConvo: true, all: {
titleModel: 'gpt-4', titleConvo: true,
titleMethod: 'structured', titleModel: 'gpt-4',
titlePrompt: 'Fallback title prompt from all config', titleMethod: 'structured',
titlePromptTemplate: 'Template: {{content}}', titlePrompt: 'Fallback title prompt from all config',
modelGroupMap: { titlePromptTemplate: 'Template: {{content}}',
'gpt-4': { modelGroupMap: {
group: 'default-group', 'gpt-4': {
deploymentName: 'gpt-4', group: 'default-group',
deploymentName: 'gpt-4',
},
}, },
}, groupMap: {
groupMap: { 'default-group': {
'default-group': { apiKey: '${AZURE_API_KEY}',
apiKey: '${AZURE_API_KEY}', baseURL: 'https://default.openai.azure.com/',
baseURL: 'https://default.openai.azure.com/', version: '2024-02-15-preview',
version: '2024-02-15-preview', serverless: true,
serverless: true, models: {
models: { 'gpt-4': {
'gpt-4': { deploymentName: 'gpt-4',
deploymentName: 'gpt-4', },
}, },
}, },
}, },
}, },
}; });
const text = 'Test Azure with all config fallback'; const text = 'Test Azure with all config fallback';
const abortController = new AbortController(); const abortController = new AbortController();
@ -982,13 +1009,6 @@ describe('AgentClient - titleConvo', () => {
}; };
mockReq = { mockReq = {
app: {
locals: {
memory: {
messageWindowSize: 3,
},
},
},
user: { user: {
id: 'user-123', id: 'user-123',
personalization: { personalization: {
@ -997,6 +1017,13 @@ describe('AgentClient - titleConvo', () => {
}, },
}; };
// Mock getAppConfig for memory tests
getAppConfig.mockResolvedValue({
memory: {
messageWindowSize: 3,
},
});
mockRes = {}; mockRes = {};
mockOptions = { mockOptions = {