Merge branch 'main' into feat/model-spec-group-icons

This commit is contained in:
Odrec 2025-12-10 14:05:12 +01:00 committed by GitHub
commit 94819c7d0c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 12319 additions and 35 deletions

View file

@ -317,14 +317,22 @@ const loadTools = async ({
requestedTools[tool] = async () => {
toolContextMap[tool] = `# \`${tool}\`:
Current Date & Time: ${replaceSpecialVars({ text: '{{iso_datetime}}' })}
1. **Execute immediately without preface** when using \`${tool}\`.
2. **After the search, begin with a brief summary** that directly addresses the query without headers or explaining your process.
3. **Structure your response clearly** using Markdown formatting (Level 2 headers for sections, lists for multiple points, tables for comparisons).
4. **Cite sources properly** according to the citation anchor format, utilizing group anchors when appropriate.
5. **Tailor your approach to the query type** (academic, news, coding, etc.) while maintaining an expert, journalistic, unbiased tone.
6. **Provide comprehensive information** with specific details, examples, and as much relevant context as possible from search results.
7. **Avoid moralizing language.**
`.trim();
**Execute immediately without preface.** After search, provide a brief summary addressing the query directly, then structure your response with clear Markdown formatting (## headers, lists, tables). Cite sources properly, tailor tone to query type, and provide comprehensive details.
**CITATION FORMAT - INVISIBLE UNICODE ANCHORS ONLY:**
Use these Unicode characters: \\ue202 (before each anchor), \\ue200 (group start), \\ue201 (group end), \\ue203 (highlight start), \\ue204 (highlight end)
Anchor pattern: turn{N}{type}{index} where N=turn number, type=search|news|image|ref, index=0,1,2...
**Examples:**
- Single: "Statement.\\ue202turn0search0"
- Multiple: "Statement.\\ue202turn0search0\\ue202turn0news1"
- Group: "Statement. \\ue200\\ue202turn0search0\\ue202turn0news1\\ue201"
- Highlight: "\\ue203Cited text.\\ue204\\ue202turn0search0"
- Image: "See photo\\ue202turn0image0."
**CRITICAL:** Place anchors AFTER punctuation. Cite every non-obvious fact/quote. NEVER use markdown links, [1], footnotes, or HTML tags.`.trim();
return createSearchTool({
...result.authResult,
onSearchResults,

View file

@ -47,7 +47,7 @@
"@langchain/google-genai": "^0.2.13",
"@langchain/google-vertexai": "^0.2.13",
"@langchain/textsplitters": "^0.1.0",
"@librechat/agents": "^3.0.36",
"@librechat/agents": "^3.0.50",
"@librechat/api": "*",
"@librechat/data-schemas": "*",
"@microsoft/microsoft-graph-client": "^3.0.7",

View file

@ -3,7 +3,8 @@ const fs = require('fs').promises;
const FormData = require('form-data');
const { Readable } = require('stream');
const { logger } = require('@librechat/data-schemas');
const { genAzureEndpoint } = require('@librechat/api');
const { HttpsProxyAgent } = require('https-proxy-agent');
const { genAzureEndpoint, logAxiosError } = require('@librechat/api');
const { extractEnvVariable, STTProviders } = require('librechat-data-provider');
const { getAppConfig } = require('~/server/services/Config');
@ -34,6 +35,34 @@ const MIME_TO_EXTENSION_MAP = {
'audio/x-flac': 'flac',
};
/**
* Validates and extracts ISO-639-1 language code from a locale string.
* @param {string} language - The language/locale string (e.g., "en-US", "en", "zh-CN")
* @returns {string|null} The ISO-639-1 language code (e.g., "en") or null if invalid
*/
function getValidatedLanguageCode(language) {
try {
if (!language) {
return null;
}
const normalizedLanguage = language.toLowerCase();
const isValidLocaleCode = /^[a-z]{2}(-[a-z]{2})?$/.test(normalizedLanguage);
if (isValidLocaleCode) {
return normalizedLanguage.split('-')[0];
}
logger.warn(
`[STT] Invalid language format "${language}". Expected ISO-639-1 locale code like "en-US" or "en". Skipping language parameter.`,
);
return null;
} catch (error) {
logger.error(`[STT] Error validating language code "${language}":`, error);
return null;
}
}
/**
* Gets the file extension from the MIME type.
* @param {string} mimeType - The MIME type.
@ -172,10 +201,9 @@ class STTService {
model: sttSchema.model,
};
if (language) {
/** Converted locale code (e.g., "en-US") to ISO-639-1 format (e.g., "en") */
const isoLanguage = language.split('-')[0];
data.language = isoLanguage;
const validLanguage = getValidatedLanguageCode(language);
if (validLanguage) {
data.language = validLanguage;
}
const headers = {
@ -220,10 +248,9 @@ class STTService {
contentType: audioFile.mimetype,
});
if (language) {
/** Converted locale code (e.g., "en-US") to ISO-639-1 format (e.g., "en") */
const isoLanguage = language.split('-')[0];
formData.append('language', isoLanguage);
const validLanguage = getValidatedLanguageCode(language);
if (validLanguage) {
formData.append('language', validLanguage);
}
const headers = {
@ -266,8 +293,14 @@ class STTService {
language,
);
const options = { headers };
if (process.env.PROXY) {
options.httpsAgent = new HttpsProxyAgent(process.env.PROXY);
}
try {
const response = await axios.post(url, data, { headers });
const response = await axios.post(url, data, options);
if (response.status !== 200) {
throw new Error('Invalid response from the STT API');
@ -279,7 +312,7 @@ class STTService {
return response.data.text.trim();
} catch (error) {
logger.error(`STT request failed for provider ${provider}:`, error);
logAxiosError({ message: `STT request failed for provider ${provider}:`, error });
throw error;
}
}
@ -309,7 +342,7 @@ class STTService {
const text = await this.sttRequest(provider, sttSchema, { audioBuffer, audioFile, language });
res.json({ text });
} catch (error) {
logger.error('An error occurred while processing the audio:', error);
logAxiosError({ message: 'An error occurred while processing the audio:', error });
res.sendStatus(500);
} finally {
try {

View file

@ -1,6 +1,7 @@
const axios = require('axios');
const { logger } = require('@librechat/data-schemas');
const { genAzureEndpoint } = require('@librechat/api');
const { HttpsProxyAgent } = require('https-proxy-agent');
const { genAzureEndpoint, logAxiosError } = require('@librechat/api');
const { extractEnvVariable, TTSProviders } = require('librechat-data-provider');
const { getRandomVoiceId, createChunkProcessor, splitTextIntoChunks } = require('./streamAudio');
const { getAppConfig } = require('~/server/services/Config');
@ -266,10 +267,14 @@ class TTSService {
const options = { headers, responseType: stream ? 'stream' : 'arraybuffer' };
if (process.env.PROXY) {
options.httpsAgent = new HttpsProxyAgent(process.env.PROXY);
}
try {
return await axios.post(url, data, options);
} catch (error) {
logger.error(`TTS request failed for provider ${provider}:`, error);
logAxiosError({ message: `TTS request failed for provider ${provider}:`, error });
throw error;
}
}
@ -325,7 +330,10 @@ class TTSService {
break;
}
} catch (innerError) {
logger.error('Error processing manual update:', chunk, innerError);
logAxiosError({
message: `[TTS] Error processing manual update for chunk: ${chunk?.text?.substring(0, 50)}...`,
error: innerError,
});
if (!res.headersSent) {
return res.status(500).end();
}
@ -337,7 +345,7 @@ class TTSService {
res.end();
}
} catch (error) {
logger.error('Error creating the audio stream:', error);
logAxiosError({ message: '[TTS] Error creating the audio stream:', error });
if (!res.headersSent) {
return res.status(500).send('An error occurred');
}
@ -407,7 +415,10 @@ class TTSService {
break;
}
} catch (innerError) {
logger.error('Error processing audio stream update:', update, innerError);
logAxiosError({
message: `[TTS] Error processing audio stream update: ${update?.text?.substring(0, 50)}...`,
error: innerError,
});
if (!res.headersSent) {
return res.status(500).end();
}
@ -424,7 +435,7 @@ class TTSService {
res.end();
}
} catch (error) {
logger.error('Failed to fetch audio:', error);
logAxiosError({ message: '[TTS] Failed to fetch audio:', error });
if (!res.headersSent) {
res.status(500).end();
}

12229
bun.lock Normal file

File diff suppressed because it is too large Load diff

BIN
bun.lockb

Binary file not shown.

10
package-lock.json generated
View file

@ -61,7 +61,7 @@
"@langchain/google-genai": "^0.2.13",
"@langchain/google-vertexai": "^0.2.13",
"@langchain/textsplitters": "^0.1.0",
"@librechat/agents": "^3.0.36",
"@librechat/agents": "^3.0.50",
"@librechat/api": "*",
"@librechat/data-schemas": "*",
"@microsoft/microsoft-graph-client": "^3.0.7",
@ -16281,9 +16281,9 @@
}
},
"node_modules/@librechat/agents": {
"version": "3.0.36",
"resolved": "https://registry.npmjs.org/@librechat/agents/-/agents-3.0.36.tgz",
"integrity": "sha512-52+uNiG0X2B4TZX03ldFRvqtJrExnntEFQV5UfA38+2sNbYgPm4lcdKyAHr9OTPdmmtbmDY/gKKguRiUzLVL2g==",
"version": "3.0.50",
"resolved": "https://registry.npmjs.org/@librechat/agents/-/agents-3.0.50.tgz",
"integrity": "sha512-oovj3BsP/QoxPbWFAc71Ddplwd9BT8ucfYs+n+kiR37aCWtvxdvL9/XldRYfnaq9boNE324njQJyqc8v8AAPFQ==",
"license": "MIT",
"dependencies": {
"@langchain/anthropic": "^0.3.26",
@ -46276,7 +46276,7 @@
"@azure/storage-blob": "^12.27.0",
"@keyv/redis": "^4.3.3",
"@langchain/core": "^0.3.79",
"@librechat/agents": "^3.0.36",
"@librechat/agents": "^3.0.50",
"@librechat/data-schemas": "*",
"@modelcontextprotocol/sdk": "^1.21.0",
"axios": "^1.12.1",

View file

@ -67,10 +67,11 @@
"b:api-inspect": "NODE_ENV=production bun --inspect run api/server/index.js",
"b:api:dev": "NODE_ENV=production bun run --watch api/server/index.js",
"b:data": "cd packages/data-provider && bun run b:build",
"b:mcp": "cd packages/api && bun run b:build",
"b:build:client-package": "cd packages/client && bun run b:build",
"b:data-schemas": "cd packages/data-schemas && bun run b:build",
"b:build:api": "cd packages/api && bun run b:build",
"b:client": "bun --bun run b:data && bun --bun run b:mcp && bun --bun run b:data-schemas && cd client && bun --bun run b:build",
"b:build:client": "cd client && bun --bun run b:build",
"b:client": "bun --bun run b:data && bun --bun run b:data-schemas && bun --bun run b:build:api && bun --bun run b:build:client-package && bun --bun run b:build:client",
"b:client:dev": "cd client && bun run b:dev",
"b:test:client": "cd client && bun run b:test",
"b:test:api": "cd api && bun run b:test",

View file

@ -84,7 +84,7 @@
"@azure/storage-blob": "^12.27.0",
"@keyv/redis": "^4.3.3",
"@langchain/core": "^0.3.79",
"@librechat/agents": "^3.0.36",
"@librechat/agents": "^3.0.50",
"@librechat/data-schemas": "*",
"@modelcontextprotocol/sdk": "^1.21.0",
"axios": "^1.12.1",

View file

@ -17,7 +17,9 @@
],
"scripts": {
"clean": "rimraf dist",
"b:clean": "bun run rimraf dist",
"build": "npm run clean && rollup -c --bundleConfigAsCjs",
"b:build": "bun run b:clean && bun run rollup -c --silent --bundleConfigAsCjs",
"build:watch": "rollup -c -w --bundleConfigAsCjs",
"dev": "rollup -c -w --bundleConfigAsCjs"
},