mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-21 19:00:13 +01:00
Merge branch 'main' into feat/model-spec-group-icons
This commit is contained in:
commit
94819c7d0c
10 changed files with 12319 additions and 35 deletions
|
|
@ -317,14 +317,22 @@ const loadTools = async ({
|
||||||
requestedTools[tool] = async () => {
|
requestedTools[tool] = async () => {
|
||||||
toolContextMap[tool] = `# \`${tool}\`:
|
toolContextMap[tool] = `# \`${tool}\`:
|
||||||
Current Date & Time: ${replaceSpecialVars({ text: '{{iso_datetime}}' })}
|
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.
|
**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.
|
||||||
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.
|
**CITATION FORMAT - INVISIBLE UNICODE ANCHORS ONLY:**
|
||||||
5. **Tailor your approach to the query type** (academic, news, coding, etc.) while maintaining an expert, journalistic, unbiased tone.
|
Use these Unicode characters: \\ue202 (before each anchor), \\ue200 (group start), \\ue201 (group end), \\ue203 (highlight start), \\ue204 (highlight end)
|
||||||
6. **Provide comprehensive information** with specific details, examples, and as much relevant context as possible from search results.
|
|
||||||
7. **Avoid moralizing language.**
|
Anchor pattern: turn{N}{type}{index} where N=turn number, type=search|news|image|ref, index=0,1,2...
|
||||||
`.trim();
|
|
||||||
|
**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({
|
return createSearchTool({
|
||||||
...result.authResult,
|
...result.authResult,
|
||||||
onSearchResults,
|
onSearchResults,
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@
|
||||||
"@langchain/google-genai": "^0.2.13",
|
"@langchain/google-genai": "^0.2.13",
|
||||||
"@langchain/google-vertexai": "^0.2.13",
|
"@langchain/google-vertexai": "^0.2.13",
|
||||||
"@langchain/textsplitters": "^0.1.0",
|
"@langchain/textsplitters": "^0.1.0",
|
||||||
"@librechat/agents": "^3.0.36",
|
"@librechat/agents": "^3.0.50",
|
||||||
"@librechat/api": "*",
|
"@librechat/api": "*",
|
||||||
"@librechat/data-schemas": "*",
|
"@librechat/data-schemas": "*",
|
||||||
"@microsoft/microsoft-graph-client": "^3.0.7",
|
"@microsoft/microsoft-graph-client": "^3.0.7",
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@ const fs = require('fs').promises;
|
||||||
const FormData = require('form-data');
|
const FormData = require('form-data');
|
||||||
const { Readable } = require('stream');
|
const { Readable } = require('stream');
|
||||||
const { logger } = require('@librechat/data-schemas');
|
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 { extractEnvVariable, STTProviders } = require('librechat-data-provider');
|
||||||
const { getAppConfig } = require('~/server/services/Config');
|
const { getAppConfig } = require('~/server/services/Config');
|
||||||
|
|
||||||
|
|
@ -34,6 +35,34 @@ const MIME_TO_EXTENSION_MAP = {
|
||||||
'audio/x-flac': 'flac',
|
'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.
|
* Gets the file extension from the MIME type.
|
||||||
* @param {string} mimeType - The MIME type.
|
* @param {string} mimeType - The MIME type.
|
||||||
|
|
@ -172,10 +201,9 @@ class STTService {
|
||||||
model: sttSchema.model,
|
model: sttSchema.model,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (language) {
|
const validLanguage = getValidatedLanguageCode(language);
|
||||||
/** Converted locale code (e.g., "en-US") to ISO-639-1 format (e.g., "en") */
|
if (validLanguage) {
|
||||||
const isoLanguage = language.split('-')[0];
|
data.language = validLanguage;
|
||||||
data.language = isoLanguage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
|
|
@ -220,10 +248,9 @@ class STTService {
|
||||||
contentType: audioFile.mimetype,
|
contentType: audioFile.mimetype,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (language) {
|
const validLanguage = getValidatedLanguageCode(language);
|
||||||
/** Converted locale code (e.g., "en-US") to ISO-639-1 format (e.g., "en") */
|
if (validLanguage) {
|
||||||
const isoLanguage = language.split('-')[0];
|
formData.append('language', validLanguage);
|
||||||
formData.append('language', isoLanguage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
|
|
@ -266,8 +293,14 @@ class STTService {
|
||||||
language,
|
language,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const options = { headers };
|
||||||
|
|
||||||
|
if (process.env.PROXY) {
|
||||||
|
options.httpsAgent = new HttpsProxyAgent(process.env.PROXY);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.post(url, data, { headers });
|
const response = await axios.post(url, data, options);
|
||||||
|
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
throw new Error('Invalid response from the STT API');
|
throw new Error('Invalid response from the STT API');
|
||||||
|
|
@ -279,7 +312,7 @@ class STTService {
|
||||||
|
|
||||||
return response.data.text.trim();
|
return response.data.text.trim();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`STT request failed for provider ${provider}:`, error);
|
logAxiosError({ message: `STT request failed for provider ${provider}:`, error });
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -309,7 +342,7 @@ class STTService {
|
||||||
const text = await this.sttRequest(provider, sttSchema, { audioBuffer, audioFile, language });
|
const text = await this.sttRequest(provider, sttSchema, { audioBuffer, audioFile, language });
|
||||||
res.json({ text });
|
res.json({ text });
|
||||||
} catch (error) {
|
} 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);
|
res.sendStatus(500);
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const { logger } = require('@librechat/data-schemas');
|
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 { extractEnvVariable, TTSProviders } = require('librechat-data-provider');
|
||||||
const { getRandomVoiceId, createChunkProcessor, splitTextIntoChunks } = require('./streamAudio');
|
const { getRandomVoiceId, createChunkProcessor, splitTextIntoChunks } = require('./streamAudio');
|
||||||
const { getAppConfig } = require('~/server/services/Config');
|
const { getAppConfig } = require('~/server/services/Config');
|
||||||
|
|
@ -266,10 +267,14 @@ class TTSService {
|
||||||
|
|
||||||
const options = { headers, responseType: stream ? 'stream' : 'arraybuffer' };
|
const options = { headers, responseType: stream ? 'stream' : 'arraybuffer' };
|
||||||
|
|
||||||
|
if (process.env.PROXY) {
|
||||||
|
options.httpsAgent = new HttpsProxyAgent(process.env.PROXY);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await axios.post(url, data, options);
|
return await axios.post(url, data, options);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error(`TTS request failed for provider ${provider}:`, error);
|
logAxiosError({ message: `TTS request failed for provider ${provider}:`, error });
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -325,7 +330,10 @@ class TTSService {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch (innerError) {
|
} 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) {
|
if (!res.headersSent) {
|
||||||
return res.status(500).end();
|
return res.status(500).end();
|
||||||
}
|
}
|
||||||
|
|
@ -337,7 +345,7 @@ class TTSService {
|
||||||
res.end();
|
res.end();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Error creating the audio stream:', error);
|
logAxiosError({ message: '[TTS] Error creating the audio stream:', error });
|
||||||
if (!res.headersSent) {
|
if (!res.headersSent) {
|
||||||
return res.status(500).send('An error occurred');
|
return res.status(500).send('An error occurred');
|
||||||
}
|
}
|
||||||
|
|
@ -407,7 +415,10 @@ class TTSService {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch (innerError) {
|
} 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) {
|
if (!res.headersSent) {
|
||||||
return res.status(500).end();
|
return res.status(500).end();
|
||||||
}
|
}
|
||||||
|
|
@ -424,7 +435,7 @@ class TTSService {
|
||||||
res.end();
|
res.end();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Failed to fetch audio:', error);
|
logAxiosError({ message: '[TTS] Failed to fetch audio:', error });
|
||||||
if (!res.headersSent) {
|
if (!res.headersSent) {
|
||||||
res.status(500).end();
|
res.status(500).end();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
10
package-lock.json
generated
10
package-lock.json
generated
|
|
@ -61,7 +61,7 @@
|
||||||
"@langchain/google-genai": "^0.2.13",
|
"@langchain/google-genai": "^0.2.13",
|
||||||
"@langchain/google-vertexai": "^0.2.13",
|
"@langchain/google-vertexai": "^0.2.13",
|
||||||
"@langchain/textsplitters": "^0.1.0",
|
"@langchain/textsplitters": "^0.1.0",
|
||||||
"@librechat/agents": "^3.0.36",
|
"@librechat/agents": "^3.0.50",
|
||||||
"@librechat/api": "*",
|
"@librechat/api": "*",
|
||||||
"@librechat/data-schemas": "*",
|
"@librechat/data-schemas": "*",
|
||||||
"@microsoft/microsoft-graph-client": "^3.0.7",
|
"@microsoft/microsoft-graph-client": "^3.0.7",
|
||||||
|
|
@ -16281,9 +16281,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@librechat/agents": {
|
"node_modules/@librechat/agents": {
|
||||||
"version": "3.0.36",
|
"version": "3.0.50",
|
||||||
"resolved": "https://registry.npmjs.org/@librechat/agents/-/agents-3.0.36.tgz",
|
"resolved": "https://registry.npmjs.org/@librechat/agents/-/agents-3.0.50.tgz",
|
||||||
"integrity": "sha512-52+uNiG0X2B4TZX03ldFRvqtJrExnntEFQV5UfA38+2sNbYgPm4lcdKyAHr9OTPdmmtbmDY/gKKguRiUzLVL2g==",
|
"integrity": "sha512-oovj3BsP/QoxPbWFAc71Ddplwd9BT8ucfYs+n+kiR37aCWtvxdvL9/XldRYfnaq9boNE324njQJyqc8v8AAPFQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@langchain/anthropic": "^0.3.26",
|
"@langchain/anthropic": "^0.3.26",
|
||||||
|
|
@ -46276,7 +46276,7 @@
|
||||||
"@azure/storage-blob": "^12.27.0",
|
"@azure/storage-blob": "^12.27.0",
|
||||||
"@keyv/redis": "^4.3.3",
|
"@keyv/redis": "^4.3.3",
|
||||||
"@langchain/core": "^0.3.79",
|
"@langchain/core": "^0.3.79",
|
||||||
"@librechat/agents": "^3.0.36",
|
"@librechat/agents": "^3.0.50",
|
||||||
"@librechat/data-schemas": "*",
|
"@librechat/data-schemas": "*",
|
||||||
"@modelcontextprotocol/sdk": "^1.21.0",
|
"@modelcontextprotocol/sdk": "^1.21.0",
|
||||||
"axios": "^1.12.1",
|
"axios": "^1.12.1",
|
||||||
|
|
|
||||||
|
|
@ -67,10 +67,11 @@
|
||||||
"b:api-inspect": "NODE_ENV=production bun --inspect run api/server/index.js",
|
"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:api:dev": "NODE_ENV=production bun run --watch api/server/index.js",
|
||||||
"b:data": "cd packages/data-provider && bun run b:build",
|
"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:data-schemas": "cd packages/data-schemas && bun run b:build",
|
||||||
"b:build:api": "cd packages/api && 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:client:dev": "cd client && bun run b:dev",
|
||||||
"b:test:client": "cd client && bun run b:test",
|
"b:test:client": "cd client && bun run b:test",
|
||||||
"b:test:api": "cd api && bun run b:test",
|
"b:test:api": "cd api && bun run b:test",
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@
|
||||||
"@azure/storage-blob": "^12.27.0",
|
"@azure/storage-blob": "^12.27.0",
|
||||||
"@keyv/redis": "^4.3.3",
|
"@keyv/redis": "^4.3.3",
|
||||||
"@langchain/core": "^0.3.79",
|
"@langchain/core": "^0.3.79",
|
||||||
"@librechat/agents": "^3.0.36",
|
"@librechat/agents": "^3.0.50",
|
||||||
"@librechat/data-schemas": "*",
|
"@librechat/data-schemas": "*",
|
||||||
"@modelcontextprotocol/sdk": "^1.21.0",
|
"@modelcontextprotocol/sdk": "^1.21.0",
|
||||||
"axios": "^1.12.1",
|
"axios": "^1.12.1",
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,9 @@
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "rimraf dist",
|
"clean": "rimraf dist",
|
||||||
|
"b:clean": "bun run rimraf dist",
|
||||||
"build": "npm run clean && rollup -c --bundleConfigAsCjs",
|
"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",
|
"build:watch": "rollup -c -w --bundleConfigAsCjs",
|
||||||
"dev": "rollup -c -w --bundleConfigAsCjs"
|
"dev": "rollup -c -w --bundleConfigAsCjs"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue