mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 00:40:14 +01:00
🛡️ fix: Title Generation Skip Logic Based On Endpoint Config (#9811)
This commit is contained in:
parent
b85950aa9a
commit
f9aebeba92
3 changed files with 132 additions and 1 deletions
|
|
@ -1121,6 +1121,13 @@ class AgentClient extends BaseClient {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (endpointConfig?.titleConvo === false) {
|
||||||
|
logger.debug(
|
||||||
|
`[api/server/controllers/agents/client.js #titleConvo] Title generation disabled for endpoint "${endpoint}"`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (endpointConfig?.titleEndpoint && endpointConfig.titleEndpoint !== endpoint) {
|
if (endpointConfig?.titleEndpoint && endpointConfig.titleEndpoint !== endpoint) {
|
||||||
try {
|
try {
|
||||||
titleProviderConfig = getProviderConfig({
|
titleProviderConfig = getProviderConfig({
|
||||||
|
|
@ -1130,7 +1137,7 @@ class AgentClient extends BaseClient {
|
||||||
endpoint = endpointConfig.titleEndpoint;
|
endpoint = endpointConfig.titleEndpoint;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
`[api/server/controllers/agents/client.js #titleConvo] Error getting title endpoint config for ${endpointConfig.titleEndpoint}, falling back to default`,
|
`[api/server/controllers/agents/client.js #titleConvo] Error getting title endpoint config for "${endpointConfig.titleEndpoint}", falling back to default`,
|
||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
// Fall back to original provider config
|
// Fall back to original provider config
|
||||||
|
|
|
||||||
|
|
@ -263,6 +263,125 @@ describe('AgentClient - titleConvo', () => {
|
||||||
expect(result).toBeUndefined();
|
expect(result).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should skip title generation when titleConvo is set to false', async () => {
|
||||||
|
// Set titleConvo to false in endpoint config
|
||||||
|
mockReq.config = {
|
||||||
|
endpoints: {
|
||||||
|
[EModelEndpoint.openAI]: {
|
||||||
|
titleConvo: false,
|
||||||
|
titleModel: 'gpt-3.5-turbo',
|
||||||
|
titlePrompt: 'Custom title prompt',
|
||||||
|
titleMethod: 'structured',
|
||||||
|
titlePromptTemplate: 'Template: {{content}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const text = 'Test conversation text';
|
||||||
|
const abortController = new AbortController();
|
||||||
|
|
||||||
|
const result = await client.titleConvo({ text, abortController });
|
||||||
|
|
||||||
|
// Should return undefined without generating title
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
|
||||||
|
// generateTitle should NOT have been called
|
||||||
|
expect(mockRun.generateTitle).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
// recordCollectedUsage should NOT have been called
|
||||||
|
expect(client.recordCollectedUsage).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should skip title generation when titleConvo is false in all config', async () => {
|
||||||
|
// Set titleConvo to false in "all" config
|
||||||
|
mockReq.config = {
|
||||||
|
endpoints: {
|
||||||
|
all: {
|
||||||
|
titleConvo: false,
|
||||||
|
titleModel: 'gpt-4o-mini',
|
||||||
|
titlePrompt: 'All config title prompt',
|
||||||
|
titleMethod: 'completion',
|
||||||
|
titlePromptTemplate: 'All config template',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const text = 'Test conversation text';
|
||||||
|
const abortController = new AbortController();
|
||||||
|
|
||||||
|
const result = await client.titleConvo({ text, abortController });
|
||||||
|
|
||||||
|
// Should return undefined without generating title
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
|
||||||
|
// generateTitle should NOT have been called
|
||||||
|
expect(mockRun.generateTitle).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
// recordCollectedUsage should NOT have been called
|
||||||
|
expect(client.recordCollectedUsage).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should skip title generation when titleConvo is false for custom endpoint scenario', async () => {
|
||||||
|
// This test validates the behavior when customEndpointConfig (retrieved via
|
||||||
|
// getProviderConfig for custom endpoints) has titleConvo: false.
|
||||||
|
//
|
||||||
|
// The code path is:
|
||||||
|
// 1. endpoints?.all is checked (undefined in this test)
|
||||||
|
// 2. endpoints?.[endpoint] is checked (our test config)
|
||||||
|
// 3. Would fall back to titleProviderConfig.customEndpointConfig (for real custom endpoints)
|
||||||
|
//
|
||||||
|
// We simulate a custom endpoint scenario using a dynamically named endpoint config
|
||||||
|
|
||||||
|
// Create a unique endpoint name that represents a custom endpoint
|
||||||
|
const customEndpointName = 'customEndpoint';
|
||||||
|
|
||||||
|
// Configure the endpoint to have titleConvo: false
|
||||||
|
// This simulates what would be in customEndpointConfig for a real custom endpoint
|
||||||
|
mockReq.config = {
|
||||||
|
endpoints: {
|
||||||
|
// No 'all' config - so it will check endpoints[endpoint]
|
||||||
|
// This config represents what customEndpointConfig would contain
|
||||||
|
[customEndpointName]: {
|
||||||
|
titleConvo: false,
|
||||||
|
titleModel: 'custom-model-v1',
|
||||||
|
titlePrompt: 'Custom endpoint title prompt',
|
||||||
|
titleMethod: 'completion',
|
||||||
|
titlePromptTemplate: 'Custom template: {{content}}',
|
||||||
|
baseURL: 'https://api.custom-llm.com/v1',
|
||||||
|
apiKey: 'test-custom-key',
|
||||||
|
// Additional custom endpoint properties
|
||||||
|
models: {
|
||||||
|
default: ['custom-model-v1', 'custom-model-v2'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set up agent to use our custom endpoint
|
||||||
|
// Use openAI as base but override with custom endpoint name for this test
|
||||||
|
mockAgent.endpoint = EModelEndpoint.openAI;
|
||||||
|
mockAgent.provider = EModelEndpoint.openAI;
|
||||||
|
|
||||||
|
// Override the endpoint in the config to point to our custom config
|
||||||
|
mockReq.config.endpoints[EModelEndpoint.openAI] =
|
||||||
|
mockReq.config.endpoints[customEndpointName];
|
||||||
|
delete mockReq.config.endpoints[customEndpointName];
|
||||||
|
|
||||||
|
const text = 'Test custom endpoint conversation';
|
||||||
|
const abortController = new AbortController();
|
||||||
|
|
||||||
|
const result = await client.titleConvo({ text, abortController });
|
||||||
|
|
||||||
|
// Should return undefined without generating title because titleConvo is false
|
||||||
|
expect(result).toBeUndefined();
|
||||||
|
|
||||||
|
// generateTitle should NOT have been called
|
||||||
|
expect(mockRun.generateTitle).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
// recordCollectedUsage should NOT have been called
|
||||||
|
expect(client.recordCollectedUsage).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
it('should pass titleEndpoint configuration to generateTitle', async () => {
|
it('should pass titleEndpoint configuration to generateTitle', async () => {
|
||||||
// Mock the API key just for this test
|
// Mock the API key just for this test
|
||||||
const originalApiKey = process.env.ANTHROPIC_API_KEY;
|
const originalApiKey = process.env.ANTHROPIC_API_KEY;
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,11 @@ const addTitle = async (req, { text, response, client }) => {
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!title) {
|
||||||
|
logger.debug(`[${key}] No title generated`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
await titleCache.set(key, title, 120000);
|
await titleCache.set(key, title, 120000);
|
||||||
await saveConvo(
|
await saveConvo(
|
||||||
req,
|
req,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue