const { Providers } = require('@librechat/agents'); const { AuthKeys } = require('librechat-data-provider'); // Example internal constant from your code const EXCLUDED_GENAI_MODELS = /gemini-(?:1\.0|1-0|pro)/; /** * * @param {boolean} isGemini2 * @returns {Array<{category: string, threshold: string}>} */ function getSafetySettings(isGemini2) { const mapThreshold = (value) => { if (isGemini2 && value === 'BLOCK_NONE') { return 'OFF'; } return value; }; return [ { category: 'HARM_CATEGORY_SEXUALLY_EXPLICIT', threshold: mapThreshold( process.env.GOOGLE_SAFETY_SEXUALLY_EXPLICIT || 'HARM_BLOCK_THRESHOLD_UNSPECIFIED', ), }, { category: 'HARM_CATEGORY_HATE_SPEECH', threshold: mapThreshold( process.env.GOOGLE_SAFETY_HATE_SPEECH || 'HARM_BLOCK_THRESHOLD_UNSPECIFIED', ), }, { category: 'HARM_CATEGORY_HARASSMENT', threshold: mapThreshold( process.env.GOOGLE_SAFETY_HARASSMENT || 'HARM_BLOCK_THRESHOLD_UNSPECIFIED', ), }, { category: 'HARM_CATEGORY_DANGEROUS_CONTENT', threshold: mapThreshold( process.env.GOOGLE_SAFETY_DANGEROUS_CONTENT || 'HARM_BLOCK_THRESHOLD_UNSPECIFIED', ), }, { category: 'HARM_CATEGORY_CIVIC_INTEGRITY', threshold: mapThreshold(process.env.GOOGLE_SAFETY_CIVIC_INTEGRITY || 'BLOCK_NONE'), }, ]; } /** * Replicates core logic from GoogleClient's constructor and setOptions, plus client determination. * Returns an object with the provider label and the final options that would be passed to createLLM. * * @param {string | object} credentials - Either a JSON string or an object containing Google keys * @param {object} [options={}] - The same shape as the "GoogleClient" constructor options */ function getLLMConfig(credentials, options = {}) { // 1. Parse credentials let creds = {}; if (typeof credentials === 'string') { try { creds = JSON.parse(credentials); } catch (err) { throw new Error(`Error parsing string credentials: ${err.message}`); } } else if (credentials && typeof credentials === 'object') { creds = credentials; } // Extract from credentials const serviceKeyRaw = creds[AuthKeys.GOOGLE_SERVICE_KEY] ?? {}; const serviceKey = typeof serviceKeyRaw === 'string' ? JSON.parse(serviceKeyRaw) : serviceKeyRaw ?? {}; const project_id = serviceKey?.project_id ?? null; const apiKey = creds[AuthKeys.GOOGLE_API_KEY] ?? null; const reverseProxyUrl = options.reverseProxyUrl; const authHeader = options.authHeader; /** @type {GoogleClientOptions | VertexAIClientOptions} */ let llmConfig = { ...(options.modelOptions || {}), maxRetries: 2, }; const isGemini2 = llmConfig.model.includes('gemini-2.0'); const isGenerativeModel = llmConfig.model.includes('gemini'); const isChatModel = !isGenerativeModel && llmConfig.model.includes('chat'); const isTextModel = !isGenerativeModel && !isChatModel && /code|text/.test(llmConfig.model); llmConfig.safetySettings = getSafetySettings(isGemini2); let provider; if (project_id && isTextModel) { provider = Providers.VERTEXAI; } else if (project_id && isChatModel) { provider = Providers.VERTEXAI; } else if (project_id) { provider = Providers.VERTEXAI; } else if (!EXCLUDED_GENAI_MODELS.test(llmConfig.model)) { provider = Providers.GOOGLE; } else { provider = Providers.GOOGLE; } // If we have a GCP project => Vertex AI if (project_id && provider === Providers.VERTEXAI) { /** @type {VertexAIClientOptions['authOptions']} */ llmConfig.authOptions = { credentials: { ...serviceKey }, projectId: project_id, }; llmConfig.location = process.env.GOOGLE_LOC || 'us-central1'; } else if (apiKey && provider === Providers.GOOGLE) { llmConfig.apiKey = apiKey; } /* let legacyOptions = {}; // Filter out any "examples" that are empty legacyOptions.examples = (legacyOptions.examples ?? []) .filter(Boolean) .filter((obj) => obj?.input?.content !== '' && obj?.output?.content !== ''); // If user has "examples" from legacyOptions, push them onto llmConfig if (legacyOptions.examples?.length) { llmConfig.examples = legacyOptions.examples.map((ex) => { const { input, output } = ex; if (!input?.content || !output?.content) {return undefined;} return { input: new HumanMessage(input.content), output: new AIMessage(output.content), }; }).filter(Boolean); } */ if (reverseProxyUrl) { llmConfig.baseUrl = reverseProxyUrl; } if (authHeader) { /** * NOTE: NOT SUPPORTED BY LANGCHAIN GENAI CLIENT, * REQUIRES PR IN https://github.com/langchain-ai/langchainjs */ llmConfig.customHeaders = { Authorization: `Bearer ${apiKey}`, }; } // Return the final shape return { /** @type {Providers.GOOGLE | Providers.VERTEXAI} */ provider, /** @type {GoogleClientOptions | VertexAIClientOptions} */ llmConfig, }; } module.exports = { getLLMConfig, };