diff --git a/packages/api/src/web/web.spec.ts b/packages/api/src/web/web.spec.ts index a33a6e1eb1..4ba9e70e48 100644 --- a/packages/api/src/web/web.spec.ts +++ b/packages/api/src/web/web.spec.ts @@ -689,8 +689,7 @@ describe('web.ts', () => { const originalEnv = process.env; process.env = { ...originalEnv, - SERPER_API_KEY: 'test-key', - // Missing other keys to force authentication failure + JINA_API_KEY: 'test-key', }; // Initialize webSearchConfig with environment variable references @@ -710,10 +709,9 @@ describe('web.ts', () => { mockLoadAuthValues.mockImplementation(({ authFields }) => { const result: Record = {}; authFields.forEach((field: string) => { - if (field === 'SERPER_API_KEY') { + if (field === 'JINA_API_KEY') { result[field] = 'test-key'; } - // Other fields are intentionally missing }); return Promise.resolve(result); }); @@ -1106,6 +1104,47 @@ describe('web.ts', () => { expect(cohereCalls.length).toBe(0); }); + it('should fallback to no reranker when rerankerType is omitted and no reranker is authenticated', async () => { + const webSearchConfig: TCustomConfig['webSearch'] = { + searxngInstanceUrl: '${SEARXNG_INSTANCE_URL}', + searxngApiKey: '${SEARXNG_API_KEY}', + firecrawlApiKey: '${FIRECRAWL_API_KEY}', + firecrawlApiUrl: '${FIRECRAWL_API_URL}', + jinaApiKey: '${JINA_API_KEY}', + jinaApiUrl: '${JINA_API_URL}', + cohereApiKey: '${COHERE_API_KEY}', + safeSearch: SafeSearchTypes.MODERATE, + searchProvider: 'searxng' as SearchProviders, + scraperProvider: 'firecrawl' as ScraperProviders, + }; + + mockLoadAuthValues.mockImplementation(({ authFields }) => { + const result: Record = {}; + authFields.forEach((field: string) => { + if (field === 'SEARXNG_INSTANCE_URL') { + result[field] = 'https://search.example'; + } else if (field === 'SEARXNG_API_KEY') { + result[field] = 'searxng-api-key'; + } else if (field === 'FIRECRAWL_API_KEY') { + result[field] = 'firecrawl-api-key'; + } else if (field === 'FIRECRAWL_API_URL') { + result[field] = 'https://api.firecrawl.dev'; + } + }); + return Promise.resolve(result); + }); + + const result = await loadWebSearchAuth({ + userId, + webSearchConfig, + loadAuthValues: mockLoadAuthValues, + }); + + expect(result.authenticated).toBe(true); + expect(result.authResult.rerankerType).toBe('none'); + expect(result.authTypes).toContainEqual(['rerankers', AuthType.SYSTEM_DEFINED]); + }); + it('should handle invalid specified service gracefully', async () => { // Initialize a webSearchConfig with an invalid searchProvider const webSearchConfig: TCustomConfig['webSearch'] = { diff --git a/packages/api/src/web/web.ts b/packages/api/src/web/web.ts index 06d65d4d98..d43649947d 100644 --- a/packages/api/src/web/web.ts +++ b/packages/api/src/web/web.ts @@ -7,11 +7,7 @@ import { extractVariableName, } from 'librechat-data-provider'; import { webSearchAuth } from '@librechat/data-schemas'; -import type { - RerankerTypes, - TCustomConfig, - TWebSearchConfig, -} from 'librechat-data-provider'; +import type { RerankerTypes, TCustomConfig, TWebSearchConfig } from 'librechat-data-provider'; import type { TWebSearchKeys, TWebSearchCategories } from '@librechat/data-schemas'; import { isSSRFTarget, resolveHostnameSSRF } from '../auth'; @@ -209,8 +205,7 @@ export async function loadWebSearchAuth({ const isUserProvidedOptInUrlKey = originalKey != null && USER_PROVIDED_OPT_IN_URL_KEYS.has(originalKey); const isUserProvidedUrlEnabled = - isUserProvidedUrlKey || - (isUserProvidedOptInUrlKey && isUserProvidedEnabled(field)); + isUserProvidedUrlKey || (isUserProvidedOptInUrlKey && isUserProvidedEnabled(field)); let contributed = false; if (isUserProvidedOptInUrlKey && isFieldUserProvided && !isUserProvidedUrlEnabled) { @@ -253,6 +248,10 @@ export async function loadWebSearchAuth({ continue; } } + if (category === SearchCategories.RERANKERS && !webSearchConfig?.rerankerType) { + authResult.rerankerType = 'none' as RerankerTypes; + return [true, false]; + } return [false, isUserProvided]; }