🧩 fix: Normalize MCP UI Resource Rendering (#14868)

* fix: normalize MCP UI resource rendering

* fix: filter unsupported MCP UI resources

* fix: preserve MCP UI marker examples

* fix: handle MCP UI resource edge cases

* fix: harden MCP UI marker sanitization

* fix: scope MCP UI marker sanitization

* fix: parse MCP UI marker contexts

* fix: align MCP UI sanitizer parsing

* fix: match MCP UI renderer syntax

* fix: align blockquote marker spans

* fix: decode MCP UI text node sources

* fix: sanitize nested subagent markers

* fix: bound MCP UI sanitizer traversal

* fix: keep MCP UI marker mapping linear

* style: sort security patch imports

* fix: harden nested MCP UI sanitization

* fix: mirror citation cleanup for MCP UI markers

* fix: clean decoded citation markers

* fix: clean assembled citation markers

* fix: align MCP marker sanitization with rendering

* fix: match persisted MCP marker render paths

* fix: preserve highlighted citation boundaries

* fix: align MCP markers across content renderers

* fix: preserve citation renderer boundaries

* fix: match legacy thinking trim semantics
This commit is contained in:
Danny Avila 2026-08-15 12:49:59 -04:00 committed by GitHub
parent eb3b353712
commit 1d789c41a5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 1758 additions and 272 deletions

View file

@ -1,11 +1,78 @@
const { v4: uuidv4 } = require('uuid');
const { logger, getTenantId } = require('@librechat/data-schemas');
const { EModelEndpoint, Constants, openAISettings } = require('librechat-data-provider');
const mongoose = require('mongoose');
const {
logger,
getTenantId,
sanitizeUIResourceContent,
stripMessageUIResourceMarkers,
} = require('@librechat/data-schemas');
const { EModelEndpoint, Constants, Tools, openAISettings } = require('librechat-data-provider');
const { getEndpointsConfig } = require('~/server/services/Config');
const { createImportBatchBuilder } = require('./importBatchBuilder');
const { resolveImportDefaultModel } = require('./defaults');
const { cloneMessagesWithTimestamps } = require('./fork');
const castImportedBoolean = mongoose.Schema.Types.Boolean.cast();
const castImportedString = mongoose.Schema.Types.String.cast();
function isImportedAssistantMessage(isCreatedByUser) {
if (isCreatedByUser === null) {
return false;
}
if (isCreatedByUser === undefined) {
return true;
}
try {
return castImportedBoolean(isCreatedByUser) !== true;
} catch {
return true;
}
}
function isImportedAssistantContent(isCreatedByUser) {
try {
return castImportedBoolean(isCreatedByUser) !== true;
} catch {
return true;
}
}
function castPersistedImportedText(text) {
try {
return castImportedString(text);
} catch {
return text;
}
}
function normalizeImportedArray(value) {
if (value == null) {
return null;
}
return Array.isArray(value) ? value : [value];
}
/** Removes executable legacy MCP-UI payloads from untrusted conversation imports. */
function sanitizeImportedMessage(message) {
const sanitizeTextMarkers = isImportedAssistantMessage(message.isCreatedByUser);
const sanitizeContentMarkers = isImportedAssistantContent(message.isCreatedByUser);
const text = castPersistedImportedText(message.text);
const content = normalizeImportedArray(message.content);
const attachments = normalizeImportedArray(message.attachments);
return {
...message,
...(text !== message.text && { text }),
...(sanitizeTextMarkers &&
typeof text === 'string' && { text: stripMessageUIResourceMarkers(text, false) }),
...(content && {
content: sanitizeUIResourceContent(content, sanitizeContentMarkers),
}),
...(attachments && {
attachments: attachments.filter((attachment) => attachment?.type !== Tools.ui_resources),
}),
};
}
/**
* Returns the appropriate importer function based on the provided JSON data.
*
@ -283,10 +350,13 @@ async function importLibreChatConvo(
return flatMessages;
};
const flatMessages = flattenMessages(messagesToImport);
const flatMessages = flattenMessages(messagesToImport).map(sanitizeImportedMessage);
cloneMessagesWithTimestamps(flatMessages, importBatchBuilder);
} else if (messagesToImport) {
cloneMessagesWithTimestamps(messagesToImport, importBatchBuilder);
cloneMessagesWithTimestamps(
messagesToImport.map(sanitizeImportedMessage),
importBatchBuilder,
);
for (const message of messagesToImport) {
if (!firstMessageDate && message.createdAt) {
firstMessageDate = new Date(message.createdAt);

View file

@ -3,6 +3,8 @@ const path = require('path');
const {
EModelEndpoint,
Constants,
ContentTypes,
Tools,
RetentionMode,
openAISettings,
anthropicSettings,
@ -877,6 +879,158 @@ describe('importLibreChatConvo', () => {
expect(importBatchBuilder.saveBatch).toHaveBeenCalled();
});
it.each([
['linear', false, false],
['recursive', true, false],
['numeric-author', false, 0],
['omitted-author', false, undefined],
])('strips MCP-UI attachments from %s imports', async (_format, recursive, authorFlag) => {
const message = {
messageId: 'message-1',
parentMessageId: Constants.NO_PARENT,
text: { _id: '\\ui{malicious}' },
isCreatedByUser: authorFlag,
content: [
{ type: ContentTypes.TEXT, text: 'Before \\ui{malicious} after' },
{ type: ContentTypes.TEXT, text: '`\\ui{literal}`' },
{
type: ContentTypes.TEXT,
text: {
value: 'Object \\ui{malicious} value',
annotations: [{ type: 'citation' }],
},
},
{
type: ContentTypes.TOOL_CALL,
tool_call: {
subagent_content: [{ type: ContentTypes.TEXT, text: 'Nested \\ui{malicious} content' }],
},
},
],
attachments: [
{
type: Tools.ui_resources,
[Tools.ui_resources]: [
{
resourceId: 'malicious',
mimeType: 'application/vnd.mcp-ui.remote-dom+javascript',
text: "root.innerHTML='<img src=x onerror=alert(window.origin)>'",
},
],
},
{ type: Tools.web_search, [Tools.web_search]: { results: [] } },
],
};
const jsonData = {
conversationId: 'malicious-import',
title: 'Malicious import',
recursive,
...(recursive ? { messagesTree: [message] } : { messages: [message] }),
};
const importBatchBuilder = new ImportBatchBuilder('user-123');
const importer = getImporter(jsonData);
await importer(jsonData, 'user-123', () => importBatchBuilder);
expect(importBatchBuilder.messages[0].attachments).toEqual([
{ type: Tools.web_search, [Tools.web_search]: { results: [] } },
]);
expect(importBatchBuilder.messages[0].text).toBe('');
expect(importBatchBuilder.messages[0].content).toEqual([
{ type: ContentTypes.TEXT, text: 'Before after' },
{ type: ContentTypes.TEXT, text: '`\\ui{literal}`' },
{
type: ContentTypes.TEXT,
text: { value: 'Object value', annotations: [{ type: 'citation' }] },
},
{
type: ContentTypes.TOOL_CALL,
tool_call: {
subagent_content: [{ type: ContentTypes.TEXT, text: 'Nested content' }],
},
},
]);
});
it('sanitizes singleton content and attachment fields before Mongoose array casting', async () => {
const message = {
messageId: 'message-1',
parentMessageId: Constants.NO_PARENT,
text: '\\ui{malicious}',
isCreatedByUser: false,
error: true,
content: { type: ContentTypes.TEXT, text: 'Before \\ui{malicious} after' },
attachments: { type: Tools.ui_resources, [Tools.ui_resources]: [] },
};
const jsonData = {
conversationId: 'singleton-import',
title: 'Singleton fields',
recursive: false,
messages: [message],
};
const importBatchBuilder = new ImportBatchBuilder('user-123');
const importer = getImporter(jsonData);
await importer(jsonData, 'user-123', () => importBatchBuilder);
expect(importBatchBuilder.messages[0].content).toEqual([
{ type: ContentTypes.TEXT, text: 'Before after' },
]);
expect(importBatchBuilder.messages[0].attachments).toEqual([]);
expect(importBatchBuilder.messages[0].text).toBe('');
});
it.each([true, null])(
'matches text and content renderers for author flag %s while stripping attachments',
async (authorFlag) => {
const message = {
messageId: 'message-1',
parentMessageId: Constants.NO_PARENT,
text: 'Example: \\ui{literal}',
isCreatedByUser: authorFlag,
content: [
{ type: ContentTypes.TEXT, text: 'Part: \\ui{literal}' },
{
type: ContentTypes.TOOL_CALL,
tool_call: {
name: Constants.SUBAGENT,
output: 'Legacy \\ui{nested} output',
subagent_content: [{ type: ContentTypes.TEXT, text: 'Nested \\ui{nested} text' }],
},
},
],
attachments: [{ type: Tools.ui_resources, [Tools.ui_resources]: [] }],
};
const jsonData = {
conversationId: 'user-marker-import',
title: 'User marker import',
recursive: false,
messages: [message],
};
const importBatchBuilder = new ImportBatchBuilder('user-123');
const importer = getImporter(jsonData);
await importer(jsonData, 'user-123', () => importBatchBuilder);
expect(importBatchBuilder.messages[0].text).toBe('Example: \\ui{literal}');
expect(importBatchBuilder.messages[0].content).toEqual([
{
type: ContentTypes.TEXT,
text: authorFlag === true ? 'Part: \\ui{literal}' : 'Part: ',
},
{
type: ContentTypes.TOOL_CALL,
tool_call: {
name: Constants.SUBAGENT,
output: 'Legacy output',
subagent_content: [{ type: ContentTypes.TEXT, text: 'Nested text' }],
},
},
]);
expect(importBatchBuilder.messages[0].attachments).toEqual([]);
},
);
it('should import linear, non-recursive thread correctly with correct endpoint', async () => {
mockGetEndpointsConfig.mockResolvedValue({
[EModelEndpoint.azureOpenAI]: {},

322
bun.lock
View file

@ -5,12 +5,14 @@
"": {
"name": "LibreChat",
"devDependencies": {
"@antithesishq/bombadil": "0.6.1",
"@axe-core/playwright": "^4.10.1",
"@eslint/compat": "^1.2.6",
"@eslint/eslintrc": "^3.3.4",
"@eslint/js": "^9.20.0",
"@playwright/test": "^1.56.1",
"@types/react-virtualized": "^9.22.0",
"brace-expansion": "^2.1.2",
"caniuse-lite": "^1.0.30001741",
"cross-env": "^7.0.3",
"elliptic": "^6.6.1",
@ -51,11 +53,11 @@
"@azure/storage-blob": "^12.30.0",
"@google/genai": "^2.8.0",
"@keyv/redis": "^4.3.3",
"@librechat/agents": "^3.3.11",
"@librechat/agents": "^3.5.1",
"@librechat/api": "*",
"@librechat/data-schemas": "*",
"@microsoft/microsoft-graph-client": "^3.0.7",
"@modelcontextprotocol/sdk": "^1.29.0",
"@modelcontextprotocol/sdk": "^1.30.0",
"@node-saml/passport-saml": "^5.1.0",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/instrumentation-express": "^0.56.0",
@ -109,7 +111,7 @@
"mongodb": "^6.14.2",
"mongoose": "^8.24.1",
"multer": "^2.2.0",
"nanoid": "^3.3.7",
"nanoid": "^3.3.18",
"node-fetch": "^2.7.0",
"nodemailer": "^9.0.1",
"ollama": "^0.5.0",
@ -127,10 +129,11 @@
"pdfjs-dist": "^5.4.624",
"prom-client": "^15.1.3",
"rate-limit-redis": "^4.2.0",
"sanitize-html": "^2.13.0",
"re2js": "^2.8.6",
"sanitize-html": "^2.17.6",
"sharp": "^0.35.3",
"ua-parser-js": "^1.0.36",
"undici": "^7.24.1",
"undici": "^7.29.0",
"winston": "^3.11.0",
"winston-daily-rotate-file": "^5.0.0",
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
@ -139,7 +142,7 @@
},
"devDependencies": {
"@babel/preset-env": "^7.29.5",
"@types/sanitize-html": "^2.13.0",
"@types/sanitize-html": "^2.16.1",
"jest": "^30.2.0",
"mongodb-memory-server": "^11.0.1",
"nodemon": "^3.1.14",
@ -207,7 +210,7 @@
"mdast-util-from-markdown": "^2.0.1",
"mdast-util-gfm": "^3.0.0",
"mdast-util-math": "^3.0.0",
"mermaid": "^11.15.0",
"mermaid": "^11.16.1",
"micromark-extension-directive": "^3.0.1",
"micromark-extension-gfm": "^3.0.0",
"micromark-extension-llm-math": "^3.1.0",
@ -296,6 +299,8 @@
"dependencies": {
"@langchain/langgraph-checkpoint": "^1.1.2",
"@langchain/langgraph-checkpoint-mongodb": "^1.4.0",
"cluster-key-slot": "^1.1.2",
"proxy-from-env": "^2.1.0",
},
"devDependencies": {
"@babel/preset-env": "^7.29.5",
@ -311,7 +316,7 @@
"@types/node": "^24.12.4",
"@types/node-fetch": "^2.6.13",
"@types/react": "^18.2.18",
"@types/sanitize-html": "^2.13.0",
"@types/sanitize-html": "^2.16.1",
"@types/supertest": "^7.2.0",
"@types/yauzl": "^2.10.3",
"aws-sdk-client-mock": "^4.1.0",
@ -325,10 +330,9 @@
"lodash": "^4.17.23",
"mammoth": "^1.11.0",
"mongodb": "^6.14.2",
"nanoid": "^3.3.7",
"nanoid": "^3.3.18",
"pdfjs-dist": "^5.4.624",
"rimraf": "^6.1.3",
"sanitize-html": "^2.13.0",
"ts-node": "^10.9.2",
"tsdown": "^0.22.2",
"typescript": "^5.9.3",
@ -349,9 +353,9 @@
"@azure/storage-blob": "^12.30.0",
"@google/genai": "^2.8.0",
"@keyv/redis": "^4.3.3",
"@librechat/agents": "^3.3.11",
"@librechat/agents": "^3.5.1",
"@librechat/data-schemas": "*",
"@modelcontextprotocol/sdk": "^1.29.0",
"@modelcontextprotocol/sdk": "^1.30.0",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/instrumentation-express": "^0.56.0",
"@opentelemetry/instrumentation-http": "^0.207.0",
@ -394,9 +398,10 @@
"pdfjs-dist": "^5.4.624",
"prom-client": "^15.1.3",
"rate-limit-redis": "^4.2.0",
"sanitize-html": "^2.13.0",
"re2js": "^2.8.6",
"sanitize-html": "^2.17.6",
"sharp": "^0.35.3",
"undici": "^7.24.1",
"undici": "^7.29.0",
"yauzl": "^3.2.1",
"zod": "^3.22.4",
},
@ -490,7 +495,7 @@
"dependencies": {
"axios": "^1.16.0",
"dayjs": "^1.11.13",
"js-yaml": "^4.2.0",
"js-yaml": "^4.3.1",
"zod": "^3.22.4",
},
"devDependencies": {
@ -522,6 +527,16 @@
"packages/data-schemas": {
"name": "@librechat/data-schemas",
"version": "0.0.68",
"dependencies": {
"mdast-util-directive": "^3.0.0",
"mdast-util-from-markdown": "^2.0.1",
"mdast-util-gfm": "^3.0.0",
"mdast-util-math": "^3.0.0",
"micromark-extension-directive": "^3.0.1",
"micromark-extension-gfm": "^3.0.0",
"micromark-extension-llm-math": "^3.1.0",
"micromark-util-decode-string": "^2.0.0",
},
"devDependencies": {
"@types/express": "^5.0.0",
"@types/jest": "^29.5.2",
@ -541,7 +556,7 @@
"lodash": "^4.17.23",
"meilisearch": "^0.38.0",
"mongoose": "^8.24.1",
"nanoid": "^3.3.7",
"nanoid": "^3.3.18",
"winston": "^3.17.0",
"winston-daily-rotate-file": "^5.0.0",
},
@ -552,7 +567,6 @@
"@opentelemetry/core": "^2.9.0",
"@opentelemetry/propagator-jaeger": "^2.10.0",
"@xmldom/xmldom": "^0.8.13",
"brace-expansion": "^5.0.8",
"elliptic": "^6.6.1",
"fast-xml-parser": "5.7.2",
"form-data": "^4.0.6",
@ -582,6 +596,8 @@
"@anthropic-ai/vertex-sdk": ["@anthropic-ai/vertex-sdk@0.16.1", "", { "dependencies": { "@anthropic-ai/sdk": ">=0.50.3 <1", "google-auth-library": "^9.4.2" } }, "sha512-NQSJTmHFqJP32W4I+UyZ42ioUkd8avdye259Cs+P9yhi+XdI4wk7sDVnmVNNTiMtN08WXyELnAQPG2gcLQFXdQ=="],
"@antithesishq/bombadil": ["@antithesishq/bombadil@0.6.1", "", { "bin": { "bombadil": "bin/bombadil.js" } }, "sha512-d1iufG3MI7gSMSiSmMeNdcMW+qR0yQXL2zdkVynC3n3DYgFJYlYXKUQzygmqU12m4RWlR5iOdQU1hsx5UT6+IA=="],
"@apideck/better-ajv-errors": ["@apideck/better-ajv-errors@0.3.6", "", { "dependencies": { "json-schema": "^0.4.0", "jsonpointer": "^5.0.0", "leven": "^3.1.0" }, "peerDependencies": { "ajv": ">=8" } }, "sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA=="],
"@ariakit/components": ["@ariakit/components@0.1.2", "", { "dependencies": { "@ariakit/store": "0.1.2", "@ariakit/utils": "0.1.2" } }, "sha512-tvh2P0x1cJnoPXnmDEJwdRk3z7x6cTB8ArctcZdAUXlRg9tuwW/rJoBFJMzD5qMI9CDDlQ3Zctx58HvENw4BYw=="],
@ -1518,7 +1534,7 @@
"@lezer/lr": ["@lezer/lr@1.4.2", "", { "dependencies": { "@lezer/common": "^1.0.0" } }, "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA=="],
"@librechat/agents": ["@librechat/agents@3.3.11", "", { "dependencies": { "@anthropic-ai/sdk": "^0.115.0", "@aws-sdk/client-bedrock-runtime": "^3.1075.0", "@langchain/anthropic": "1.5.2", "@langchain/aws": "^1.4.2", "@langchain/core": "^1.2.3", "@langchain/deepseek": "^1.1.3", "@langchain/google-common": "2.2.0", "@langchain/google-gauth": "2.2.0", "@langchain/google-genai": "2.2.0", "@langchain/google-vertexai": "2.2.0", "@langchain/langgraph": "1.4.8", "@langchain/mistralai": "^1.2.0", "@langchain/openai": "1.5.5", "@langchain/textsplitters": "^1.0.1", "@langchain/xai": "^1.4.3", "@langfuse/core": "^5.4.1", "@langfuse/langchain": "^5.4.1", "@langfuse/otel": "^5.4.1", "@langfuse/tracing": "^5.4.1", "@opentelemetry/context-async-hooks": "^2.9.0", "@opentelemetry/sdk-node": "^0.220.0", "@types/diff": "^7.0.2", "ai-tokenizer": "^1.0.6", "axios": "^1.18.1", "cheerio": "^1.0.0", "diff": "^9.0.0", "dotenv": "^16.4.7", "https-proxy-agent": "^7.0.6", "mathjs": "^15.2.0", "nanoid": "^3.3.7", "okapibm25": "^1.4.1", "openai": "^6.46.0", "reo-census": "^1.2.9", "uuid": "^11.1.1" }, "peerDependencies": { "@anthropic-ai/sandbox-runtime": "^0.0.67" }, "optionalPeers": ["@anthropic-ai/sandbox-runtime"] }, "sha512-rCCUQbi6b2HcUfq11a/1FXR9JveCmV/30HH64TkVyVHoUkL7QlSd99rddaYRjnAcsGlWb1zY+0oHEO1jQ3m93A=="],
"@librechat/agents": ["@librechat/agents@3.5.1", "", { "dependencies": { "@anthropic-ai/sdk": "^0.115.0", "@aws-sdk/client-bedrock-runtime": "^3.1075.0", "@langchain/anthropic": "1.5.2", "@langchain/aws": "^1.4.2", "@langchain/core": "^1.2.3", "@langchain/deepseek": "^1.1.3", "@langchain/google-common": "2.2.0", "@langchain/google-gauth": "2.2.0", "@langchain/google-genai": "2.2.0", "@langchain/google-vertexai": "2.2.0", "@langchain/langgraph": "1.4.8", "@langchain/mistralai": "^1.2.0", "@langchain/openai": "1.5.5", "@langchain/textsplitters": "^1.0.1", "@langchain/xai": "^1.4.3", "@langfuse/core": "^5.4.1", "@langfuse/langchain": "^5.4.1", "@langfuse/otel": "^5.4.1", "@langfuse/tracing": "^5.4.1", "@opentelemetry/context-async-hooks": "^2.9.0", "@opentelemetry/sdk-node": "^0.220.0", "@types/diff": "^7.0.2", "ai-tokenizer": "^1.0.6", "axios": "^1.18.1", "cheerio": "^1.0.0", "diff": "^9.0.0", "dotenv": "^16.4.7", "https-proxy-agent": "^7.0.6", "mathjs": "^15.2.0", "nanoid": "^3.3.18", "okapibm25": "^1.4.1", "openai": "^6.46.0", "reova": "^0.4.1", "socks-proxy-agent": "^8.0.5", "uuid": "^11.1.1" }, "peerDependencies": { "@anthropic-ai/sandbox-runtime": "^0.0.67" }, "optionalPeers": ["@anthropic-ai/sandbox-runtime"] }, "sha512-8y4gfZg8OD5BuykF8xixh71yafgmmk7dUFX8KN9O40/WkqfJTtA/FG7E48Ke+ben3xOoXE6aIc7fwmotrYrhKw=="],
"@librechat/api": ["@librechat/api@workspace:packages/api"],
@ -1546,7 +1562,7 @@
"@monaco-editor/react": ["@monaco-editor/react@4.7.0", "", { "dependencies": { "@monaco-editor/loader": "^1.5.0" }, "peerDependencies": { "monaco-editor": ">= 0.25.0 < 1", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA=="],
"@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.3.1", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-6nZrq5kfAz0POWyhljnbWQQJQ5uT8oE2ddX303q1uY0tWsivWKgBDXBBvuFPwOqRRalXJuVO9EjOdVtuhLX0zg=="],
"@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.4.13", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-E3Sv4eCYAlKYUTx8S3ioQcDUscOif+8zZ5OnW1IzJ+Tt+EO+ke8mn+Y3FX6N1H79picwbdOavVOb1jPi2EOyrg=="],
"@napi-rs/canvas": ["@napi-rs/canvas@0.1.96", "", { "optionalDependencies": { "@napi-rs/canvas-android-arm64": "0.1.96", "@napi-rs/canvas-darwin-arm64": "0.1.96", "@napi-rs/canvas-darwin-x64": "0.1.96", "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.96", "@napi-rs/canvas-linux-arm64-gnu": "0.1.96", "@napi-rs/canvas-linux-arm64-musl": "0.1.96", "@napi-rs/canvas-linux-riscv64-gnu": "0.1.96", "@napi-rs/canvas-linux-x64-gnu": "0.1.96", "@napi-rs/canvas-linux-x64-musl": "0.1.96", "@napi-rs/canvas-win32-arm64-msvc": "0.1.96", "@napi-rs/canvas-win32-x64-msvc": "0.1.96" } }, "sha512-6NNmNxvoJKeucVjxaaRUt3La2i5jShgiAbaY3G/72s1Vp3U06XPrAIxkAjBxpDcamEn/t+WJ4OOlGmvILo4/Ew=="],
@ -1970,7 +1986,7 @@
"@sinonjs/samsam": ["@sinonjs/samsam@8.0.3", "", { "dependencies": { "@sinonjs/commons": "^3.0.1", "type-detect": "^4.1.0" } }, "sha512-hw6HbX+GyVZzmaYNh82Ecj1vdGZrqVIn/keDTg63IgAwiQPO+xCz99uG6Woqgb4tM0mUiFENKZ4cqd7IX94AXQ=="],
"@smithy/abort-controller": ["@smithy/abort-controller@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-xolrFw6b+2iYGl6EcOL7IJY71vvyZ0DJ3mcKtpykqPe2uscwtzDZJa1uVQXyP7w9Dd+kGwYnPbMsJrGISKiY/Q=="],
"@smithy/abort-controller": ["@smithy/abort-controller@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-Hj4WoYWMJnSpM6/kchsm4bUNTL9XiSyhvoMb2KIq4VJzyDt7JpGHUZHkVNPZVC7YE1tf8tPeVauxpFBKGW4/KQ=="],
"@smithy/chunked-blob-reader": ["@smithy/chunked-blob-reader@5.2.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-St+kVicSyayWQca+I1rGitaOEH6uKgE8IUWoYnnEX26SWdWQcL6LvMSD19Lg+vYHKdT9B2Zuu7rd3i6Wnyb/iw=="],
@ -1982,7 +1998,7 @@
"@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.4.16", "", { "dependencies": { "@smithy/core": "^3.31.1", "@smithy/types": "^4.16.1", "tslib": "^2.6.2" } }, "sha512-QfuLWAkLzptffFW980AFeHZFdqds2B64rpEd3uJ6lgs3xVn9QegGMUgUcj+4d7dRrAsya3r58ZKpku97WcFb4w=="],
"@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.12", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.13.1", "@smithy/util-hex-encoding": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-FE3bZdEl62ojmy8x4FHqxq2+BuOHlcxiH5vaZ6aqHJr3AIZzwF5jfx8dEiU/X0a8RboyNDjmXjlbr8AdEyLgiA=="],
"@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.11", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.13.0", "@smithy/util-hex-encoding": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-Sf39Ml0iVX+ba/bgMPxaXWAAFmHqYLTmbjAPfLPLY8CrYkRDEqZdUsKC1OwVMCdJXfAt0v4j49GIJ8DoSYAe6w=="],
"@smithy/eventstream-serde-browser": ["@smithy/eventstream-serde-browser@4.2.11", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.11", "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-3rEpo3G6f/nRS7fQDsZmxw/ius6rnlIpz4UX6FlALEzz8JoSxFmdBt0SZnthis+km7sQo6q5/3e+UJcuQivoXA=="],
@ -2024,7 +2040,7 @@
"@smithy/protocol-http": ["@smithy/protocol-http@5.3.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-hI+barOVDJBkNt4y0L2mu3Ugc0w7+BpJ2CZuLwXtSltGAAwCb3IvnalGlbDV/UCS6a9ZuT3+exd1WxNdLb5IlQ=="],
"@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "@smithy/util-uri-escape": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-6wTZjGABQufekycfDGMEB84BgtdOE/rCVTov+EDXQ8NHKTUNIp/j27IliwP7tjIU9LR+sSzyGBOXjeEtVgzCHg=="],
"@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "@smithy/util-uri-escape": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-7spdikrYiljpket6u0up2Ck2mxhy7dZ0+TDd+S53Dg2DHd6wg+YNJrTCHiLdgZmEXZKI7LJZcwL3721ZRDFiqA=="],
"@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-nE3IRNjDltvGcoThD2abTozI1dkSy8aX+a2N1Rs55en5UsdyyIXgGEmevUL3okZFoJC77JgRGe99xYohhsjivQ=="],
@ -2588,7 +2604,7 @@
"bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="],
"balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"bare-events": ["bare-events@2.6.0", "", {}, "sha512-EKZ5BTXYExaNqi3I3f9RtEsaI/xBSGjE0XZCZilPzFAV/goswFHuPd9jEZlPIZ/iNZJwDSao9qRiScySz7MbQg=="],
@ -2626,7 +2642,7 @@
"bowser": ["bowser@2.11.0", "", {}, "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA=="],
"brace-expansion": ["brace-expansion@5.0.9", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg=="],
"brace-expansion": ["brace-expansion@2.1.4", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg=="],
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
@ -2654,8 +2670,6 @@
"buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="],
"buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="],
"buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
"buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
@ -2768,6 +2782,8 @@
"compression": ["compression@1.8.1", "", { "dependencies": { "bytes": "3.1.2", "compressible": "~2.0.18", "debug": "2.6.9", "negotiator": "~0.6.4", "on-headers": "~1.1.0", "safe-buffer": "5.2.1", "vary": "~1.1.2" } }, "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w=="],
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
"concat-stream": ["concat-stream@2.0.0", "", { "dependencies": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.0.2", "typedarray": "^0.0.6" } }, "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A=="],
"confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
@ -2934,7 +2950,7 @@
"date-fns": ["date-fns@3.3.1", "", {}, "sha512-y8e109LYGgoQDveiEBD3DYXKba1jWf5BA8YU1FL5Tvm0BTdEfy54WLCwnuYWZNnzzvALy/QQ4Hov+Q9RVRv+Zw=="],
"dayjs": ["dayjs@1.11.19", "", {}, "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw=="],
"dayjs": ["dayjs@1.11.21", "", {}, "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA=="],
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
@ -3792,7 +3808,7 @@
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
"lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="],
"lodash": ["lodash@4.18.1", "", {}, "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q=="],
"lodash-es": ["lodash-es@4.17.23", "", {}, "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg=="],
@ -3916,7 +3932,7 @@
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
"mermaid": ["mermaid@11.16.0", "", { "dependencies": { "@braintree/sanitize-url": "^7.1.2", "@iconify/utils": "^3.0.2", "@mermaid-js/parser": "^1.2.0", "@types/d3": "^7.4.3", "@upsetjs/venn.js": "^2.0.0", "cytoscape": "^3.33.3", "cytoscape-cose-bilkent": "^4.1.0", "cytoscape-fcose": "^2.2.0", "d3": "^7.9.0", "d3-sankey": "^0.12.3", "dagre-d3-es": "7.0.14", "dayjs": "^1.11.20", "dompurify": "^3.3.3", "es-toolkit": "^1.45.1", "katex": "^0.16.45", "khroma": "^2.1.0", "marked": "^16.3.0", "roughjs": "^4.6.6", "stylis": "^4.3.6", "ts-dedent": "^2.2.0", "uuid": "^11.1.0 || ^12 || ^13 || ^14.0.0" } }, "sha512-Zvm3kbstgdpvIJPPItlL7fppIZ3kibvc1oZIGxdvk9t6UFz6flv+Jw7FtRGKwfcI8OckmH04LqG6LlS6X4B1pA=="],
"mermaid": ["mermaid@11.16.1", "", { "dependencies": { "@braintree/sanitize-url": "^7.1.2", "@iconify/utils": "^3.0.2", "@mermaid-js/parser": "^1.2.0", "@types/d3": "^7.4.3", "@upsetjs/venn.js": "^2.0.0", "cytoscape": "^3.33.3", "cytoscape-cose-bilkent": "^4.1.0", "cytoscape-fcose": "^2.2.0", "d3": "^7.9.0", "d3-sankey": "^0.12.3", "dagre-d3-es": "7.0.14", "dayjs": "^1.11.20", "dompurify": "^3.3.3", "es-toolkit": "^1.45.1", "katex": "^0.16.45", "khroma": "^2.1.0", "marked": "^16.3.0", "roughjs": "^4.6.6", "stylis": "^4.3.6", "ts-dedent": "^2.2.0", "uuid": "^11.1.0 || ^12 || ^13 || ^14.0.0" } }, "sha512-TQsq6u22fAn3rek5VOubrhKPo1g5hwC3FXUN9hiyupTckcYiGuuKGkNQrKYwGJkXUxZdojwRG46gsSCFZMDp4g=="],
"methods": ["methods@1.1.2", "", {}, "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="],
@ -4022,7 +4038,7 @@
"monaco-editor": ["monaco-editor@0.56.0", "", { "dependencies": { "dompurify": "3.4.8", "marked": "14.0.0" } }, "sha512-sXboRm3BeBeLm938eaiyLMe0OxzfXIlZvbv4ir/jVgQy1zDhWjgmny0WoN45fuDKhCCQsYMbBJrv/A6jd8aCUg=="],
"mongodb": ["mongodb@6.14.2", "", { "dependencies": { "@mongodb-js/saslprep": "^1.1.9", "bson": "^6.10.3", "mongodb-connection-string-url": "^3.0.0" }, "peerDependencies": { "@aws-sdk/credential-providers": "^3.188.0", "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", "gcp-metadata": "^5.2.0", "kerberos": "^2.0.1", "mongodb-client-encryption": ">=6.0.0 <7", "snappy": "^7.2.2", "socks": "^2.7.1" }, "optionalPeers": ["@mongodb-js/zstd", "kerberos", "mongodb-client-encryption", "snappy", "socks"] }, "sha512-kMEHNo0F3P6QKDq17zcDuPeaywK/YaJVCEQRzPF3TOM/Bl9MFg64YE5Tu7ifj37qZJMhwU1tl2Ioivws5gRG5Q=="],
"mongodb": ["mongodb@6.21.0", "", { "dependencies": { "@mongodb-js/saslprep": "^1.3.0", "bson": "^6.10.4", "mongodb-connection-string-url": "^3.0.2" }, "peerDependencies": { "@aws-sdk/credential-providers": "^3.188.0", "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", "gcp-metadata": "^5.2.0", "kerberos": "^2.0.1", "mongodb-client-encryption": ">=6.0.0 <7", "snappy": "^7.3.2", "socks": "^2.7.1" }, "optionalPeers": ["@aws-sdk/credential-providers", "@mongodb-js/zstd", "gcp-metadata", "kerberos", "mongodb-client-encryption", "snappy", "socks"] }, "sha512-URyb/VXMjJ4da46OeSXg+puO39XH9DeQpWCslifrRn9JWugy0D+DvvBvkm2WxmHe61O/H19JM66p1z7RHVkZ6A=="],
"mongodb-connection-string-url": ["mongodb-connection-string-url@3.0.2", "", { "dependencies": { "@types/whatwg-url": "^11.0.2", "whatwg-url": "^14.1.0 || ^13.0.0" } }, "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA=="],
@ -4050,7 +4066,7 @@
"mz": ["mz@2.7.0", "", { "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", "thenify-all": "^1.0.0" } }, "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q=="],
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
"nanoid": ["nanoid@3.3.18", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w=="],
"napi-postinstall": ["napi-postinstall@0.3.4", "", { "bin": "lib/cli.js" }, "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ=="],
@ -4396,6 +4412,8 @@
"rc-util": ["rc-util@5.38.1", "", { "dependencies": { "@babel/runtime": "^7.18.3", "react-is": "^18.2.0" }, "peerDependencies": { "react": ">=16.9.0", "react-dom": ">=16.9.0" } }, "sha512-e4ZMs7q9XqwTuhIK7zBIVFltUtMSjphuPPQXHoHlzRzNdOwUxDejo0Zls5HYaJfRKNURcsS/ceKVULlhjBrxng=="],
"re2js": ["re2js@2.8.6", "", {}, "sha512-xLgQil4kIUCrAzVk9fRSkxkFNwmygLFjVxXrLc65aE1F0+Zsb8rxumFBy4XKyvgMCTL6kilDq3EZ0piE2dP/Dg=="],
"react": ["react@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0" } }, "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ=="],
"react-avatar-editor": ["react-avatar-editor@13.0.2", "", { "dependencies": { "@babel/plugin-transform-runtime": "^7.12.1", "@babel/runtime": "^7.12.5", "prop-types": "^15.7.2" }, "peerDependencies": { "react": "^0.14.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom": "^0.14.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" } }, "sha512-a4ajbi7lwDh98kgEtSEeKMu0vs0CHTczkq4Xcxr1EiwMFH1GlgHCEtwGU8q/H5W8SeLnH4KPK8LUjEEaZXklxQ=="],
@ -4502,7 +4520,7 @@
"remove-accents": ["remove-accents@0.5.0", "", {}, "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A=="],
"reo-census": ["reo-census@1.2.9", "", {}, "sha512-QPnAyRk6gUK9h2XJy9yTXiA91+LEHahmzbRdfb6DigAoe1S/nKg2LXc+/m3//HGyMPAkCFVz/FJJ8YrKm5IrXw=="],
"reova": ["reova@0.4.1", "", {}, "sha512-9TNaquUZIeT+2SYAy5on/ZTCTF+cWFJNeZ1ugV1K2HdepeswSzGRl+pBghuXqr0ur4tWfaxkvW5etPX0e7mQNg=="],
"require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
@ -4630,13 +4648,19 @@
"slice-ansi": ["slice-ansi@5.0.0", "", { "dependencies": { "ansi-styles": "^6.0.0", "is-fullwidth-code-point": "^4.0.0" } }, "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ=="],
"smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="],
"smob": ["smob@1.4.1", "", {}, "sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ=="],
"socks": ["socks@2.8.9", "", { "dependencies": { "ip-address": "^10.1.1", "smart-buffer": "^4.2.0" } }, "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw=="],
"socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="],
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
"source-map-support": ["source-map-support@0.5.13", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w=="],
"source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="],
"space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="],
@ -4884,7 +4908,7 @@
"underscore": ["underscore@1.13.8", "", {}, "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ=="],
"undici": ["undici@7.24.4", "", {}, "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w=="],
"undici": ["undici@7.29.0", "", {}, "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw=="],
"undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
@ -5096,7 +5120,7 @@
"yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
"yauzl": ["yauzl@3.2.1", "", { "dependencies": { "buffer-crc32": "~0.2.3", "pend": "~1.2.0" } }, "sha512-k1isifdbpNSFEHFJ1ZY4YDewv0IH9FR61lDetaRMD3j2ae3bIXGV+7c+LHCqtQGofSd8PIyV4X6+dHMAnSr60A=="],
"yauzl": ["yauzl@3.4.0", "", { "dependencies": { "pend": "~1.2.0" } }, "sha512-jIH9yLR9wqr0wOS0TpBvo/g/2UgZH5qePVbjgRliiF0BYvOZyaBknKsF+x9Iht0O6sqgnB93rCICdOZFecJuDw=="],
"yn": ["yn@3.1.1", "", {}, "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q=="],
@ -5486,8 +5510,6 @@
"@hyperdx/otel-web/@opentelemetry/instrumentation": ["@opentelemetry/instrumentation@0.218.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.218.0", "import-in-the-middle": "^3.0.0", "require-in-the-middle": "^8.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-mIZil8Es+sYDK5m+DQiwAwF57F14TF2YlEqvIjZ/RQWcxDBwRGsKfdK2Tv65OU9meQKCMzSIFS9mxAcnAb6Bkg=="],
"@hyperdx/otel-web/lodash": ["lodash@4.18.1", "", {}, "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q=="],
"@img/sharp-wasm32/@emnapi/runtime": ["@emnapi/runtime@1.11.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA=="],
"@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
@ -5550,8 +5572,6 @@
"@langchain/google-gauth/google-auth-library": ["google-auth-library@10.9.1", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^7.1.4", "gcp-metadata": "8.1.2", "google-logging-utils": "1.1.3", "jws": "^4.0.0" } }, "sha512-i1ydyHrqcIxXkWh/uBmVkzCvIuq5yiK2ATndIe5XxKholrG/MTYP9xGYka4sQhrbIAgGjL2B6NOE7rFaiF3fXw=="],
"@langchain/langgraph-checkpoint-mongodb/mongodb": ["mongodb@6.21.0", "", { "dependencies": { "@mongodb-js/saslprep": "^1.3.0", "bson": "^6.10.4", "mongodb-connection-string-url": "^3.0.2" }, "peerDependencies": { "@aws-sdk/credential-providers": "^3.188.0", "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", "gcp-metadata": "^5.2.0", "kerberos": "^2.0.1", "mongodb-client-encryption": ">=6.0.0 <7", "snappy": "^7.3.2", "socks": "^2.7.1" }, "optionalPeers": ["@aws-sdk/credential-providers", "@mongodb-js/zstd", "gcp-metadata", "kerberos", "mongodb-client-encryption", "snappy", "socks"] }, "sha512-URyb/VXMjJ4da46OeSXg+puO39XH9DeQpWCslifrRn9JWugy0D+DvvBvkm2WxmHe61O/H19JM66p1z7RHVkZ6A=="],
"@langchain/langgraph-sdk/p-retry": ["p-retry@7.1.1", "", { "dependencies": { "is-network-error": "^1.1.0" } }, "sha512-J5ApzjyRkkf601HpEeykoiCvzHQjWxPAHhyjFcEUP2SWq0+35NKh8TLhpLw+Dkq5TZBFvUM6UigdE9hIVYTl5w=="],
"@langchain/openai/openai": ["openai@6.49.0", "", { "peerDependencies": { "@aws-sdk/credential-provider-node": ">=3.972.0 <4", "@smithy/hash-node": ">=4.3.0 <5", "@smithy/signature-v4": ">=5.4.0 <6", "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["@aws-sdk/credential-provider-node", "@smithy/hash-node", "@smithy/signature-v4", "ws", "zod"] }, "sha512-aYCc0C6L864eR6WSYIwQGyXriw/nIyZx0ObvhzOEVuk0zoBDpynjSbrionWI7q65B5H8jJX0DXR9snEzM6bfPg=="],
@ -5564,18 +5584,10 @@
"@librechat/agents/diff": ["diff@9.0.0", "", {}, "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw=="],
"@librechat/agents/nanoid": ["nanoid@3.3.16", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q=="],
"@librechat/agents/openai": ["openai@6.49.0", "", { "peerDependencies": { "@aws-sdk/credential-provider-node": ">=3.972.0 <4", "@smithy/hash-node": ">=4.3.0 <5", "@smithy/signature-v4": ">=5.4.0 <6", "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["@aws-sdk/credential-provider-node", "@smithy/hash-node", "@smithy/signature-v4", "ws", "zod"] }, "sha512-aYCc0C6L864eR6WSYIwQGyXriw/nIyZx0ObvhzOEVuk0zoBDpynjSbrionWI7q65B5H8jJX0DXR9snEzM6bfPg=="],
"@librechat/agents/uuid": ["uuid@11.1.1", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime": ["@aws-sdk/client-bedrock-runtime@3.1013.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.22", "@aws-sdk/credential-provider-node": "^3.972.23", "@aws-sdk/eventstream-handler-node": "^3.972.11", "@aws-sdk/middleware-eventstream": "^3.972.8", "@aws-sdk/middleware-host-header": "^3.972.8", "@aws-sdk/middleware-logger": "^3.972.8", "@aws-sdk/middleware-recursion-detection": "^3.972.8", "@aws-sdk/middleware-user-agent": "^3.972.23", "@aws-sdk/middleware-websocket": "^3.972.13", "@aws-sdk/region-config-resolver": "^3.972.8", "@aws-sdk/token-providers": "3.1013.0", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@aws-sdk/util-user-agent-browser": "^3.972.8", "@aws-sdk/util-user-agent-node": "^3.973.9", "@smithy/config-resolver": "^4.4.11", "@smithy/core": "^3.23.12", "@smithy/eventstream-serde-browser": "^4.2.12", "@smithy/eventstream-serde-config-resolver": "^4.3.12", "@smithy/eventstream-serde-node": "^4.2.12", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.26", "@smithy/middleware-retry": "^4.4.43", "@smithy/middleware-serde": "^4.2.15", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.0", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.42", "@smithy/util-defaults-mode-node": "^4.2.45", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-LU80q1avpBwQ0eVAGbQpPApdVY4vcdBEIycY5iaznI10mdabeG83nrFySJrZ8knX7G6hl5d5KIOSjcpnolMKSA=="],
"@librechat/backend/@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
"@librechat/backend/@smithy/node-http-handler": ["@smithy/node-http-handler@4.5.0", "", { "dependencies": { "@smithy/abort-controller": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Rnq9vQWiR1+/I6NZZMNzJHV6pZYyEHt2ZnuV3MG8z2NNenC4i/8Kzttz7CjZiHSmsN5frhXhg17z3Zqjjhmz1A=="],
"@librechat/client/caniuse-lite": ["caniuse-lite@1.0.30001777", "", {}, "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ=="],
"@librechat/frontend/@react-spring/web": ["@react-spring/web@9.7.5", "", { "dependencies": { "@react-spring/animated": "~9.7.5", "@react-spring/core": "~9.7.5", "@react-spring/shared": "~9.7.5", "@react-spring/types": "~9.7.5" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "sha512-lmvqGwpe+CSttsWNZVr+Dg62adtKhauGwLyGE/RRyZ8AAMLgb9x3NDMA5RMElXo+IMyTkPp7nxTB8ZQlmhb6JQ=="],
@ -5854,11 +5866,11 @@
"@sinonjs/samsam/type-detect": ["type-detect@4.1.0", "", {}, "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw=="],
"@smithy/abort-controller/@smithy/types": ["@smithy/types@4.13.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g=="],
"@smithy/abort-controller/@smithy/types": ["@smithy/types@4.13.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw=="],
"@smithy/config-resolver/@smithy/types": ["@smithy/types@4.13.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw=="],
"@smithy/eventstream-codec/@smithy/types": ["@smithy/types@4.13.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g=="],
"@smithy/eventstream-codec/@smithy/types": ["@smithy/types@4.13.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw=="],
"@smithy/eventstream-serde-browser/@smithy/types": ["@smithy/types@4.13.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw=="],
@ -5866,8 +5878,6 @@
"@smithy/eventstream-serde-node/@smithy/types": ["@smithy/types@4.13.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw=="],
"@smithy/eventstream-serde-universal/@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.11", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.13.0", "@smithy/util-hex-encoding": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-Sf39Ml0iVX+ba/bgMPxaXWAAFmHqYLTmbjAPfLPLY8CrYkRDEqZdUsKC1OwVMCdJXfAt0v4j49GIJ8DoSYAe6w=="],
"@smithy/eventstream-serde-universal/@smithy/types": ["@smithy/types@4.13.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw=="],
"@smithy/hash-blob-browser/@smithy/types": ["@smithy/types@4.13.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw=="],
@ -5898,7 +5908,7 @@
"@smithy/protocol-http/@smithy/types": ["@smithy/types@4.13.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw=="],
"@smithy/querystring-builder/@smithy/types": ["@smithy/types@4.13.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g=="],
"@smithy/querystring-builder/@smithy/types": ["@smithy/types@4.13.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw=="],
"@smithy/querystring-parser/@smithy/types": ["@smithy/types@4.13.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw=="],
@ -5930,8 +5940,6 @@
"@smithy/util-stream/@smithy/types": ["@smithy/types@4.13.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw=="],
"@smithy/util-waiter/@smithy/abort-controller": ["@smithy/abort-controller@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-Hj4WoYWMJnSpM6/kchsm4bUNTL9XiSyhvoMb2KIq4VJzyDt7JpGHUZHkVNPZVC7YE1tf8tPeVauxpFBKGW4/KQ=="],
"@smithy/util-waiter/@smithy/types": ["@smithy/types@4.13.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-COuLsZILbbQsdrwKQpkkpyep7lCsByxwj7m0Mg5v66/ZTyenlfBc40/QFQ5chO0YN/PNEH1Bi3fGtfXPnYNeDw=="],
"@tanstack/match-sorter-utils/remove-accents": ["remove-accents@0.4.2", "", {}, "sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA=="],
@ -6268,6 +6276,8 @@
"jest-runner/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
"jest-runner/source-map-support": ["source-map-support@0.5.13", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w=="],
"jest-runtime/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
"jest-runtime/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": "dist/esm/bin.mjs" }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="],
@ -6326,8 +6336,6 @@
"langsmith/p-queue": ["p-queue@6.6.2", "", { "dependencies": { "eventemitter3": "^4.0.4", "p-timeout": "^3.2.0" } }, "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ=="],
"launder/dayjs": ["dayjs@1.11.21", "", {}, "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA=="],
"ldapauth-fork/lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="],
"lint-staged/chalk": ["chalk@5.4.1", "", {}, "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w=="],
@ -6350,14 +6358,14 @@
"memorystore/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
"mermaid/dayjs": ["dayjs@1.11.21", "", {}, "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA=="],
"micromark/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"miller-rabin/bn.js": ["bn.js@4.12.2", "", {}, "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw=="],
"minimatch/brace-expansion": ["brace-expansion@1.1.18", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw=="],
"mlly/acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
"monaco-editor/dompurify": ["dompurify@3.4.8", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-yb1cEmaOum7wFvOCSQxyfgVlv5D47Rc30iZWoMpbDIWTnJ6grDDQyu2KFJzB2k7u0pMuJcQ1zphH//fFnw2tjQ=="],
@ -6370,8 +6378,6 @@
"mongodb-memory-server-core/semver": ["semver@7.7.3", "", { "bin": "bin/semver.js" }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="],
"mongodb-memory-server-core/yauzl": ["yauzl@3.4.0", "", { "dependencies": { "pend": "~1.2.0" } }, "sha512-jIH9yLR9wqr0wOS0TpBvo/g/2UgZH5qePVbjgRliiF0BYvOZyaBknKsF+x9Iht0O6sqgnB93rCICdOZFecJuDw=="],
"mongoose/mongodb": ["mongodb@6.20.0", "", { "dependencies": { "@mongodb-js/saslprep": "^1.3.0", "bson": "^6.10.4", "mongodb-connection-string-url": "^3.0.2" }, "peerDependencies": { "@aws-sdk/credential-providers": "^3.188.0", "@mongodb-js/zstd": "^1.1.0 || ^2.0.0", "gcp-metadata": "^5.2.0", "kerberos": "^2.0.1", "mongodb-client-encryption": ">=6.0.0 <7", "snappy": "^7.3.2", "socks": "^2.7.1" }, "optionalPeers": ["@aws-sdk/credential-providers", "@mongodb-js/zstd", "gcp-metadata", "kerberos", "mongodb-client-encryption", "snappy", "socks"] }, "sha512-Tl6MEIU3K4Rq3TSHd+sZQqRBoGlFsOgNrH5ltAcFBV62Re3Fd+FcaVf8uSEQFOJ51SDowDVttBTONMfoYWrWlQ=="],
"mquery/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
@ -6552,8 +6558,6 @@
"terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="],
"terser/source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="],
"test-exclude/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="],
"to-buffer/isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="],
@ -6670,12 +6674,6 @@
"@aws-sdk/client-s3/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.11", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.11", "@smithy/property-provider": "^4.2.11", "@smithy/types": "^4.13.0", "@smithy/url-parser": "^4.2.11", "tslib": "^2.6.2" } }, "sha512-lBXrS6ku0kTj3xLmsJW0WwqWbGQ6ueooYyp/1L9lkyT0M02C+DWwYwc5aTyXFbRaK38ojALxNixg+LxKSHZc0g=="],
"@aws-sdk/client-s3/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "@smithy/util-uri-escape": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-7spdikrYiljpket6u0up2Ck2mxhy7dZ0+TDd+S53Dg2DHd6wg+YNJrTCHiLdgZmEXZKI7LJZcwL3721ZRDFiqA=="],
"@aws-sdk/client-s3/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-Hj4WoYWMJnSpM6/kchsm4bUNTL9XiSyhvoMb2KIq4VJzyDt7JpGHUZHkVNPZVC7YE1tf8tPeVauxpFBKGW4/KQ=="],
"@aws-sdk/client-s3/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "@smithy/util-uri-escape": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-7spdikrYiljpket6u0up2Ck2mxhy7dZ0+TDd+S53Dg2DHd6wg+YNJrTCHiLdgZmEXZKI7LJZcwL3721ZRDFiqA=="],
"@aws-sdk/middleware-flexible-checksums/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.10", "", { "dependencies": { "@smithy/types": "^4.13.0", "fast-xml-parser": "5.4.1", "tslib": "^2.6.2" } }, "sha512-OnejAIVD+CxzyAUrVic7lG+3QRltyja9LoNqCE/1YVs8ichoTbJlVSaZ9iSMcnHLyzrSNtvaOGjSDRP+d/ouFA=="],
"@aws-sdk/middleware-flexible-checksums/@aws-sdk/core/@smithy/core": ["@smithy/core@3.23.9", "", { "dependencies": { "@smithy/middleware-serde": "^4.2.12", "@smithy/protocol-http": "^5.3.11", "@smithy/types": "^4.13.0", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.11", "@smithy/util-stream": "^4.5.17", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-1Vcut4LEL9HZsdpI0vFiRYIsaoPwZLjAxnVQDUMQK8beMS+EYPLDQCXtbzfxmM5GzSgjfe2Q9M7WaXwIMQllyQ=="],
@ -6952,6 +6950,8 @@
"@babel/preset-typescript/@babel/plugin-transform-modules-commonjs/@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.3", "", { "dependencies": { "@babel/helper-module-imports": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1", "@babel/traverse": "^7.28.3" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw=="],
"@eslint/config-array/minimatch/brace-expansion": ["brace-expansion@1.1.18", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw=="],
"@firebase/firestore/@grpc/grpc-js/@types/node": ["@types/node@20.11.16", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ=="],
"@google/genai/google-auth-library/gaxios": ["gaxios@7.1.3", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2", "rimraf": "^5.0.1" } }, "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ=="],
@ -7046,8 +7046,6 @@
"@langchain/google-gauth/google-auth-library/gcp-metadata": ["gcp-metadata@8.1.2", "", { "dependencies": { "gaxios": "^7.0.0", "google-logging-utils": "^1.0.0", "json-bigint": "^1.0.0" } }, "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg=="],
"@langchain/langgraph-checkpoint-mongodb/mongodb/@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.4.13", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-E3Sv4eCYAlKYUTx8S3ioQcDUscOif+8zZ5OnW1IzJ+Tt+EO+ke8mn+Y3FX6N1H79picwbdOavVOb1jPi2EOyrg=="],
"@librechat/agents/@opentelemetry/sdk-node/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.220.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w=="],
"@librechat/agents/@opentelemetry/sdk-node/@opentelemetry/configuration": ["@opentelemetry/configuration@0.220.0", "", { "dependencies": { "@opentelemetry/core": "2.9.0", "yaml": "^2.8.3" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0" } }, "sha512-glfIVKnZevRin8fY/9uES/mhRtMT1lGINLHc9MIo5fTQZXswEEHamJtgjv4MTtzgnhHGC92mIS/0lzAUZMyE0w=="],
@ -7096,88 +7094,6 @@
"@librechat/agents/@opentelemetry/sdk-node/@opentelemetry/sdk-trace-node": ["@opentelemetry/sdk-trace-node@2.9.0", "", { "dependencies": { "@opentelemetry/context-async-hooks": "2.9.0", "@opentelemetry/core": "2.9.0", "@opentelemetry/sdk-trace-base": "2.9.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-ec9a7ps37huy5itYk0MalaZdSLlM6AXWp/FhtEjgMpp5leEGojBDvAl/UWttQnkMZOvFHKzRESn8TD3yKTF5nQ=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/core": ["@aws-sdk/core@3.973.22", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/xml-builder": "^3.972.14", "@smithy/core": "^3.23.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-lY6g5L95jBNgOUitUhfV2N/W+i08jHEl3xuLODYSQH5Sf50V+LkVYBSyZRLtv2RyuXZXiV7yQ+acpswK1tlrOA=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.23", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.20", "@aws-sdk/credential-provider-http": "^3.972.22", "@aws-sdk/credential-provider-ini": "^3.972.22", "@aws-sdk/credential-provider-process": "^3.972.20", "@aws-sdk/credential-provider-sso": "^3.972.22", "@aws-sdk/credential-provider-web-identity": "^3.972.22", "@aws-sdk/types": "^3.973.6", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-U8tyLbLOZItuVWTH0ay9gWo4xMqZwqQbg1oMzdU4FQSkTpqXemm4X0uoKBR6llqAStgBp30ziKFJHTA43l4qMw=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/eventstream-handler-node": ["@aws-sdk/eventstream-handler-node@3.972.11", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/eventstream-codec": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-2IrLrOruRr1NhTK0vguBL1gCWv1pu4bf4KaqpsA+/vCJpFEbvXFawn71GvCzk1wyjnDUsemtKypqoKGv4cSGbA=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-eventstream": ["@aws-sdk/middleware-eventstream@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-r+oP+tbCxgqXVC3pu3MUVePgSY0ILMjA+aEwOosS77m3/DRbtvHrHwqvMcw+cjANMeGzJ+i0ar+n77KXpRA8RQ=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-BnnvYs2ZEpdlmZ2PNlV2ZyQ8j8AEkMTjN79y/YA475ER1ByFYrkVR85qmhni8oeTaJcDqbx364wDpitDAA/wCA=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.23", "", { "dependencies": { "@aws-sdk/core": "^3.973.22", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-retry": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-HQu8QoqGZZTvg0Spl9H39QTsSMFwgu+8yz/QGKndXFLk9FZMiCiIgBCVlTVKMDvVbgqIzD9ig+/HmXsIL2Rb+g=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-websocket": ["@aws-sdk/middleware-websocket@3.972.13", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-format-url": "^3.972.8", "@smithy/eventstream-codec": "^4.2.12", "@smithy/eventstream-serde-browser": "^4.2.12", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/protocol-http": "^5.3.12", "@smithy/signature-v4": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-Gp6EWIqHX5wmsOR5ZxWyyzEU8P0xBdSxkm6VHEwXwBqScKZ7QWRoj6ZmHpr+S44EYb5tuzGya4ottsogSu2W3A=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/config-resolver": "^4.4.11", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1eD4uhTDeambO/PNIDVG19A6+v4NdD7xzwLHDutHsUqz0B+i661MwQB2eYO4/crcCvCiQG4SRm1k81k54FEIvw=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1013.0", "", { "dependencies": { "@aws-sdk/core": "^3.973.22", "@aws-sdk/nested-clients": "^3.996.12", "@aws-sdk/types": "^3.973.6", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-IL1c54UvbuERrs9oLm5rvkzMciwhhpn1FL0SlC3XUMoLlFhdBsWJgQKK8O5fsQLxbFVqjbjFx9OBkrn44X9PHw=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/types": ["@aws-sdk/types@3.973.6", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.5", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-endpoints": "^3.3.3", "tslib": "^2.6.2" } }, "sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/types": "^4.13.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.9", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.23", "@aws-sdk/types": "^3.973.6", "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-jeFqqp8KD/P5O+qeKxyGeu7WEVIZFNprnkaDjGmBOjwxYwafCBhpxTgV1TlW6L8e76Vh/siNylNmN/OmSIFBUQ=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/config-resolver": ["@smithy/config-resolver@4.4.13", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "@smithy/util-config-provider": "^4.2.2", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-iIzMC5NmOUP6WL6o8iPBjFhUhBZ9pPjpUpQYWMUFQqKyXXzOftbfK8zcQCz/jFV1Psmf05BK5ypx4K2r4Tnwdg=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/core": ["@smithy/core@3.23.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-stream": "^4.5.20", "@smithy/util-utf8": "^4.2.2", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-o9VycsYNtgC+Dy3I0yrwCqv9CWicDnke0L7EVOrZtJpjb2t0EjaEofmMrYc0T1Kn3yk32zm6cspxF9u9Bj7e5w=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-browser": ["@smithy/eventstream-serde-browser@4.2.12", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-XUSuMxlTxV5pp4VpqZf6Sa3vT/Q75FVkLSpSSE3KkWBvAQWeuWt1msTv8fJfgA4/jcJhrbrbMzN1AC/hvPmm5A=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-config-resolver": ["@smithy/eventstream-serde-config-resolver@4.3.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-7epsAZ3QvfHkngz6RXQYseyZYHlmWXSTPOfPmXkiS+zA6TBNo1awUaMFL9vxyXlGdoELmCZyZe1nQE+imbmV+Q=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-node": ["@smithy/eventstream-serde-node@4.2.12", "", { "dependencies": { "@smithy/eventstream-serde-universal": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-D1pFuExo31854eAvg89KMn9Oab/wEeJR6Buy32B49A9Ogdtx5fwZPqBHUlDzaCDpycTFk2+fSQgX689Qsk7UGA=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.3.15", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "tslib": "^2.6.2" } }, "sha512-T4jFU5N/yiIfrtrsb9uOQn7RdELdM/7HbyLNr6uO/mpkj1ctiVs7CihVr51w4LyQlXWDpXFn4BElf1WmQvZu/A=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/hash-node": ["@smithy/hash-node@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-QhBYbGrbxTkZ43QoTPrK72DoYviDeg6YKDrHTMJbbC+A0sml3kSjzFtXP7BtbyJnXojLfTQldGdUR0RGD8dA3w=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-/4F1zb7Z8LOu1PalTdESFHR0RbPwHd3FcaG1sI3UEIriQTWakysgJr65lc1jj6QY5ye7aFsisajotH6UhWfm/g=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.2.12", "", { "dependencies": { "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-YE58Yz+cvFInWI/wOTrB+DbvUVz/pLn5mC5MvOV4fdRUc6qGwygyngcucRQjAhiCEbmfLOXX0gntSIcgMvAjmA=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.4.27", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-serde": "^4.2.15", "@smithy/node-config-provider": "^4.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-middleware": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-T3TFfUgXQlpcg+UdzcAISdZpj4Z+XECZ/cefgA6wLBd6V4lRi0svN2hBouN/be9dXQ31X4sLWz3fAQDf+nt6BA=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/middleware-retry": ["@smithy/middleware-retry@4.4.44", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/protocol-http": "^5.3.12", "@smithy/service-error-classification": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/uuid": "^1.1.2", "tslib": "^2.6.2" } }, "sha512-Y1Rav7m5CFRPQyM4CI0koD/bXjyjJu3EQxZZhtLGD88WIrBrQ7kqXM96ncd6rYnojwOo/u9MXu57JrEvu/nLrA=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/middleware-serde": ["@smithy/middleware-serde@4.2.15", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-ExYhcltZSli0pgAKOpQQe1DLFBLryeZ22605y/YS+mQpdNWekum9Ujb/jMKfJKgjtz1AZldtwA/wCYuKJgjjlg=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/middleware-stack": ["@smithy/middleware-stack@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-kruC5gRHwsCOuyCd4ouQxYjgRAym2uDlCvQ5acuMtRrcdfg7mFBg6blaxcJ09STpt3ziEkis6bhg1uwrWU7txw=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/node-config-provider": ["@smithy/node-config-provider@4.3.12", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-tr2oKX2xMcO+rBOjobSwVAkV05SIfUKz8iI53rzxEmgW3GOOPOv0UioSDk+J8OpRQnpnhsO3Af6IEBabQBVmiw=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/protocol-http": ["@smithy/protocol-http@5.3.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-fit0GZK9I1xoRlR4jXmbLhoN0OdEpa96ul8M65XdmXnxXkuMxM0Y8HDT0Fh0Xb4I85MBvBClOzgSrV1X2s1Hxw=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/smithy-client": ["@smithy/smithy-client@4.12.7", "", { "dependencies": { "@smithy/core": "^3.23.12", "@smithy/middleware-endpoint": "^4.4.27", "@smithy/middleware-stack": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-q3gqnwml60G44FECaEEsdQMplYhDMZYCtYhMCzadCnRnnHIobZJjegmdoUo6ieLQlPUzvrMdIJUpx6DoPmzANQ=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/types": ["@smithy/types@4.13.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/url-parser": ["@smithy/url-parser@4.2.12", "", { "dependencies": { "@smithy/querystring-parser": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-wOPKPEpso+doCZGIlr+e1lVI6+9VAKfL4kZWFgzVgGWY2hZxshNKod4l2LXS3PRC9otH/JRSjtEHqQ/7eLciRA=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.3.43", "", { "dependencies": { "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Qd/0wCKMaXxev/z00TvNzGCH2jlKKKxXP1aDxB6oKwSQthe3Og2dMhSayGCnsma1bK/kQX1+X7SMP99t6FgiiQ=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.2.47", "", { "dependencies": { "@smithy/config-resolver": "^4.4.13", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/smithy-client": "^4.12.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-qSRbYp1EQ7th+sPFuVcVO05AE0QH635hycdEXlpzIahqHHf2Fyd/Zl+8v0XYMJ3cgDVPa0lkMefU7oNUjAP+DQ=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/util-endpoints": ["@smithy/util-endpoints@3.3.3", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-VACQVe50j0HZPjpwWcjyT51KUQ4AnsvEaQ2lKHOSL4mNLD0G9BjEniQ+yCt1qqfKfiAHRAts26ud7hBjamrwig=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/util-middleware": ["@smithy/util-middleware@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-Er805uFUOvgc0l8nv0e0su0VFISoxhJ/AwOn3gL2NWNY2LUEldP5WtVcRYSQBcjg0y9NfG8JYrCJaYDpupBHJQ=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/util-retry": ["@smithy/util-retry@4.2.12", "", { "dependencies": { "@smithy/service-error-classification": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-1zopLDUEOwumjcHdJ1mwBHddubYF8GMQvstVCLC54Y46rqoHwlIU+8ZzUeaBcD+WCJHyDGSeZ2ml9YSe9aqcoQ=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/util-stream": ["@smithy/util-stream@4.5.20", "", { "dependencies": { "@smithy/fetch-http-handler": "^5.3.15", "@smithy/node-http-handler": "^4.5.0", "@smithy/types": "^4.13.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-buffer-from": "^4.2.2", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-4yXLm5n/B5SRBR2p8cZ90Sbv4zL4NKsgxdzCzp/83cXw2KxLEumt5p+GAVyRNZgQOSrzXn9ARpO0lUe8XSlSDw=="],
"@librechat/backend/@smithy/node-http-handler/@smithy/protocol-http": ["@smithy/protocol-http@5.3.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-fit0GZK9I1xoRlR4jXmbLhoN0OdEpa96ul8M65XdmXnxXkuMxM0Y8HDT0Fh0Xb4I85MBvBClOzgSrV1X2s1Hxw=="],
"@librechat/backend/@smithy/node-http-handler/@smithy/types": ["@smithy/types@4.13.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g=="],
"@librechat/frontend/@react-spring/web/@react-spring/animated": ["@react-spring/animated@9.7.5", "", { "dependencies": { "@react-spring/shared": "~9.7.5", "@react-spring/types": "~9.7.5" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg=="],
"@librechat/frontend/@react-spring/web/@react-spring/core": ["@react-spring/core@9.7.5", "", { "dependencies": { "@react-spring/animated": "~9.7.5", "@react-spring/shared": "~9.7.5", "@react-spring/types": "~9.7.5" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "sha512-rmEqcxRcu7dWh7MnCcMXLvrf6/SDlSokLaLTxiPlAYi11nN3B5oiCUAblO72o+9z/87j2uzxa2Inm8UbLjXA+w=="],
@ -7334,12 +7250,6 @@
"@rollup/plugin-babel/@babel/helper-module-imports/@babel/types": ["@babel/types@7.29.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg=="],
"@smithy/util-stream/@smithy/fetch-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "@smithy/util-uri-escape": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-7spdikrYiljpket6u0up2Ck2mxhy7dZ0+TDd+S53Dg2DHd6wg+YNJrTCHiLdgZmEXZKI7LJZcwL3721ZRDFiqA=="],
"@smithy/util-stream/@smithy/node-http-handler/@smithy/abort-controller": ["@smithy/abort-controller@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "tslib": "^2.6.2" } }, "sha512-Hj4WoYWMJnSpM6/kchsm4bUNTL9XiSyhvoMb2KIq4VJzyDt7JpGHUZHkVNPZVC7YE1tf8tPeVauxpFBKGW4/KQ=="],
"@smithy/util-stream/@smithy/node-http-handler/@smithy/querystring-builder": ["@smithy/querystring-builder@4.2.11", "", { "dependencies": { "@smithy/types": "^4.13.0", "@smithy/util-uri-escape": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-7spdikrYiljpket6u0up2Ck2mxhy7dZ0+TDd+S53Dg2DHd6wg+YNJrTCHiLdgZmEXZKI7LJZcwL3721ZRDFiqA=="],
"@testing-library/dom/@babel/code-frame/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
"@testing-library/dom/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
@ -7388,6 +7298,8 @@
"@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="],
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@5.0.9", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg=="],
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
"@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
@ -7438,8 +7350,16 @@
"data-urls/whatwg-url/webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="],
"eslint-plugin-import/minimatch/brace-expansion": ["brace-expansion@1.1.18", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw=="],
"eslint-plugin-jsx-a11y/minimatch/brace-expansion": ["brace-expansion@1.1.18", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw=="],
"eslint-plugin-react/minimatch/brace-expansion": ["brace-expansion@1.1.18", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw=="],
"eslint/@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="],
"eslint/minimatch/brace-expansion": ["brace-expansion@1.1.18", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw=="],
"expect/jest-message-util/@babel/code-frame": ["@babel/code-frame@7.27.1", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg=="],
"expect/jest-message-util/@jest/types": ["@jest/types@29.6.3", "", { "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", "@types/yargs": "^17.0.8", "chalk": "^4.0.0" } }, "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw=="],
@ -7464,6 +7384,8 @@
"gcp-metadata/gaxios/https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="],
"glob/minimatch/brace-expansion": ["brace-expansion@5.0.9", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg=="],
"google-auth-library/gcp-metadata/google-logging-utils": ["google-logging-utils@0.0.2", "", {}, "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ=="],
"hast-util-from-html-isomorphic/@types/hast/@types/unist": ["@types/unist@2.0.10", "", {}, "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="],
@ -7516,6 +7438,8 @@
"istanbul-lib-report/supports-color/has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
"jake/minimatch/brace-expansion": ["brace-expansion@1.1.18", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw=="],
"jest-changed-files/execa/human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="],
"jest-changed-files/execa/npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="],
@ -7662,18 +7586,16 @@
"mongodb-connection-string-url/whatwg-url/webidl-conversions": ["webidl-conversions@7.0.0", "", {}, "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="],
"mongodb-memory-server-core/mongodb/@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.4.13", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-E3Sv4eCYAlKYUTx8S3ioQcDUscOif+8zZ5OnW1IzJ+Tt+EO+ke8mn+Y3FX6N1H79picwbdOavVOb1jPi2EOyrg=="],
"mongodb-memory-server-core/mongodb/bson": ["bson@7.3.1", "", {}, "sha512-h/C0qe6857pQhcSJHLfsR1uYGj98Ge3wKAD3Ed9KqH3wcVh+BM4Jq4xISD7vs9OPuT07n+q3QQVjslJ286j6ag=="],
"mongodb-memory-server-core/mongodb/mongodb-connection-string-url": ["mongodb-connection-string-url@7.0.2", "", { "dependencies": { "@types/whatwg-url": "^13.0.0", "whatwg-url": "^14.1.0" } }, "sha512-ZoS07RoFqpKYQwAk59qmrx8+jJHNHU30UjlU96QktiGn1ltvDr+vCznLX5DiUBLEpMAHatHNWV1nM/74ul66kA=="],
"mongoose/mongodb/@mongodb-js/saslprep": ["@mongodb-js/saslprep@1.4.13", "", { "dependencies": { "sparse-bitfield": "^3.0.3" } }, "sha512-E3Sv4eCYAlKYUTx8S3ioQcDUscOif+8zZ5OnW1IzJ+Tt+EO+ke8mn+Y3FX6N1H79picwbdOavVOb1jPi2EOyrg=="],
"multer/type-is/media-typer": ["media-typer@0.3.0", "", {}, "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ=="],
"multer/type-is/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
"nodemon/minimatch/brace-expansion": ["brace-expansion@5.0.9", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg=="],
"parse-json/@babel/code-frame/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
"pbkdf2/ripemd160/hash-base": ["hash-base@2.0.2", "", { "dependencies": { "inherits": "^2.0.1" } }, "sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw=="],
@ -7728,6 +7650,8 @@
"tailwindcss/postcss-load-config/lilconfig": ["lilconfig@3.0.0", "", {}, "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g=="],
"test-exclude/minimatch/brace-expansion": ["brace-expansion@5.0.9", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg=="],
"typescript-eslint/@typescript-eslint/eslint-plugin/@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="],
"typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.65.0", "", { "dependencies": { "@typescript-eslint/types": "8.65.0", "@typescript-eslint/visitor-keys": "8.65.0" } }, "sha512-Esbl8OSYiVxBokYgWPf7VVWg/BE798wXhimnn9ML9Pt5qoDf8bfQlgjlKXR/k98+AcNzlLKYrpCcrcuZ9DZLgg=="],
@ -8132,64 +8056,6 @@
"@librechat/agents/@opentelemetry/sdk-node/@opentelemetry/otlp-grpc-exporter-base/@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.220.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.220.0", "@opentelemetry/core": "2.9.0", "@opentelemetry/resources": "2.9.0", "@opentelemetry/sdk-logs": "0.220.0", "@opentelemetry/sdk-metrics": "2.9.0", "@opentelemetry/sdk-trace": "2.9.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-lXGrv7KXZ0gNH9SVNUaa6vv6phVYGvJxfXAlMbzbakiXru75f5MZl8Z7oqiMMQD77riVHJCFlQvbZs/VVN2/4A=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.14", "", { "dependencies": { "@smithy/types": "^4.13.1", "fast-xml-parser": "5.5.6", "tslib": "^2.6.2" } }, "sha512-G/Yd8Bnnyh8QrqLf8jWJbixEnScUFW24e/wOBGYdw1Cl4r80KX/DvHyM2GVZ2vTp7J4gTEr8IXJlTadA8+UfuQ=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@smithy/property-provider": ["@smithy/property-provider@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-jqve46eYU1v7pZ5BM+fmkbq3DerkSluPr5EhvOcHxygxzD05ByDRppRwRPPpFrsFo5yDtCYLKu+kreHKVrvc7A=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/core/@smithy/signature-v4": ["@smithy/signature-v4@5.3.12", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.2", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-uri-escape": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-B/FBwO3MVOL00DaRSXfXfa/TRXRheagt/q5A2NM13u7q+sHS59EOVGQNfG7DkmVtdQm5m3vOosoKAXSqn/OEgw=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.20", "", { "dependencies": { "@aws-sdk/core": "^3.973.22", "@aws-sdk/types": "^3.973.6", "@smithy/property-provider": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-vI0QN96DFx3g9AunfOWF3CS4cMkqFiR/WM/FyP9QHr5rZ2dKPkYwP3tCgAOvGuu9CXI7dC1vU2FVUuZ+tfpNvQ=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.22", "", { "dependencies": { "@aws-sdk/core": "^3.973.22", "@aws-sdk/types": "^3.973.6", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/node-http-handler": "^4.5.0", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/util-stream": "^4.5.20", "tslib": "^2.6.2" } }, "sha512-aS/81smalpe7XDnuQfOq4LIPuaV2PRKU2aMTrHcqO5BD4HwO5kESOHNcec2AYfBtLtIDqgF6RXisgBnfK/jt0w=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.972.22", "", { "dependencies": { "@aws-sdk/core": "^3.973.22", "@aws-sdk/credential-provider-env": "^3.972.20", "@aws-sdk/credential-provider-http": "^3.972.22", "@aws-sdk/credential-provider-login": "^3.972.22", "@aws-sdk/credential-provider-process": "^3.972.20", "@aws-sdk/credential-provider-sso": "^3.972.22", "@aws-sdk/credential-provider-web-identity": "^3.972.22", "@aws-sdk/nested-clients": "^3.996.12", "@aws-sdk/types": "^3.973.6", "@smithy/credential-provider-imds": "^4.2.12", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-rpF8fBT0LllMDp78s62aL2A/8MaccjyJ0ORzqu+ZADeECLSrrCWIeeXsuRam+pxiAMkI1uIyDZJmgLGdadkPXw=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.20", "", { "dependencies": { "@aws-sdk/core": "^3.973.22", "@aws-sdk/types": "^3.973.6", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-QRfk7GbA4/HDRjhP3QYR6QBr/QKreVoOzvvlRHnOuGgYJkeoPgPY3LAI1kK1ZMgZ4hH9KiGp757/ntol+INAig=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.972.22", "", { "dependencies": { "@aws-sdk/core": "^3.973.22", "@aws-sdk/nested-clients": "^3.996.12", "@aws-sdk/token-providers": "3.1013.0", "@aws-sdk/types": "^3.973.6", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-4vqlSaUbBj4aNPVKfB6yXuIQ2Z2mvLfIGba2OzzF6zUkN437/PGWsxBU2F8QPSFHti6seckvyCXidU3H+R8NvQ=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.22", "", { "dependencies": { "@aws-sdk/core": "^3.973.22", "@aws-sdk/nested-clients": "^3.996.12", "@aws-sdk/types": "^3.973.6", "@smithy/property-provider": "^4.2.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-/wN1CYg2rVLhW8/jLxMWacQrkpaynnL+4j/Z+e6X1PfoE6NiC0BeOw3i0JmtZrKun85wNV5GmspvuWJihfeeUw=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.12", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-cr2lR792vNZcYMriSIj+Um3x9KWrjcu98kn234xA6reOAFMmbRpQMOv8KPgEmLLtx3eldU6c5wALKFqNOhugmg=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@smithy/property-provider": ["@smithy/property-provider@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-jqve46eYU1v7pZ5BM+fmkbq3DerkSluPr5EhvOcHxygxzD05ByDRppRwRPPpFrsFo5yDtCYLKu+kreHKVrvc7A=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.7", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-HrOKWsUb+otTeo1HxVWeEb99t5ER1XrBi/xka2Wv6NVmTbuCUC1dvlrksdvxFtODLBjsC+PHK+fuy2x/7Ynyiw=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-recursion-detection/@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.2", "", {}, "sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-websocket/@aws-sdk/util-format-url": ["@aws-sdk/util-format-url@3.972.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.6", "@smithy/querystring-builder": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-J6DS9oocrgxM8xlUTTmQOuwRF6rnAGEujAN9SAzllcrQmwn5iJ58ogxy3SEhD0Q7JZvlA5jvIXBkpQRqEqlE9A=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/middleware-websocket/@smithy/signature-v4": ["@smithy/signature-v4@5.3.12", "", { "dependencies": { "@smithy/is-array-buffer": "^4.2.2", "@smithy/protocol-http": "^5.3.12", "@smithy/types": "^4.13.1", "@smithy/util-hex-encoding": "^4.2.2", "@smithy/util-middleware": "^4.2.12", "@smithy/util-uri-escape": "^4.2.2", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-B/FBwO3MVOL00DaRSXfXfa/TRXRheagt/q5A2NM13u7q+sHS59EOVGQNfG7DkmVtdQm5m3vOosoKAXSqn/OEgw=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/token-providers/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.12", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.22", "@aws-sdk/middleware-host-header": "^3.972.8", "@aws-sdk/middleware-logger": "^3.972.8", "@aws-sdk/middleware-recursion-detection": "^3.972.8", "@aws-sdk/middleware-user-agent": "^3.972.23", "@aws-sdk/region-config-resolver": "^3.972.8", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@aws-sdk/util-user-agent-browser": "^3.972.8", "@aws-sdk/util-user-agent-node": "^3.973.9", "@smithy/config-resolver": "^4.4.11", "@smithy/core": "^3.23.12", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.26", "@smithy/middleware-retry": "^4.4.43", "@smithy/middleware-serde": "^4.2.15", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.0", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.42", "@smithy/util-defaults-mode-node": "^4.2.45", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-KLdQGJPSm98uLINolQ0Tol8OAbk7g0Y7zplHJ1K83vbMIH13aoCvR6Tho66xueW4l4aZlEgVGLWBnD8ifUMsGQ=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/token-providers/@smithy/property-provider": ["@smithy/property-provider@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-jqve46eYU1v7pZ5BM+fmkbq3DerkSluPr5EhvOcHxygxzD05ByDRppRwRPPpFrsFo5yDtCYLKu+kreHKVrvc7A=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/token-providers/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.7", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-HrOKWsUb+otTeo1HxVWeEb99t5ER1XrBi/xka2Wv6NVmTbuCUC1dvlrksdvxFtODLBjsC+PHK+fuy2x/7Ynyiw=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-browser/@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.12", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-+yNuTiyBACxOJUTvbsNsSOfH9G9oKbaJE1lNL3YHpGcuucl6rPZMi3nrpehpVOVR2E07YqFFmtwpImtpzlouHQ=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/eventstream-serde-node/@smithy/eventstream-serde-universal": ["@smithy/eventstream-serde-universal@4.2.12", "", { "dependencies": { "@smithy/eventstream-codec": "^4.2.12", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-+yNuTiyBACxOJUTvbsNsSOfH9G9oKbaJE1lNL3YHpGcuucl6rPZMi3nrpehpVOVR2E07YqFFmtwpImtpzlouHQ=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/middleware-endpoint/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.7", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-HrOKWsUb+otTeo1HxVWeEb99t5ER1XrBi/xka2Wv6NVmTbuCUC1dvlrksdvxFtODLBjsC+PHK+fuy2x/7Ynyiw=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/middleware-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1" } }, "sha512-LlP29oSQN0Tw0b6D0Xo6BIikBswuIiGYbRACy5ujw/JgWSzTdYj46U83ssf6Ux0GyNJVivs2uReU8pt7Eu9okQ=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/node-config-provider/@smithy/property-provider": ["@smithy/property-provider@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-jqve46eYU1v7pZ5BM+fmkbq3DerkSluPr5EhvOcHxygxzD05ByDRppRwRPPpFrsFo5yDtCYLKu+kreHKVrvc7A=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/node-config-provider/@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.4.7", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-HrOKWsUb+otTeo1HxVWeEb99t5ER1XrBi/xka2Wv6NVmTbuCUC1dvlrksdvxFtODLBjsC+PHK+fuy2x/7Ynyiw=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/url-parser/@smithy/querystring-parser": ["@smithy/querystring-parser@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-P2OdvrgiAKpkPNKlKUtWbNZKB1XjPxM086NeVhK+W+wI46pIKdWBe5QyXvhUm3MEcyS/rkLvY8rZzyUdmyDZBw=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-browser/@smithy/property-provider": ["@smithy/property-provider@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-jqve46eYU1v7pZ5BM+fmkbq3DerkSluPr5EhvOcHxygxzD05ByDRppRwRPPpFrsFo5yDtCYLKu+kreHKVrvc7A=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-node/@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.2.12", "", { "dependencies": { "@smithy/node-config-provider": "^4.3.12", "@smithy/property-provider": "^4.2.12", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "tslib": "^2.6.2" } }, "sha512-cr2lR792vNZcYMriSIj+Um3x9KWrjcu98kn234xA6reOAFMmbRpQMOv8KPgEmLLtx3eldU6c5wALKFqNOhugmg=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/util-defaults-mode-node/@smithy/property-provider": ["@smithy/property-provider@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-jqve46eYU1v7pZ5BM+fmkbq3DerkSluPr5EhvOcHxygxzD05ByDRppRwRPPpFrsFo5yDtCYLKu+kreHKVrvc7A=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@smithy/util-retry/@smithy/service-error-classification": ["@smithy/service-error-classification@4.2.12", "", { "dependencies": { "@smithy/types": "^4.13.1" } }, "sha512-LlP29oSQN0Tw0b6D0Xo6BIikBswuIiGYbRACy5ujw/JgWSzTdYj46U83ssf6Ux0GyNJVivs2uReU8pt7Eu9okQ=="],
"@librechat/frontend/@react-spring/web/@react-spring/shared/@react-spring/rafz": ["@react-spring/rafz@9.7.5", "", {}, "sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw=="],
"@librechat/frontend/@testing-library/jest-dom/chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
@ -8240,6 +8106,8 @@
"@rollup/plugin-babel/@babel/helper-module-imports/@babel/types/@babel/helper-string-parser": ["@babel/helper-string-parser@7.29.7", "", {}, "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw=="],
"@typescript-eslint/typescript-estree/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
"@unrs/resolver-binding-wasm32-wasi/@napi-rs/wasm-runtime/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
"babel-plugin-transform-import-meta/@babel/template/@babel/code-frame/@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="],
@ -8272,6 +8140,8 @@
"gcp-metadata/gaxios/https-proxy-agent/debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
"glob/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
"hast-util-from-html-isomorphic/unist-util-remove-position/unist-util-visit/unist-util-is": ["unist-util-is@5.2.1", "", { "dependencies": { "@types/unist": "^2.0.0" } }, "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw=="],
"hast-util-from-html-isomorphic/unist-util-remove-position/unist-util-visit/unist-util-visit-parents": ["unist-util-visit-parents@5.1.3", "", { "dependencies": { "@types/unist": "^2.0.0", "unist-util-is": "^5.0.0" } }, "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg=="],
@ -8346,6 +8216,8 @@
"multer/type-is/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
"nodemon/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
"pkg-dir/find-up/locate-path/p-locate": ["p-locate@4.1.0", "", { "dependencies": { "p-limit": "^2.2.0" } }, "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="],
"rehype-highlight/unified/vfile/unist-util-stringify-position": ["unist-util-stringify-position@3.0.3", "", { "dependencies": { "@types/unist": "^2.0.0" } }, "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg=="],
@ -8356,6 +8228,8 @@
"sucrase/glob/path-scurry/lru-cache": ["lru-cache@10.2.0", "", {}, "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q=="],
"test-exclude/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="],
"typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/types": ["@typescript-eslint/types@8.65.0", "", {}, "sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg=="],
"typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/types": ["@typescript-eslint/types@8.65.0", "", {}, "sha512-JSSwWNy+H0E/01jJEM+hrX6N0OFDzFzeIhHFSAS01tlVaevpG8cFyYRPhS5yjGOvBUx3sqQHVMjCL1CAZZMxBg=="],
@ -8522,14 +8396,6 @@
"@librechat/agents/@opentelemetry/sdk-node/@opentelemetry/instrumentation/import-in-the-middle/cjs-module-lexer": ["cjs-module-lexer@2.2.0", "", {}, "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.22", "", { "dependencies": { "@aws-sdk/core": "^3.973.22", "@aws-sdk/nested-clients": "^3.996.12", "@aws-sdk/types": "^3.973.6", "@smithy/property-provider": "^4.2.12", "@smithy/protocol-http": "^5.3.12", "@smithy/shared-ini-file-loader": "^4.4.7", "@smithy/types": "^4.13.1", "tslib": "^2.6.2" } }, "sha512-u33CO9zeNznlVSg9tWTCRYxaGkqr1ufU6qeClpmzAabXZa8RZxQoVXxL5T53oZJFzQYj+FImORCSsi7H7B77gQ=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-ini/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.12", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.22", "@aws-sdk/middleware-host-header": "^3.972.8", "@aws-sdk/middleware-logger": "^3.972.8", "@aws-sdk/middleware-recursion-detection": "^3.972.8", "@aws-sdk/middleware-user-agent": "^3.972.23", "@aws-sdk/region-config-resolver": "^3.972.8", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@aws-sdk/util-user-agent-browser": "^3.972.8", "@aws-sdk/util-user-agent-node": "^3.973.9", "@smithy/config-resolver": "^4.4.11", "@smithy/core": "^3.23.12", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.26", "@smithy/middleware-retry": "^4.4.43", "@smithy/middleware-serde": "^4.2.15", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.0", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.42", "@smithy/util-defaults-mode-node": "^4.2.45", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-KLdQGJPSm98uLINolQ0Tol8OAbk7g0Y7zplHJ1K83vbMIH13aoCvR6Tho66xueW4l4aZlEgVGLWBnD8ifUMsGQ=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-sso/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.12", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.22", "@aws-sdk/middleware-host-header": "^3.972.8", "@aws-sdk/middleware-logger": "^3.972.8", "@aws-sdk/middleware-recursion-detection": "^3.972.8", "@aws-sdk/middleware-user-agent": "^3.972.23", "@aws-sdk/region-config-resolver": "^3.972.8", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@aws-sdk/util-user-agent-browser": "^3.972.8", "@aws-sdk/util-user-agent-node": "^3.973.9", "@smithy/config-resolver": "^4.4.11", "@smithy/core": "^3.23.12", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.26", "@smithy/middleware-retry": "^4.4.43", "@smithy/middleware-serde": "^4.2.15", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.0", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.42", "@smithy/util-defaults-mode-node": "^4.2.45", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-KLdQGJPSm98uLINolQ0Tol8OAbk7g0Y7zplHJ1K83vbMIH13aoCvR6Tho66xueW4l4aZlEgVGLWBnD8ifUMsGQ=="],
"@librechat/backend/@aws-sdk/client-bedrock-runtime/@aws-sdk/credential-provider-node/@aws-sdk/credential-provider-web-identity/@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.996.12", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.973.22", "@aws-sdk/middleware-host-header": "^3.972.8", "@aws-sdk/middleware-logger": "^3.972.8", "@aws-sdk/middleware-recursion-detection": "^3.972.8", "@aws-sdk/middleware-user-agent": "^3.972.23", "@aws-sdk/region-config-resolver": "^3.972.8", "@aws-sdk/types": "^3.973.6", "@aws-sdk/util-endpoints": "^3.996.5", "@aws-sdk/util-user-agent-browser": "^3.972.8", "@aws-sdk/util-user-agent-node": "^3.973.9", "@smithy/config-resolver": "^4.4.11", "@smithy/core": "^3.23.12", "@smithy/fetch-http-handler": "^5.3.15", "@smithy/hash-node": "^4.2.12", "@smithy/invalid-dependency": "^4.2.12", "@smithy/middleware-content-length": "^4.2.12", "@smithy/middleware-endpoint": "^4.4.26", "@smithy/middleware-retry": "^4.4.43", "@smithy/middleware-serde": "^4.2.15", "@smithy/middleware-stack": "^4.2.12", "@smithy/node-config-provider": "^4.3.12", "@smithy/node-http-handler": "^4.5.0", "@smithy/protocol-http": "^5.3.12", "@smithy/smithy-client": "^4.12.6", "@smithy/types": "^4.13.1", "@smithy/url-parser": "^4.2.12", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.42", "@smithy/util-defaults-mode-node": "^4.2.45", "@smithy/util-endpoints": "^3.3.3", "@smithy/util-middleware": "^4.2.12", "@smithy/util-retry": "^4.2.12", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-KLdQGJPSm98uLINolQ0Tol8OAbk7g0Y7zplHJ1K83vbMIH13aoCvR6Tho66xueW4l4aZlEgVGLWBnD8ifUMsGQ=="],
"@librechat/frontend/@testing-library/jest-dom/chalk/supports-color/has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="],
"@mcp-ui/client/@modelcontextprotocol/sdk/express/body-parser/iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="],

View file

@ -1,13 +1,13 @@
import { useState, useMemo } from 'react';
import { ChevronDown } from 'lucide-react';
import { Tools } from 'librechat-data-provider';
import { UIResourceRenderer } from '@mcp-ui/client';
import type { TAttachment, UIResource } from 'librechat-data-provider';
import UIResourceRenderer, { isSupportedUIResource } from '~/components/MCPUIResource/Renderer';
import { useOptionalMessagesOperations } from '~/Providers';
import { useLocalize, useExpandCollapse } from '~/hooks';
import UIResourceCarousel from './UIResourceCarousel';
import { handleUIAction, cn } from '~/utils';
import { OutputRenderer } from './ToolOutput';
import { handleUIAction, cn } from '~/utils';
function isSimpleObject(obj: unknown): obj is Record<string, string | number | boolean | null> {
if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) {
@ -126,7 +126,8 @@ export default function ToolCallInfo({
?.filter((attachment) => attachment.type === Tools.ui_resources)
.flatMap((attachment) => {
return attachment[Tools.ui_resources] as UIResource[];
}) ?? [];
})
.filter(isSupportedUIResource) ?? [];
return (
<div className="w-full px-3 py-3.5">

View file

@ -1,8 +1,8 @@
import React, { useState } from 'react';
import { Button } from '@librechat/client';
import { UIResourceRenderer } from '@mcp-ui/client';
import { ChevronLeft, ChevronRight } from 'lucide-react';
import type { UIResource } from 'librechat-data-provider';
import UIResourceRenderer, { isSupportedUIResource } from '~/components/MCPUIResource/Renderer';
import { useOptionalMessagesOperations } from '~/Providers';
import { handleUIAction } from '~/utils';
import { useLocalize } from '~/hooks';
@ -18,6 +18,10 @@ const UIResourceCarousel: React.FC<UIResourceCarouselProps> = React.memo(({ uiRe
const [isContainerHovered, setIsContainerHovered] = useState(false);
const scrollContainerRef = React.useRef<HTMLDivElement>(null);
const { ask } = useOptionalMessagesOperations();
const supportedUIResources = React.useMemo(
() => uiResources.filter(isSupportedUIResource),
[uiResources],
);
const handleScroll = React.useCallback(() => {
if (!scrollContainerRef.current) return;
@ -49,12 +53,24 @@ const UIResourceCarousel: React.FC<UIResourceCarouselProps> = React.memo(({ uiRe
handleScroll();
return () => container.removeEventListener('scroll', handleScroll);
}
}, [handleScroll]);
}, [handleScroll, supportedUIResources.length]);
if (uiResources.length === 0) {
if (supportedUIResources.length === 0) {
return null;
}
if (supportedUIResources.length === 1) {
return (
<UIResourceRenderer
resource={supportedUIResources[0]}
onUIAction={async (result) => handleUIAction(result, ask)}
htmlProps={{
autoResizeIframe: { width: true, height: true },
}}
/>
);
}
return (
<div
className="relative mb-4 pt-3"
@ -91,7 +107,7 @@ const UIResourceCarousel: React.FC<UIResourceCarouselProps> = React.memo(({ uiRe
ref={scrollContainerRef}
className="hide-scrollbar flex gap-4 overflow-x-auto scroll-smooth"
>
{uiResources.map((uiResource, index) => {
{supportedUIResources.map((uiResource, index) => {
const height = 360;
const width = 230;

View file

@ -64,8 +64,10 @@ describe('ToolCallInfo', () => {
describe('ui_resources from attachments', () => {
it('should render single ui_resource from attachments', () => {
const uiResource = {
type: 'text',
data: 'Test resource',
resourceId: 'resource-1',
uri: 'ui://test/resource-1',
mimeType: 'text/html',
text: 'Test resource',
};
const attachments: TAttachment[] = [
@ -104,10 +106,25 @@ describe('ToolCallInfo', () => {
toolCallId: 'tool1',
conversationId: 'conv1',
[Tools.ui_resources]: [
{ type: 'text', data: 'Resource 1' },
{ type: 'text', data: 'Resource 2' },
{ type: 'text', data: 'Resource 3' },
] as any,
{
resourceId: 'resource-1',
uri: 'ui://test/resource-1',
mimeType: 'text/html',
text: 'Resource 1',
},
{
resourceId: 'resource-2',
uri: 'ui://test/resource-2',
mimeType: 'text/html',
text: 'Resource 2',
},
{
resourceId: 'resource-3',
uri: 'ui://test/resource-3',
mimeType: 'text/html',
text: 'Resource 3',
},
],
},
];
@ -117,9 +134,9 @@ describe('ToolCallInfo', () => {
expect(UIResourceCarousel).toHaveBeenCalledWith(
expect.objectContaining({
uiResources: [
{ type: 'text', data: 'Resource 1' },
{ type: 'text', data: 'Resource 2' },
{ type: 'text', data: 'Resource 3' },
expect.objectContaining({ resourceId: 'resource-1' }),
expect.objectContaining({ resourceId: 'resource-2' }),
expect.objectContaining({ resourceId: 'resource-3' }),
],
}),
expect.any(Object),
@ -129,6 +146,65 @@ describe('ToolCallInfo', () => {
expect(UIResourceRenderer).not.toHaveBeenCalled();
});
it('renders a single supported resource without carousel layout', () => {
const attachments: TAttachment[] = [
{
type: Tools.ui_resources,
messageId: 'msg1',
toolCallId: 'tool1',
conversationId: 'conv1',
[Tools.ui_resources]: [
{
resourceId: 'blocked-resource',
uri: 'ui://test/blocked',
mimeType: 'application/vnd.mcp-ui.remote-dom+javascript',
text: 'malicious script',
},
{
resourceId: 'html-resource',
uri: 'ui://test/html',
mimeType: 'text/html',
text: '<p>Supported</p>',
},
],
},
];
render(<ToolCallInfo {...mockProps} attachments={attachments} />);
expect(UIResourceRenderer).toHaveBeenCalledWith(
expect.objectContaining({
resource: expect.objectContaining({ resourceId: 'html-resource' }),
}),
expect.any(Object),
);
expect(UIResourceCarousel).not.toHaveBeenCalled();
});
it('omits the resource section when every resource is blocked', () => {
const attachments: TAttachment[] = [
{
type: Tools.ui_resources,
messageId: 'msg1',
toolCallId: 'tool1',
conversationId: 'conv1',
[Tools.ui_resources]: [
{
resourceId: 'blocked-resource',
uri: 'ui://test/blocked',
mimeType: 'text/uri-list',
text: 'https://example.com',
},
],
},
];
render(<ToolCallInfo input="" attachments={attachments} />);
expect(UIResourceRenderer).not.toHaveBeenCalled();
expect(UIResourceCarousel).not.toHaveBeenCalled();
});
it('should handle no attachments', () => {
render(<ToolCallInfo {...mockProps} output="Some output" />);
@ -200,7 +276,14 @@ describe('ToolCallInfo', () => {
messageId: 'msg123',
toolCallId: 'tool456',
conversationId: 'conv789',
[Tools.ui_resources]: [{ type: 'text', data: 'Test' }] as any,
[Tools.ui_resources]: [
{
resourceId: 'resource-1',
uri: 'ui://test/resource-1',
mimeType: 'text/html',
text: 'Test',
},
],
},
];
@ -208,7 +291,7 @@ describe('ToolCallInfo', () => {
expect(UIResourceRenderer).toHaveBeenCalledWith(
expect.objectContaining({
resource: { type: 'text', data: 'Test' },
resource: expect.objectContaining({ resourceId: 'resource-1', text: 'Test' }),
}),
expect.any(Object),
);
@ -241,7 +324,14 @@ describe('ToolCallInfo', () => {
messageId: 'msg123',
toolCallId: 'tool456',
conversationId: 'conv789',
[Tools.ui_resources]: [{ type: 'attachment', data: 'From attachments' }] as any,
[Tools.ui_resources]: [
{
resourceId: 'attachment-resource',
uri: 'ui://test/attachment-resource',
mimeType: 'text/html',
text: 'From attachments',
},
],
},
];
@ -259,7 +349,10 @@ describe('ToolCallInfo', () => {
// Should use attachments, not output
expect(UIResourceRenderer).toHaveBeenCalledWith(
expect.objectContaining({
resource: { type: 'attachment', data: 'From attachments' },
resource: expect.objectContaining({
resourceId: 'attachment-resource',
text: 'From attachments',
}),
}),
expect.any(Object),
);

View file

@ -1,9 +1,27 @@
import '@testing-library/jest-dom';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import type { UIResource } from 'librechat-data-provider';
import type { ComponentProps } from 'react';
import UIResourceCarousel from '~/components/Chat/Messages/Content/UIResourceCarousel';
import { handleUIAction } from '~/utils';
jest.mock(
'@librechat/client',
() => ({
Button: ({
variant: _variant,
size: _size,
...props
}: ComponentProps<'button'> & { variant?: string; size?: string }) => <button {...props} />,
}),
{ virtual: true },
);
jest.mock('~/hooks', () => ({
useLocalize: () => (key: string) =>
key === 'com_ui_scroll_left' ? 'Scroll left' : 'Scroll right',
}));
// Mock the UIResourceRenderer component
jest.mock('@mcp-ui/client', () => ({
UIResourceRenderer: ({ resource, onUIAction }: any) => (
@ -69,6 +87,43 @@ describe('UIResourceCarousel', () => {
expect(container.firstChild).toBeNull();
});
it('filters blocked resources before choosing a single-resource layout', () => {
const { container } = render(
<UIResourceCarousel
uiResources={[
{
resourceId: 'blocked-resource',
uri: 'ui://blocked',
mimeType: 'application/vnd.mcp-ui.remote-dom+javascript',
text: 'malicious script',
},
mockUIResources[0],
]}
/>,
);
expect(screen.getAllByTestId('ui-resource-renderer')).toHaveLength(1);
expect(screen.getByText('Resource 1')).toBeInTheDocument();
expect(container.querySelector('.hide-scrollbar')).not.toBeInTheDocument();
});
it('renders nothing when every resource is blocked', () => {
const { container } = render(
<UIResourceCarousel
uiResources={[
{
resourceId: 'blocked-resource',
uri: 'ui://blocked',
mimeType: 'text/uri-list',
text: 'https://example.com',
},
]}
/>,
);
expect(container.firstChild).toBeNull();
});
it('renders all UI resources', () => {
render(<UIResourceCarousel uiResources={mockUIResources} />);
const renderers = screen.getAllByTestId('ui-resource-renderer');
@ -141,6 +196,26 @@ describe('UIResourceCarousel', () => {
});
});
it('binds scrolling when a singleton becomes a carousel', async () => {
const { container, rerender } = render(
<UIResourceCarousel uiResources={mockUIResources.slice(0, 1)} />,
);
expect(container.querySelector('.hide-scrollbar')).not.toBeInTheDocument();
rerender(<UIResourceCarousel uiResources={mockUIResources.slice(0, 2)} />);
const scrollContainer = container.querySelector('.hide-scrollbar');
Object.defineProperty(scrollContainer, 'scrollLeft', {
configurable: true,
value: 200,
});
fireEvent.scroll(scrollContainer!);
await waitFor(() => {
expect(screen.getByLabelText('Scroll left')).toBeInTheDocument();
});
});
it('hides right arrow when scrolled to end', async () => {
const { container } = render(<UIResourceCarousel uiResources={mockUIResources} />);
const scrollContainer = container.querySelector('.hide-scrollbar');

View file

@ -1,7 +1,7 @@
import React from 'react';
import { UIResourceRenderer } from '@mcp-ui/client';
import { useOptionalMessagesConversation, useOptionalMessagesOperations } from '~/Providers';
import { useConversationUIResources } from '~/hooks/Messages/useConversationUIResources';
import UIResourceRenderer, { isSupportedUIResource } from './Renderer';
import { handleUIAction } from '~/utils';
import { useLocalize } from '~/hooks';
@ -34,6 +34,10 @@ export function MCPUIResource(props: MCPUIResourceProps) {
);
}
if (!isSupportedUIResource(uiResource)) {
return null;
}
try {
return (
<span className="mx-1 inline-block w-full align-middle">
@ -42,7 +46,6 @@ export function MCPUIResource(props: MCPUIResourceProps) {
onUIAction={async (result) => handleUIAction(result, ask)}
htmlProps={{
autoResizeIframe: { width: true, height: true },
sandboxPermissions: 'allow-popups',
}}
/>
</span>

View file

@ -0,0 +1,47 @@
import { UIResourceRenderer as LegacyUIResourceRenderer } from '@mcp-ui/client';
import type { UIResource } from 'librechat-data-provider';
import type { ComponentProps } from 'react';
type LegacyRendererProps = ComponentProps<typeof LegacyUIResourceRenderer>;
type UIResourceRendererProps = Omit<
LegacyRendererProps,
'resource' | 'remoteDomProps' | 'supportedContentTypes'
> & {
resource: UIResource;
};
export function isSupportedUIResource(
resource: UIResource | null | undefined,
): resource is UIResource {
return (
typeof resource?.mimeType === 'string' &&
resource.mimeType.split(';', 1)[0].trim().toLowerCase() === 'text/html'
);
}
/** Restricts legacy MCP-UI rendering to sandboxed inline HTML resources. */
export default function UIResourceRenderer({
resource,
htmlProps,
...props
}: UIResourceRendererProps) {
if (!isSupportedUIResource(resource)) {
return null;
}
const safeResource = { ...resource };
const safeHtmlProps = { ...htmlProps };
delete safeResource.contentType;
safeResource.mimeType = 'text/html';
delete safeHtmlProps.sandboxPermissions;
return (
<LegacyUIResourceRenderer
{...props}
resource={safeResource}
htmlProps={safeHtmlProps}
supportedContentTypes={['rawHtml']}
/>
);
}

View file

@ -1,19 +1,23 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { RecoilRoot } from 'recoil';
import { MCPUIResource } from '../MCPUIResource';
import { render, screen } from '@testing-library/react';
import {
useMessageContext,
useOptionalMessagesConversation,
useOptionalMessagesOperations,
} from '~/Providers';
import { useLocalize } from '~/hooks';
import { MCPUIResource } from '../MCPUIResource';
import { handleUIAction } from '~/utils';
import { useLocalize } from '~/hooks';
// Mock dependencies
jest.mock('~/Providers');
jest.mock('~/hooks');
jest.mock('~/utils');
jest.mock('~/Providers', () => ({
useMessageContext: jest.fn(),
useOptionalMessagesConversation: jest.fn(),
useOptionalMessagesOperations: jest.fn(),
}));
jest.mock('~/hooks', () => ({ useLocalize: jest.fn() }));
jest.mock('~/utils', () => ({ handleUIAction: jest.fn() }));
jest.mock('@mcp-ui/client', () => ({
UIResourceRenderer: ({ resource, onUIAction }: any) => (
@ -141,6 +145,34 @@ describe('MCPUIResource', () => {
expect(screen.getByText('UI resource resource-1 not found')).toBeInTheDocument();
});
it('should omit a referenced resource with an unsupported MIME type', () => {
currentTestMessages = [
{
messageId: 'msg123',
attachments: [
{
type: 'ui_resources',
ui_resources: [
{
resourceId: 'blocked-resource',
uri: 'ui://test/blocked',
mimeType: 'application/vnd.mcp-ui.remote-dom+javascript',
text: 'malicious script',
},
],
},
],
},
];
const { container } = renderWithRecoil(
<MCPUIResource node={{ properties: { resourceId: 'blocked-resource' } }} />,
);
expect(container.firstChild).toBeNull();
expect(screen.queryByTestId('ui-resource-renderer')).not.toBeInTheDocument();
});
it('should resolve resources by resourceId across conversation messages', () => {
mockUseMessageContext.mockReturnValue({ messageId: 'msg-current' } as any);
currentTestMessages = [

View file

@ -0,0 +1,98 @@
import { render, screen } from '@testing-library/react';
import { UIResourceRenderer as LegacyUIResourceRenderer } from '@mcp-ui/client';
import type { UIResource } from 'librechat-data-provider';
import UIResourceRenderer from '../Renderer';
jest.mock('@mcp-ui/client', () => ({
UIResourceRenderer: jest.fn(({ resource }) => (
<div data-testid="legacy-ui-resource" data-mime-type={resource.mimeType} />
)),
}));
const mockLegacyRenderer = LegacyUIResourceRenderer as jest.MockedFunction<
typeof LegacyUIResourceRenderer
>;
describe('UIResourceRenderer', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it.each([
'application/vnd.mcp-ui.remote-dom+javascript',
'application/vnd.mcp-ui.remote-dom',
'text/uri-list',
])('blocks unsafe legacy MIME type %s', (mimeType) => {
const resource: UIResource = {
resourceId: 'unsafe-resource',
uri: 'ui://unsafe',
mimeType,
text: "root.innerHTML='<img src=x onerror=alert(window.origin)>'",
};
const { container } = render(<UIResourceRenderer resource={resource} />);
expect(container).toBeEmptyDOMElement();
expect(mockLegacyRenderer).not.toHaveBeenCalled();
});
it('blocks malformed non-string MIME values', () => {
const resource: UIResource = {
resourceId: 'malformed-resource',
uri: 'ui://malformed',
mimeType: 1 as unknown as string,
text: '<p>Malformed resource</p>',
};
const { container } = render(<UIResourceRenderer resource={resource} />);
expect(container).toBeEmptyDOMElement();
expect(mockLegacyRenderer).not.toHaveBeenCalled();
});
it('forces text/html through the raw HTML renderer without popup permissions', () => {
const resource: UIResource = {
resourceId: 'html-resource',
uri: 'ui://html',
mimeType: 'text/html',
contentType: 'remoteDom',
text: '<p>Safe iframe content</p>',
};
render(
<UIResourceRenderer
resource={resource}
htmlProps={{ sandboxPermissions: 'allow-popups allow-same-origin' }}
/>,
);
expect(screen.getByTestId('legacy-ui-resource')).toBeInTheDocument();
expect(mockLegacyRenderer).toHaveBeenCalledWith(
expect.objectContaining({
resource: expect.not.objectContaining({ contentType: expect.anything() }),
htmlProps: {},
supportedContentTypes: ['rawHtml'],
}),
expect.any(Object),
);
});
it.each(['text/html; charset=utf-8', 'TEXT/HTML'])('normalizes HTML MIME type %s', (mimeType) => {
const resource: UIResource = {
resourceId: 'html-resource',
uri: 'ui://html',
mimeType,
text: '<p>Safe iframe content</p>',
};
render(<UIResourceRenderer resource={resource} />);
expect(mockLegacyRenderer).toHaveBeenCalledWith(
expect.objectContaining({
resource: expect.objectContaining({ mimeType: 'text/html' }),
supportedContentTypes: ['rawHtml'],
}),
expect.any(Object),
);
});
});

10
package-lock.json generated
View file

@ -45238,6 +45238,16 @@
"name": "@librechat/data-schemas",
"version": "0.0.68",
"license": "MIT",
"dependencies": {
"mdast-util-directive": "^3.0.0",
"mdast-util-from-markdown": "^2.0.1",
"mdast-util-gfm": "^3.0.0",
"mdast-util-math": "^3.0.0",
"micromark-extension-directive": "^3.0.1",
"micromark-extension-gfm": "^3.0.0",
"micromark-extension-llm-math": "^3.1.0",
"micromark-util-decode-string": "^2.0.0"
},
"devDependencies": {
"@types/express": "^5.0.0",
"@types/jest": "^29.5.2",

View file

@ -2,6 +2,9 @@ export default {
collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}', '!<rootDir>/node_modules/'],
coveragePathIgnorePatterns: ['/node_modules/', '/dist/'],
testPathIgnorePatterns: ['/node_modules/', '/dist/', '/misc/'],
transformIgnorePatterns: [
'/node_modules/(?!mdast-util-|micromark|decode-named-character-reference|devlop|longest-streak|unist-util-|zwitch|character-(?:entities|reference)|parse-entities|stringify-entities|is-(?:alphanumerical|alphabetical|decimal|hexadecimal)|ccount|markdown-table|escape-string-regexp)',
],
coverageReporters: ['text', 'cobertura'],
testResultsProcessor: 'jest-junit',
moduleNameMapper: {

View file

@ -52,6 +52,16 @@
"url": "https://github.com/danny-avila/LibreChat/issues"
},
"homepage": "https://librechat.ai",
"dependencies": {
"mdast-util-directive": "^3.0.0",
"mdast-util-from-markdown": "^2.0.1",
"mdast-util-gfm": "^3.0.0",
"mdast-util-math": "^3.0.0",
"micromark-extension-directive": "^3.0.1",
"micromark-extension-gfm": "^3.0.0",
"micromark-extension-llm-math": "^3.1.0",
"micromark-util-decode-string": "^2.0.0"
},
"devDependencies": {
"@types/express": "^5.0.0",
"@types/jest": "^29.5.2",

View file

@ -1,7 +1,7 @@
import { nanoid } from 'nanoid';
import mongoose from 'mongoose';
import { Constants } from 'librechat-data-provider';
import { MongoMemoryServer } from 'mongodb-memory-server';
import { Constants, ContentTypes, Tools } from 'librechat-data-provider';
import type { SchemaWithMeiliMethods } from '~/models/plugins/mongoMeili';
import type * as t from '~/types';
import { createShareMethods, anonymizeSharedContent, type ShareMethods } from './share';
@ -521,6 +521,133 @@ describe('Share Methods', () => {
).toBe(result?.conversationId);
});
test('strips MCP-UI attachments from public shared messages', async () => {
const userId = new mongoose.Types.ObjectId().toString();
const conversationId = `conv_${nanoid()}`;
const shareId = `share_${nanoid()}`;
const message = await Message.create({
messageId: `msg_${nanoid()}`,
conversationId,
user: userId,
text: '\\ui{malicious}',
isCreatedByUser: false,
content: [
{ type: ContentTypes.TEXT, text: 'Before \\ui{malicious} after' },
{ type: ContentTypes.TEXT, text: '`\\ui{literal}`' },
{
type: ContentTypes.TEXT,
text: {
value: 'Object \\ui{malicious} value',
annotations: [{ type: 'citation' }],
},
},
{
type: ContentTypes.TOOL_CALL,
tool_call: {
subagent_content: [
{ type: ContentTypes.TEXT, text: 'Nested \\ui{malicious} content' },
],
},
},
],
attachments: [
{
type: Tools.ui_resources,
[Tools.ui_resources]: [
{
resourceId: 'malicious',
mimeType: 'application/vnd.mcp-ui.remote-dom+javascript',
text: "root.innerHTML='<img src=x onerror=alert(window.origin)>'",
},
],
},
{ type: Tools.web_search, [Tools.web_search]: { results: [] } },
],
});
await SharedLink.create({
shareId,
conversationId,
user: userId,
messages: [message._id],
});
const result = await shareMethods.getSharedMessages(shareId);
expect(result?.messages[0].attachments).toHaveLength(1);
expect(result?.messages[0].attachments?.[0].type).toBe(Tools.web_search);
expect(result?.messages[0].text).toBe('');
expect(result?.messages[0].content).toEqual([
{ type: ContentTypes.TEXT, text: 'Before after' },
{ type: ContentTypes.TEXT, text: '`\\ui{literal}`' },
{
type: ContentTypes.TEXT,
text: { value: 'Object value', annotations: [{ type: 'citation' }] },
},
{
type: ContentTypes.TOOL_CALL,
tool_call: {
subagent_content: [{ type: ContentTypes.TEXT, text: 'Nested content' }],
},
},
]);
});
test.each([true, null])(
'matches text and content renderers for author flag %s in public shares',
async (authorFlag) => {
const userId = new mongoose.Types.ObjectId().toString();
const conversationId = `conv_${nanoid()}`;
const shareId = `share_${nanoid()}`;
const message = await Message.create({
messageId: `msg_${nanoid()}`,
conversationId,
user: userId,
text: 'Example: \\ui{literal}',
isCreatedByUser: authorFlag,
content: [
{ type: ContentTypes.TEXT, text: 'Part: \\ui{literal}' },
{
type: ContentTypes.TOOL_CALL,
tool_call: {
name: Constants.SUBAGENT,
output: 'Legacy \\ui{nested} output',
subagent_content: [{ type: ContentTypes.TEXT, text: 'Nested \\ui{nested} text' }],
},
},
],
attachments: [{ type: Tools.ui_resources, [Tools.ui_resources]: [] }],
});
await SharedLink.create({
shareId,
conversationId,
user: userId,
messages: [message._id],
});
const result = await shareMethods.getSharedMessages(shareId);
expect(result?.messages[0].text).toBe('Example: \\ui{literal}');
expect(result?.messages[0].content).toEqual([
{
type: ContentTypes.TEXT,
text: authorFlag === true ? 'Part: \\ui{literal}' : 'Part: ',
},
{
type: ContentTypes.TOOL_CALL,
tool_call: {
name: Constants.SUBAGENT,
output: 'Legacy output',
subagent_content: [{ type: ContentTypes.TEXT, text: 'Nested text' }],
},
},
]);
expect(result?.messages[0].attachments).toBeUndefined();
},
);
test('strips storage-internal fields while preserving shared render data', async () => {
const userId = new mongoose.Types.ObjectId().toString();
const conversationId = `conv_${nanoid()}`;
@ -741,7 +868,7 @@ describe('Share Methods', () => {
expect(share?.fileSnapshots?.map((snapshot) => snapshot.file_id)).toContain('steer-file-2');
});
test('leaves non-steer content untouched (same array reference when no steer part)', () => {
test('leaves safe non-steer content untouched (same array reference)', () => {
const plainContent = [
{ type: 'text', text: 'no steers here' },
{ type: 'tool_call', tool_call: { id: 'call_1' } },

View file

@ -1,9 +1,13 @@
import { nanoid } from 'nanoid';
import { Types } from 'mongoose';
import { Constants, ContentTypes, FileSources } from 'librechat-data-provider';
import { Constants, ContentTypes, FileSources, Tools } from 'librechat-data-provider';
import type { FilterQuery, Model } from 'mongoose';
import type { SchemaWithMeiliMethods } from '~/models/plugins/mongoMeili';
import type * as t from '~/types';
import {
sanitizeUIResourceContent,
stripMessageUIResourceMarkers,
} from '~/utils/stripUIResourceMarkers';
import { activeExpirationFilter } from '~/utils/retention';
import { isValidObjectIdString } from '~/utils/objectId';
import logger from '~/config/winston';
@ -118,6 +122,13 @@ function sanitizeSharedFiles(files: unknown): t.SharedFile[] | undefined {
return sanitized.length > 0 ? sanitized : undefined;
}
function sanitizeSharedAttachments(attachments: unknown): t.SharedFile[] | undefined {
const sanitized = sanitizeSharedFiles(attachments)?.filter(
(attachment) => attachment.type !== Tools.ui_resources,
);
return sanitized && sanitized.length > 0 ? sanitized : undefined;
}
/**
* Sources backed by a durable stored object that the share-scoped routes can
* stream with only `storageKey`/`filepath` + the request. Sources requiring
@ -379,6 +390,7 @@ export function anonymizeSharedContent(
shareId: string;
snapshotIds: Set<string>;
includeFiles: boolean;
sanitizeUIResourceMarkers?: boolean;
},
): unknown[] | undefined {
if (!Array.isArray(content)) {
@ -386,8 +398,13 @@ export function anonymizeSharedContent(
}
let result: unknown[] | null = null;
const sanitized = sanitizeUIResourceContent(content, params.sanitizeUIResourceMarkers === true);
if (sanitized !== content) {
result = sanitized as unknown[];
}
for (let i = 0; i < content.length; i++) {
const part = content[i];
const part = result?.[i] ?? content[i];
if (!isSteerPartWithFiles(part)) {
continue;
}
@ -405,9 +422,7 @@ export function anonymizeSharedContent(
),
)
: undefined;
if (result == null) {
result = [...content];
}
result ??= [...content];
result[i] = files ? { ...rest, files } : rest;
}
return result ?? content;
@ -456,7 +471,7 @@ function anonymizeMessages(
// When files are not shared for this link, omit files/attachments entirely so
// viewers can't load them through the owner's original (e.g. static) paths.
const attachments = includeFiles
? sanitizeSharedFiles(message.attachments)?.map((attachment) =>
? sanitizeSharedAttachments(message.attachments)?.map((attachment) =>
applyShareFileRoute(
{
...attachment,
@ -492,13 +507,17 @@ function anonymizeMessages(
anonymizeMessageId(message.parentMessageId || ''),
conversationId: newConvoId,
sender: message.sender,
text: message.text,
text:
message.isCreatedByUser === false
? stripMessageUIResourceMarkers(message.text, message.error)
: message.text,
content: anonymizeSharedContent(message.content, {
newConvoId,
newMessageId,
shareId,
snapshotIds,
includeFiles,
sanitizeUIResourceMarkers: message.isCreatedByUser !== true,
}),
...(message.iconURL && { iconURL: message.iconURL }),
...(model && { model }),

View file

@ -6,3 +6,4 @@ export { tenantSafeBulkWrite } from './tenantBulkWrite';
export * from './transactions';
export * from './objectId';
export * from './yaml';
export * from './stripUIResourceMarkers';

View file

@ -0,0 +1,255 @@
import { Constants, ContentTypes } from 'librechat-data-provider';
import {
sanitizeUIResourceContent,
stripMessageUIResourceMarkers,
stripUIResourceMarkers,
} from './stripUIResourceMarkers';
describe('stripUIResourceMarkers', () => {
it('removes markers from renderable text while preserving non-text Markdown nodes', () => {
const markdown = [
'Before \\ui{rendered} after',
'`\\ui{inline}`',
'```text',
'\\ui{fenced}',
'```',
'<div>\\ui{html}</div>',
'$$\\ui{inline-math}$$',
'$$',
'\\ui{display-math}',
'$$',
].join('\n');
expect(stripUIResourceMarkers(markdown)).toBe(markdown.replace('\\ui{rendered}', ''));
});
it('preserves markers inside inline and display math nodes', () => {
const markdown = ['$$\\ui{inline-math}$$', '', '$$', '\\ui{display-math}', '$$'].join('\n');
expect(stripUIResourceMarkers(markdown)).toBe(markdown);
expect(stripUIResourceMarkers('$\\ui{rendered}$')).toBe('$$');
});
it('preserves directive attributes that the renderer does not visit as text', () => {
const markdown = '::artifact{title="\\ui{example}"}';
expect(stripUIResourceMarkers(markdown)).toBe(markdown);
});
it('preserves text directive labels replaced before MCP marker rendering', () => {
const markdown = ':note[\\ui{directive}] outside \\ui{outside}';
expect(stripUIResourceMarkers(markdown)).toBe(':note[\\ui{directive}] outside ');
});
it('removes markers after Markdown escapes and character references are decoded', () => {
const markdown = [
'Encoded &#92;ui{backslash}',
'Encoded \\ui&#123;braces&#125;',
'Escaped \\ui\\{braces\\}',
].join('\n');
expect(stripUIResourceMarkers(markdown)).toBe(['Encoded ', 'Encoded ', 'Escaped '].join('\n'));
});
it('removes markers formed by citation cleanup before MCP marker rendering', () => {
const markdown = [
'Actual \\u\ue206i{actual}',
'Literal \\u\\ue206i{literal}',
'Entity \\u&#xE206;i{entity}',
'Mixed \\u&#92;ue206i{mixed}',
].join('\n');
expect(stripUIResourceMarkers(markdown)).toBe(
['Actual ', 'Literal ', 'Entity ', 'Mixed '].join('\n'),
);
});
it('preserves markers inside composite citations consumed before MCP marker rendering', () => {
const markdown = '\\ue200\\ue202turn0search0 \\ui{citation}\\ue201 outside \\ui{outside}';
expect(stripUIResourceMarkers(markdown)).toBe(
'\\ue200\\ue202turn0search0 \\ui{citation}\\ue201 outside ',
);
expect(stripUIResourceMarkers('\\ue200 invalid \\ui{rendered}\\ue201')).toBe(
'\\ue200 invalid \\ue201',
);
expect(stripUIResourceMarkers('\\ue200\n\\ue202turn0search0 \\ui{rendered}\\ue201')).toBe(
'\\ue200\n\\ue202turn0search0 \\ue201',
);
});
it('preserves highlighted citation text-node boundaries before MCP marker rendering', () => {
const acrossBoundary = '\\u\\ue203i{id}\\ue204';
expect(stripUIResourceMarkers(acrossBoundary)).toBe(acrossBoundary);
expect(stripUIResourceMarkers('\\ue203\\ui{inside}\\ue204')).toBe('\\ue203\\ue204');
expect(
stripUIResourceMarkers('\\ue203 text \\ue200\\ue202turn0search0 \\ui{nested}\\ue201\\ue204'),
).toBe('\\ue203 text \\ue200\\ue202turn0search0 \\ue201\\ue204');
});
it('uses the earliest citation match when highlight and composite ranges cross', () => {
const markdown = '\\ue203 text \\ue200\\ue202turn0search0 \\ui{id}\\ue204 tail \\ue201';
expect(stripUIResourceMarkers(markdown)).toBe(
'\\ue203 text \\ue200\\ue202turn0search0 \\ue204 tail \\ue201',
);
});
it('preserves text boundaries around invalid composite citations', () => {
const markdown = '\\u\\ue200\\ue201i{id}';
expect(stripUIResourceMarkers(markdown)).toBe(markdown);
});
it('handles many unmatched citation openers in linear time', () => {
const markdown = `${'\\ue203'.repeat(16_000)}\\ui{rendered}`;
expect(stripUIResourceMarkers(markdown)).toBe('\\ue203'.repeat(16_000));
});
it('preserves markers in message text that bypasses Markdown rendering', () => {
expect(stripMessageUIResourceMarkers('Error \\ui{literal}', true)).toBe('Error \\ui{literal}');
expect(
stripMessageUIResourceMarkers(':::thinking Hidden \\ui{hidden} ::: Visible \\ui{visible}'),
).toBe(':::thinking Hidden \\ui{hidden} ::: Visible ');
expect(stripMessageUIResourceMarkers('\\u:::thinking Hidden :::i{formed}')).toBe(
':::thinking Hidden :::',
);
expect(stripMessageUIResourceMarkers(':::thinking hidden ::: \\ui{id}')).toBe(
':::thinking hidden ::: ',
);
});
it('handles paragraph continuations and container code according to CommonMark', () => {
const markdown = [
'intro',
' \\ui{paragraph}',
'',
' \\ui{indented-code}',
'> ```',
'> \\ui{quote-code}',
'outside \\ui{outside}',
].join('\n');
expect(stripUIResourceMarkers(markdown)).toBe(
markdown.replace('\\ui{paragraph}', '').replace('\\ui{outside}', ''),
);
});
it('maps markers across CRLF paragraph continuations', () => {
const markdown = 'intro\r\n \\ui{paragraph}\r\nnext \\ui{next}';
expect(stripUIResourceMarkers(markdown)).toBe('intro\r\n \r\nnext ');
});
it('maps markers across blockquote paragraph prefixes', () => {
const markdown = '> intro\n> \\ui{paragraph}\n>\n> \\ui{code}';
expect(stripUIResourceMarkers(markdown)).toBe(markdown.replace('\\ui{paragraph}', ''));
});
it('handles escaped blockquote content and CommonMark replacement characters', () => {
expect(stripUIResourceMarkers('> intro\n> \\> \\ui{paragraph}')).toBe('> intro\n> \\> ');
expect(stripUIResourceMarkers('prefix\0 \\ui{paragraph}')).toBe('prefix\0 ');
});
it('handles long literal text without per-character source-span objects', () => {
const markdown = `\\not-a-marker ${'a'.repeat(100_000)} & plain text`;
expect(stripUIResourceMarkers(markdown)).toBe(markdown);
});
it('maps many encoded markers with a monotonic source-segment cursor', () => {
const markdown = Array.from({ length: 1_000 }, (_, index) => `&#92;ui{id${index}}`).join(' ');
expect(stripUIResourceMarkers(markdown)).toBe(' '.repeat(999));
});
it('walks deeply nested Markdown without recursive traversal', () => {
const prefix = '> '.repeat(500);
expect(stripUIResourceMarkers(`${prefix}\\ui{deep}`)).toBe(prefix);
});
it('recursively sanitizes TextData and subagent content while preserving annotations', () => {
const content = [
{
type: 'tool_call',
tool_call: {
subagent_content: [
{
type: ContentTypes.TEXT,
text: {
value: 'Before \\ui{nested} after',
annotations: [{ type: 'citation' }],
},
},
],
},
},
];
expect(sanitizeUIResourceContent(content)).toEqual([
{
type: 'tool_call',
tool_call: {
subagent_content: [
{
type: ContentTypes.TEXT,
text: { value: 'Before after', annotations: [{ type: 'citation' }] },
},
],
},
},
]);
});
it('sanitizes deeply nested subagent content without recursive traversal', () => {
const depth = 10_000;
let nestedContent: unknown[] = [{ type: ContentTypes.TEXT, text: 'Deep \\ui{deep} content' }];
for (let i = 0; i < depth; i++) {
nestedContent = [
{
type: ContentTypes.TOOL_CALL,
tool_call: { subagent_content: nestedContent },
},
];
}
let cursor = sanitizeUIResourceContent(nestedContent) as unknown[];
for (let i = 0; i < depth; i++) {
const part = cursor[0] as { tool_call: { subagent_content: unknown[] } };
cursor = part.tool_call.subagent_content;
}
expect(cursor).toEqual([{ type: ContentTypes.TEXT, text: 'Deep content' }]);
});
it('preserves top-level user text while sanitizing assistant-rendered subagent fields', () => {
const content = [
{ type: ContentTypes.TEXT, text: 'User example \\ui{literal}' },
{
type: ContentTypes.TOOL_CALL,
tool_call: {
name: Constants.SUBAGENT,
output: 'Legacy \\ui{legacy} output',
subagent_content: [
{ type: ContentTypes.TEXT, text: 'Nested \\ui{nested} content' },
{
type: ContentTypes.TOOL_CALL,
tool_call: {
name: Constants.SUBAGENT,
output: 'Deep \\ui{deep} output',
},
},
],
},
},
];
expect(sanitizeUIResourceContent(content, false)).toEqual([
{ type: ContentTypes.TEXT, text: 'User example \\ui{literal}' },
{
type: ContentTypes.TOOL_CALL,
tool_call: {
name: Constants.SUBAGENT,
output: 'Legacy output',
subagent_content: [
{ type: ContentTypes.TEXT, text: 'Nested content' },
{
type: ContentTypes.TOOL_CALL,
tool_call: { name: Constants.SUBAGENT, output: 'Deep output' },
},
],
},
},
]);
});
});

View file

@ -0,0 +1,599 @@
import { gfm } from 'micromark-extension-gfm';
import { gfmFromMarkdown } from 'mdast-util-gfm';
import { mathFromMarkdown } from 'mdast-util-math';
import { math } from 'micromark-extension-llm-math';
import { fromMarkdown } from 'mdast-util-from-markdown';
import { directive } from 'micromark-extension-directive';
import { decodeString } from 'micromark-util-decode-string';
import { directiveFromMarkdown } from 'mdast-util-directive';
import { Constants, ContentTypes } from 'librechat-data-provider';
const UI_RESOURCE_PATTERN = /\\ui\{[\w]+(?:,[\w]+)*\}/g;
const CITATION_CLEANUP = /\\ue20[0-46]|[\ue200-\ue204\ue206]/g;
const STANDALONE_SUFFIX = /turn(\d+)(search|image|news|video|ref|file)(\d+)/y;
const MARKDOWN_ESCAPE_OR_REFERENCE = /\\(.)|&(#(?:\d{1,7}|[xX][\dA-Fa-f]{1,6})|[\dA-Za-z]{1,31});/g;
const TEXT_BOUNDARY = '\0';
type MarkdownNode = {
type: string;
position?: { start: { offset?: number }; end: { offset?: number } };
children?: MarkdownNode[];
};
type SourceSegment = {
decodedStart: number;
decodedEnd: number;
sourceStart: number;
sourceEnd: number;
literal: boolean;
};
type CitationToken = {
code: number;
start: number;
end: number;
line: number;
literal: boolean;
};
type CitationMatch = { start: number; end: number };
type CitationOutputSegment =
| { kind: 'text'; intervals: Array<[number, number]> }
| { kind: 'nontext' };
function collectCitationTokens(value: string) {
const tokens: CitationToken[] = [];
const allStandalone: CitationMatch[] = [];
const standalone: CitationMatch[] = [];
let lastCompositeOpen = -1;
let lastCompositeClose = -1;
let line = 0;
for (let index = 0; index < value.length; ) {
let code = -1;
let end = index + 1;
let literal = false;
const characterCode = value.charCodeAt(index);
if (characterCode >= 0xe200 && characterCode <= 0xe206 && characterCode !== 0xe205) {
code = characterCode - 0xe200;
} else if (
value.charCodeAt(index) === 92 &&
value.startsWith('ue20', index + 1) &&
index + 5 < value.length
) {
const digit = value.charCodeAt(index + 5) - 48;
if (digit >= 0 && digit <= 6 && digit !== 5) {
code = digit;
end = index + 6;
literal = true;
}
}
if (code < 0) {
if (
characterCode === 10 ||
characterCode === 13 ||
characterCode === 0x2028 ||
characterCode === 0x2029
) {
line++;
}
index++;
continue;
}
const token = { code, start: index, end, line, literal };
tokens.push(token);
if (code === 2) {
STANDALONE_SUFFIX.lastIndex = end;
const suffix = STANDALONE_SUFFIX.exec(value);
if (suffix) {
const citation = { start: index, end: STANDALONE_SUFFIX.lastIndex };
allStandalone.push(citation);
if (lastCompositeOpen === -1 || lastCompositeClose > lastCompositeOpen) {
standalone.push(citation);
}
}
} else if (code === 0) {
lastCompositeOpen = index;
} else if (code === 1) {
lastCompositeClose = index;
}
index = end;
}
return { tokens, allStandalone, standalone };
}
function pairCitationRanges(tokens: CitationToken[], openCode: number, closeCode: number) {
const openers = tokens.filter((token) => token.code === openCode);
const closers = tokens.filter((token) => token.code === closeCode);
const ranges: CitationMatch[] = [];
let closeIndex = 0;
for (const opener of openers) {
while (
closers[closeIndex] &&
(closers[closeIndex].line < opener.line ||
(closers[closeIndex].line === opener.line && closers[closeIndex].start < opener.end))
) {
closeIndex++;
}
const closer = closers[closeIndex];
if (closer?.line === opener.line) {
ranges.push({ start: opener.start, end: closer.end });
}
}
return ranges;
}
/** Model the citation plugin's emitted text nodes without its unbounded wildcard regexes. */
function applyCitationTextBoundaries(value: string, sourceSegments: SourceSegment[]) {
const { tokens, allStandalone, standalone } = collectCitationTokens(value);
const highlighted = pairCitationRanges(tokens, 3, 4);
const composite = pairCitationRanges(tokens, 0, 1);
const output: CitationOutputSegment[] = [];
let tokenIndex = 0;
const addText = (start: number, end: number, highlightedText = false) => {
const intervals: Array<[number, number]> = [];
let cursor = start;
while (tokens[tokenIndex]?.end <= start) {
tokenIndex++;
}
while (tokens[tokenIndex]?.start < end) {
const token = tokens[tokenIndex++];
const remove = highlightedText
? token.literal && (token.code === 3 || token.code === 4)
: true;
if (remove) {
if (cursor < token.start) {
intervals.push([cursor, token.start]);
}
cursor = token.end;
}
}
if (cursor < end) {
intervals.push([cursor, end]);
}
if (intervals.length > 0 || highlightedText) {
output.push({ kind: 'text', intervals });
}
};
let highlightedIndex = 0;
let compositeIndex = 0;
let standaloneIndex = 0;
let compositeCitationIndex = 0;
let position = 0;
while (position < value.length) {
while (highlighted[highlightedIndex]?.start < position) {
highlightedIndex++;
}
while (composite[compositeIndex]?.start < position) {
compositeIndex++;
}
while (standalone[standaloneIndex]?.start < position) {
standaloneIndex++;
}
const highlightedMatch = highlighted[highlightedIndex];
const compositeMatch = composite[compositeIndex];
const standaloneMatch = standalone[standaloneIndex];
let type: 'highlighted' | 'composite' | 'standalone' | undefined;
let next = highlightedMatch;
if (next) {
type = 'highlighted';
}
if (compositeMatch && (!next || compositeMatch.start < next.start)) {
type = 'composite';
next = compositeMatch;
}
if (standaloneMatch && (!next || standaloneMatch.start < next.start)) {
type = 'standalone';
next = standaloneMatch;
}
if (!next || !type) {
addText(position, value.length);
break;
}
if (next.start > position) {
addText(position, next.start);
}
if (type === 'highlighted') {
addText(next.start, next.end, true);
highlightedIndex++;
} else if (type === 'standalone') {
output.push({ kind: 'nontext' });
standaloneIndex++;
} else {
while (allStandalone[compositeCitationIndex]?.start < next.start) {
compositeCitationIndex++;
}
const citation = allStandalone[compositeCitationIndex];
if (citation && citation.end <= next.end) {
output.push({ kind: 'nontext' });
}
compositeIndex++;
}
position = next.end;
}
if (output.length === 0) {
tokenIndex = 0;
addText(0, value.length);
}
let transformedValue = '';
const transformedSegments: SourceSegment[] = [];
let sourceSegmentIndex = 0;
const appendInterval = ([start, end]: [number, number]) => {
while (sourceSegments[sourceSegmentIndex]?.decodedEnd <= start) {
sourceSegmentIndex++;
}
let index = sourceSegmentIndex;
while (sourceSegments[index]?.decodedStart < end) {
const segment = sourceSegments[index];
const sliceStart = Math.max(start, segment.decodedStart);
const sliceEnd = Math.min(end, segment.decodedEnd);
if (sliceStart < sliceEnd) {
const decodedStart = transformedValue.length;
transformedValue += value.slice(sliceStart, sliceEnd);
const sourceStart = segment.literal
? segment.sourceStart + sliceStart - segment.decodedStart
: segment.sourceStart;
const sourceEnd = segment.literal
? segment.sourceStart + sliceEnd - segment.decodedStart
: segment.sourceEnd;
const previous = transformedSegments[transformedSegments.length - 1];
if (
segment.literal &&
previous?.literal &&
previous.decodedEnd === decodedStart &&
previous.sourceEnd === sourceStart
) {
previous.decodedEnd = transformedValue.length;
previous.sourceEnd = sourceEnd;
} else {
transformedSegments.push({
decodedStart,
decodedEnd: transformedValue.length,
sourceStart,
sourceEnd,
literal: segment.literal,
});
}
}
index++;
}
sourceSegmentIndex = Math.max(sourceSegmentIndex, index - 1);
};
output.forEach((segment, index) => {
if (index > 0) {
transformedValue += TEXT_BOUNDARY;
}
if (segment.kind === 'text') {
segment.intervals.forEach(appendInterval);
}
});
return { value: transformedValue, segments: transformedSegments };
}
function decodeTextWithSourceSpans(source: string) {
let value = '';
const segments: SourceSegment[] = [];
let cursor = 0;
MARKDOWN_ESCAPE_OR_REFERENCE.lastIndex = 0;
const appendLiteral = (start: number, end: number) => {
if (start === end) {
return;
}
const decodedStart = value.length;
value += source.slice(start, end);
const previous = segments[segments.length - 1];
if (previous?.literal && previous.decodedEnd === decodedStart && previous.sourceEnd === start) {
previous.decodedEnd = value.length;
previous.sourceEnd = end;
return;
}
segments.push({
decodedStart,
decodedEnd: value.length,
sourceStart: start,
sourceEnd: end,
literal: true,
});
};
let match: RegExpExecArray | null;
while ((match = MARKDOWN_ESCAPE_OR_REFERENCE.exec(source)) != null) {
appendLiteral(cursor, match.index);
const decoded = decodeString(match[0]);
if (decoded === match[0]) {
appendLiteral(match.index, MARKDOWN_ESCAPE_OR_REFERENCE.lastIndex);
} else {
const decodedStart = value.length;
value += decoded;
segments.push({
decodedStart,
decodedEnd: value.length,
sourceStart: match.index,
sourceEnd: MARKDOWN_ESCAPE_OR_REFERENCE.lastIndex,
literal: false,
});
}
cursor = MARKDOWN_ESCAPE_OR_REFERENCE.lastIndex;
}
appendLiteral(cursor, source.length);
return applyCitationTextBoundaries(value, segments);
}
function mapDecodedRange(
segments: SourceSegment[],
decodedStart: number,
decodedEnd: number,
fromIndex: number,
): { range: [number, number]; segmentIndex: number } | null {
let firstIndex = fromIndex;
while (segments[firstIndex]?.decodedEnd <= decodedStart) {
firstIndex++;
}
const first = segments[firstIndex];
if (!first || decodedStart < first.decodedStart) {
return null;
}
let lastIndex = firstIndex;
while (segments[lastIndex]?.decodedEnd < decodedEnd) {
lastIndex++;
}
const last = segments[lastIndex];
if (!last || decodedEnd <= last.decodedStart) {
return null;
}
const sourceStart = first.literal
? first.sourceStart + decodedStart - first.decodedStart
: first.sourceStart;
const sourceEnd = last.literal
? last.sourceStart + decodedEnd - last.decodedStart
: last.sourceEnd;
return { range: [sourceStart, sourceEnd], segmentIndex: lastIndex };
}
function collectMarkerRanges(root: MarkdownNode, source: string, ranges: Array<[number, number]>) {
const stack = [root];
while (stack.length > 0) {
const node = stack.pop() as MarkdownNode;
const start = node.position?.start.offset;
const end = node.position?.end.offset;
if (node.type === 'text' && start != null && end != null) {
const decoded = decodeTextWithSourceSpans(source.slice(start, end));
UI_RESOURCE_PATTERN.lastIndex = 0;
let segmentCursor = 0;
let match: RegExpExecArray | null;
while ((match = UI_RESOURCE_PATTERN.exec(decoded.value)) != null) {
const mapped = mapDecodedRange(
decoded.segments,
match.index,
match.index + match[0].length,
segmentCursor,
);
if (mapped) {
segmentCursor = mapped.segmentIndex;
ranges.push([start + mapped.range[0], start + mapped.range[1]]);
}
}
}
if (node.type === 'textDirective') {
continue;
}
if (node.children) {
for (let i = node.children.length - 1; i >= 0; i--) {
stack.push(node.children[i]);
}
}
}
}
function findUIResourceMarkerRanges(text: string): Array<[number, number]> {
if (
(!text.includes('\\') && !text.includes('&')) ||
!decodeString(text).replace(CITATION_CLEANUP, '').includes('\\ui{')
) {
return [];
}
const ranges: Array<[number, number]> = [];
collectMarkerRanges(
fromMarkdown(text, {
extensions: [gfm(), directive(), math({ singleDollarTextMath: false })],
mdastExtensions: [gfmFromMarkdown(), directiveFromMarkdown(), mathFromMarkdown()],
}) as unknown as MarkdownNode,
text,
ranges,
);
return ranges;
}
function removeSourceRanges(text: string, ranges: Array<[number, number]>) {
let result = '';
let cursor = 0;
for (const [start, end] of ranges) {
result += text.slice(cursor, start);
cursor = end;
}
return result + text.slice(cursor);
}
/** Remove MCP-UI markers only from Markdown text nodes visited by the renderer plugin. */
export function stripUIResourceMarkers(text: string): string;
export function stripUIResourceMarkers(text: undefined): undefined;
export function stripUIResourceMarkers(text: string | undefined): string | undefined;
export function stripUIResourceMarkers(text: string | undefined): string | undefined {
if (text == null) {
return text;
}
const ranges = findUIResourceMarkerRanges(text);
return ranges.length === 0 ? text : removeSourceRanges(text, ranges);
}
/** Sanitize only the portion of a legacy message that the client renders as Markdown. */
export function stripMessageUIResourceMarkers(
text: string | undefined,
error?: unknown,
): string | undefined {
if (text == null || error) {
return text;
}
const thinkingMatch = /:::thinking[\s\S]*?:::/.exec(text);
if (!thinkingMatch) {
return stripUIResourceMarkers(text);
}
const start = thinkingMatch.index;
const end = start + thinkingMatch[0].length;
const regularContent = text.slice(0, start) + text.slice(end);
const renderedStart = regularContent.length - regularContent.trimStart().length;
const renderedEnd = regularContent.trimEnd().length;
const regularRanges = findUIResourceMarkerRanges(
regularContent.slice(renderedStart, renderedEnd),
);
if (regularRanges.length === 0) {
return text;
}
const sourceRanges: Array<[number, number]> = [];
const blockLength = end - start;
for (const renderedRange of regularRanges) {
const rangeStart = renderedRange[0] + renderedStart;
const rangeEnd = renderedRange[1] + renderedStart;
if (rangeEnd <= start) {
sourceRanges.push([rangeStart, rangeEnd]);
} else if (rangeStart >= start) {
sourceRanges.push([rangeStart + blockLength, rangeEnd + blockLength]);
} else {
sourceRanges.push([rangeStart, start], [end, rangeEnd + blockLength]);
}
}
return removeSourceRanges(text, sourceRanges);
}
function sanitizeTextPart(part: Record<string, unknown>): unknown {
if (typeof part.text === 'string') {
const text = stripUIResourceMarkers(part.text);
return text === part.text ? part : { ...part, text };
}
if (part.text != null && typeof part.text === 'object') {
const textData = part.text as Record<string, unknown>;
if (typeof textData.value === 'string') {
const value = stripUIResourceMarkers(textData.value);
return value === textData.value ? part : { ...part, text: { ...textData, value } };
}
}
return part;
}
type ContentFrame = {
content: unknown[];
sanitizeTextParts: boolean;
index: number;
result: unknown[] | null;
onComplete: (content: unknown[]) => void;
};
function updateFramePart(
frame: ContentFrame,
index: number,
originalPart: unknown,
sanitizedPart: unknown,
) {
if (sanitizedPart === originalPart) {
return;
}
frame.result ??= [...frame.content];
frame.result[index] = sanitizedPart;
}
/** Sanitize assistant text parts, including arbitrarily nested persisted subagent content. */
export function sanitizeUIResourceContent(content: unknown, sanitizeTextParts = true): unknown {
if (!Array.isArray(content)) {
return content;
}
let sanitizedContent = content;
const stack: ContentFrame[] = [
{
content,
sanitizeTextParts,
index: 0,
result: null,
onComplete: (result) => {
sanitizedContent = result;
},
},
];
while (stack.length > 0) {
const frame = stack[stack.length - 1];
if (frame.index >= frame.content.length) {
stack.pop();
frame.onComplete(frame.result ?? frame.content);
continue;
}
const index = frame.index++;
const part = frame.content[index];
if (part == null || typeof part !== 'object') {
continue;
}
let sanitizedPart: unknown = part;
const record = part as Record<string, unknown>;
if (frame.sanitizeTextParts && record.type === ContentTypes.TEXT) {
sanitizedPart = sanitizeTextPart(record);
}
const current = sanitizedPart as Record<string, unknown>;
if (current.tool_call == null || typeof current.tool_call !== 'object') {
updateFramePart(frame, index, part, sanitizedPart);
continue;
}
const toolCall = current.tool_call as Record<string, unknown>;
let sanitizedToolCall = toolCall;
if (toolCall.name === Constants.SUBAGENT && typeof toolCall.output === 'string') {
const output = stripUIResourceMarkers(toolCall.output);
if (output !== toolCall.output) {
sanitizedToolCall = { ...sanitizedToolCall, output };
}
}
if (Array.isArray(toolCall.subagent_content)) {
const originalSubagentContent = toolCall.subagent_content;
stack.push({
content: originalSubagentContent,
sanitizeTextParts: true,
index: 0,
result: null,
onComplete: (subagentContent) => {
if (subagentContent !== originalSubagentContent) {
sanitizedToolCall = { ...sanitizedToolCall, subagent_content: subagentContent };
}
if (sanitizedToolCall !== toolCall) {
sanitizedPart = { ...current, tool_call: sanitizedToolCall };
}
updateFramePart(frame, index, part, sanitizedPart);
},
});
continue;
}
if (sanitizedToolCall !== toolCall) {
sanitizedPart = { ...current, tool_call: sanitizedToolCall };
}
updateFramePart(frame, index, part, sanitizedPart);
}
return sanitizedContent;
}

View file

@ -1,6 +1,11 @@
import path from 'node:path';
import { defineConfig } from 'tsdown';
const isMarkdownParserDependency = (id) =>
/^(?:mdast-util-|micromark(?:-|$)|decode-named-character-reference$|devlop$|longest-streak$|unist-util-|zwitch$|character-(?:entities|reference)(?:-|$)|parse-entities$|stringify-entities$|is-(?:alphanumerical|alphabetical|decimal|hexadecimal)$|ccount$|markdown-table$|escape-string-regexp$)/.test(
id,
);
export default defineConfig({
entry: ['src/index.ts', 'src/admin/capabilities.ts'],
format: ['esm', 'cjs'],
@ -10,13 +15,15 @@ export default defineConfig({
sourcemap: true,
// Warn on module cycles at build time; CI enforces via config/circular-deps.mjs.
checks: { circularDependency: true },
// Externalize all third-party deps (consumers provide the peers); bundle only `dotenv`
// so the package stays self-contained for its env-loading side effect, matching the
// prior Rollup build. `neverBundle` is the 0.22 replacement for the deprecated `external`.
// Externalize third-party deps consumers provide, while bundling `dotenv` for its
// env-loading side effect and the ESM-only Markdown parser for CommonJS consumers.
// `neverBundle` is the 0.22 replacement for the deprecated `external`.
deps: {
alwaysBundle: isMarkdownParserDependency,
neverBundle: (id) =>
id !== 'dotenv' &&
!id.startsWith('dotenv/') &&
!isMarkdownParserDependency(id) &&
!id.startsWith('.') &&
!id.startsWith('~') &&
!path.isAbsolute(id),