mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-27 04:07:05 +00:00
🧬 chore: Align LibreChat With Agents LangChain Upgrade (#12922)
* 🔧 chore: Update dependencies in package-lock.json and package.json - Bump version of @librechat/agents to 3.1.75-dev.0 in multiple package.json files. - Upgrade various AWS SDK and Smithy dependencies to their latest versions in package-lock.json for improved stability and performance. * 🔧 chore: Update AWS SDK and Smithy dependencies in package-lock.json - Bump version of @aws-sdk/client-bedrock-runtime to 3.1041.0 and update related dependencies for improved performance and stability. - Upgrade various AWS SDK and Smithy packages to their latest versions, ensuring compatibility and enhanced functionality. * chore: Align LibreChat with agents LangChain upgrade - Route LangChain imports through @librechat/agents facade exports - Update @librechat/agents to 3.1.75-dev.1 and remove direct LangChain deps - Normalize nullable agent model params and API key override typing - Update Google thinking config typing for newer LangChain packages - Refresh targeted audit-related dependency overrides * chore: Add Jest types for API specs * test: Fix LangChain upgrade CI specs * test: Exercise agents env facade * fix: Clean up TS preview diagnostics * fix: Address Codex review feedback
This commit is contained in:
parent
4e45e8e17c
commit
1b79e0b785
53 changed files with 1395 additions and 1141 deletions
|
|
@ -1,6 +1,10 @@
|
|||
const { ToolMessage } = require('@langchain/core/messages');
|
||||
const { ContentTypes } = require('librechat-data-provider');
|
||||
const { HumanMessage, AIMessage, SystemMessage } = require('@langchain/core/messages');
|
||||
const {
|
||||
AIMessage,
|
||||
ToolMessage,
|
||||
HumanMessage,
|
||||
SystemMessage,
|
||||
} = require('@librechat/agents/langchain/messages');
|
||||
const { formatAgentMessages } = require('./formatMessages');
|
||||
|
||||
describe('formatAgentMessages', () => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
const { ToolMessage } = require('@langchain/core/messages');
|
||||
const { EModelEndpoint, ContentTypes } = require('librechat-data-provider');
|
||||
const { HumanMessage, AIMessage, SystemMessage } = require('@langchain/core/messages');
|
||||
const {
|
||||
AIMessage,
|
||||
ToolMessage,
|
||||
HumanMessage,
|
||||
SystemMessage,
|
||||
} = require('@librechat/agents/langchain/messages');
|
||||
|
||||
/**
|
||||
* Formats a message to OpenAI Vision API payload format.
|
||||
|
|
@ -191,7 +195,7 @@ const formatAgentMessages = (payload) => {
|
|||
let args = _args;
|
||||
try {
|
||||
args = JSON.parse(_args);
|
||||
} catch (e) {
|
||||
} catch (_e) {
|
||||
if (typeof _args === 'string') {
|
||||
args = { input: _args };
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const { Constants } = require('librechat-data-provider');
|
||||
const { HumanMessage, AIMessage, SystemMessage } = require('@langchain/core/messages');
|
||||
const { HumanMessage, AIMessage, SystemMessage } = require('@librechat/agents/langchain/messages');
|
||||
const { formatMessage, formatLangChainMessages, formatFromLangChain } = require('./formatMessages');
|
||||
|
||||
describe('formatMessage', () => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
const { PromptTemplate } = require('@langchain/core/prompts');
|
||||
const { PromptTemplate } = require('@librechat/agents/langchain/prompts');
|
||||
/*
|
||||
* Without `{summary}` and `{new_lines}`, token count is 98
|
||||
* We are counting this towards the max context tokens for summaries, +3 for the assistant label (101)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const { Tool } = require('@langchain/core/tools');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { Tool } = require('@librechat/agents/langchain/tools');
|
||||
const { SearchClient, AzureKeyCredential } = require('@azure/search-documents');
|
||||
|
||||
const azureAISearchJsonSchema = {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ const path = require('path');
|
|||
const OpenAI = require('openai');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
const { ProxyAgent, fetch } = require('undici');
|
||||
const { Tool } = require('@langchain/core/tools');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { Tool } = require('@librechat/agents/langchain/tools');
|
||||
const { getImageBasename, extractBaseURL } = require('@librechat/api');
|
||||
const { FileContext, ContentTypes } = require('librechat-data-provider');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
const axios = require('axios');
|
||||
const fetch = require('node-fetch');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
const { Tool } = require('@langchain/core/tools');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { HttpsProxyAgent } = require('https-proxy-agent');
|
||||
const { Tool } = require('@librechat/agents/langchain/tools');
|
||||
const { FileContext, ContentTypes } = require('librechat-data-provider');
|
||||
|
||||
const fluxApiJsonSchema = {
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ const sharp = require('sharp');
|
|||
const { v4 } = require('uuid');
|
||||
const { ProxyAgent } = require('undici');
|
||||
const { GoogleGenAI } = require('@google/genai');
|
||||
const { tool } = require('@langchain/core/tools');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { tool } = require('@librechat/agents/langchain/tools');
|
||||
const { ContentTypes, EImageOutputType } = require('librechat-data-provider');
|
||||
const {
|
||||
geminiToolkit,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
const { Tool } = require('@langchain/core/tools');
|
||||
const { getEnvironmentVariable } = require('@langchain/core/utils/env');
|
||||
const { Tool } = require('@librechat/agents/langchain/tools');
|
||||
const { getEnvironmentVariable } = require('@librechat/agents/langchain/utils/env');
|
||||
|
||||
const googleSearchJsonSchema = {
|
||||
type: 'object',
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ const { v4 } = require('uuid');
|
|||
const OpenAI = require('openai');
|
||||
const FormData = require('form-data');
|
||||
const { ProxyAgent } = require('undici');
|
||||
const { tool } = require('@langchain/core/tools');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { HttpsProxyAgent } = require('https-proxy-agent');
|
||||
const { tool } = require('@librechat/agents/langchain/tools');
|
||||
const { ContentTypes, EImageOutputType } = require('librechat-data-provider');
|
||||
const { logAxiosError, oaiToolkit, extractBaseURL } = require('@librechat/api');
|
||||
const { getStrategyFunctions } = require('~/server/services/Files/strategies');
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
const { Tool } = require('@langchain/core/tools');
|
||||
const { getEnvironmentVariable } = require('@langchain/core/utils/env');
|
||||
const fetch = require('node-fetch');
|
||||
const { Tool } = require('@librechat/agents/langchain/tools');
|
||||
const { getEnvironmentVariable } = require('@librechat/agents/langchain/utils/env');
|
||||
|
||||
const openWeatherJsonSchema = {
|
||||
type: 'object',
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ const path = require('path');
|
|||
const axios = require('axios');
|
||||
const sharp = require('sharp');
|
||||
const { v4: uuidv4 } = require('uuid');
|
||||
const { Tool } = require('@langchain/core/tools');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { Tool } = require('@librechat/agents/langchain/tools');
|
||||
const { FileContext, ContentTypes } = require('librechat-data-provider');
|
||||
const { getBasePath } = require('@librechat/api');
|
||||
const paths = require('~/config/paths');
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
const { z } = require('zod');
|
||||
const { ProxyAgent, fetch } = require('undici');
|
||||
const { tool } = require('@langchain/core/tools');
|
||||
const { tool } = require('@librechat/agents/langchain/tools');
|
||||
const { getApiKey } = require('./credentials');
|
||||
|
||||
function createTavilySearchTool(fields = {}) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
const { ProxyAgent, fetch } = require('undici');
|
||||
const { Tool } = require('@langchain/core/tools');
|
||||
const { getEnvironmentVariable } = require('@langchain/core/utils/env');
|
||||
const { Tool } = require('@librechat/agents/langchain/tools');
|
||||
const { getEnvironmentVariable } = require('@librechat/agents/langchain/utils/env');
|
||||
|
||||
const tavilySearchJsonSchema = {
|
||||
type: 'object',
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
const { Tool } = require('@langchain/core/tools');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { getEnvironmentVariable } = require('@langchain/core/utils/env');
|
||||
const { Tool } = require('@librechat/agents/langchain/tools');
|
||||
const { getEnvironmentVariable } = require('@librechat/agents/langchain/utils/env');
|
||||
|
||||
const traversaalSearchJsonSchema = {
|
||||
type: 'object',
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable no-useless-escape */
|
||||
const axios = require('axios');
|
||||
const { Tool } = require('@langchain/core/tools');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { Tool } = require('@librechat/agents/langchain/tools');
|
||||
|
||||
const wolframJsonSchema = {
|
||||
type: 'object',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
const { getEnvironmentVariable } = require('@langchain/core/utils/env');
|
||||
const { getEnvironmentVariable } = require('@librechat/agents/langchain/utils/env');
|
||||
|
||||
function getApiKey(envVar, override) {
|
||||
const key = getEnvironmentVariable(envVar);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
const GoogleSearch = require('../GoogleSearch');
|
||||
|
||||
jest.mock('node-fetch');
|
||||
jest.mock('@langchain/core/utils/env');
|
||||
|
||||
describe('GoogleSearch', () => {
|
||||
let originalEnv;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ const { fetch, ProxyAgent } = require('undici');
|
|||
const TavilySearchResults = require('../TavilySearchResults');
|
||||
|
||||
jest.mock('undici');
|
||||
jest.mock('@langchain/core/utils/env');
|
||||
|
||||
describe('TavilySearchResults', () => {
|
||||
let originalEnv;
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ const axios = require('axios');
|
|||
const OpenAI = require('openai');
|
||||
const undici = require('undici');
|
||||
const fetch = require('node-fetch');
|
||||
const { ToolMessage } = require('@langchain/core/messages');
|
||||
const { ContentTypes } = require('librechat-data-provider');
|
||||
const { ToolMessage } = require('@librechat/agents/langchain/messages');
|
||||
const StableDiffusionAPI = require('../StableDiffusion');
|
||||
const FluxAPI = require('../FluxAPI');
|
||||
const DALLE3 = require('../DALLE3');
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
const axios = require('axios');
|
||||
const { tool } = require('@langchain/core/tools');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { tool } = require('@librechat/agents/langchain/tools');
|
||||
const { generateShortLivedToken } = require('@librechat/api');
|
||||
const { Tools, EToolResources } = require('librechat-data-provider');
|
||||
const { filterFilesByAgentAccess } = require('~/server/services/Files/permissions');
|
||||
|
|
|
|||
|
|
@ -106,8 +106,8 @@ const validateTools = async (user, tools = []) => {
|
|||
}
|
||||
};
|
||||
|
||||
/** @typedef {typeof import('@langchain/core/tools').Tool} ToolConstructor */
|
||||
/** @typedef {import('@langchain/core/tools').Tool} Tool */
|
||||
/** @typedef {typeof import('@librechat/agents/langchain/tools').Tool} ToolConstructor */
|
||||
/** @typedef {import('@librechat/agents/langchain/tools').Tool} Tool */
|
||||
|
||||
/**
|
||||
* Initializes a tool with authentication values for the given user, supporting alternate authentication fields.
|
||||
|
|
|
|||
|
|
@ -38,13 +38,12 @@
|
|||
"@aws-sdk/client-bedrock-runtime": "^3.1013.0",
|
||||
"@aws-sdk/client-s3": "^3.980.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.758.0",
|
||||
"@azure/identity": "^4.7.0",
|
||||
"@azure/identity": "^4.13.1",
|
||||
"@azure/search-documents": "^12.0.0",
|
||||
"@azure/storage-blob": "^12.30.0",
|
||||
"@google/genai": "^1.19.0",
|
||||
"@keyv/redis": "^4.3.3",
|
||||
"@langchain/core": "^0.3.80",
|
||||
"@librechat/agents": "^3.1.75",
|
||||
"@librechat/agents": "^3.1.75-dev.1",
|
||||
"@librechat/api": "*",
|
||||
"@librechat/data-schemas": "*",
|
||||
"@microsoft/microsoft-graph-client": "^3.0.7",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
require('events').EventEmitter.defaultMaxListeners = 100;
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { getBufferString, HumanMessage } = require('@langchain/core/messages');
|
||||
const { getBufferString, HumanMessage } = require('@librechat/agents/langchain/messages');
|
||||
const {
|
||||
createRun,
|
||||
isEnabled,
|
||||
|
|
|
|||
|
|
@ -1250,7 +1250,7 @@ describe('AgentClient - titleConvo', () => {
|
|||
'# MCP Server Instructions\n\nTest MCP instructions here',
|
||||
);
|
||||
|
||||
const { DynamicStructuredTool } = require('@langchain/core/tools');
|
||||
const { DynamicStructuredTool } = require('@librechat/agents/langchain/tools');
|
||||
|
||||
// Create mock MCP tools with the delimiter pattern
|
||||
const mockMCPTool1 = new DynamicStructuredTool({
|
||||
|
|
@ -1482,7 +1482,7 @@ describe('AgentClient - titleConvo', () => {
|
|||
});
|
||||
|
||||
it('should filter out image URLs from message content', async () => {
|
||||
const { HumanMessage, AIMessage } = require('@langchain/core/messages');
|
||||
const { HumanMessage, AIMessage } = require('@librechat/agents/langchain/messages');
|
||||
const messages = [
|
||||
new HumanMessage({
|
||||
content: [
|
||||
|
|
@ -1538,7 +1538,7 @@ describe('AgentClient - titleConvo', () => {
|
|||
});
|
||||
|
||||
it('should handle messages with only text content', async () => {
|
||||
const { HumanMessage, AIMessage } = require('@langchain/core/messages');
|
||||
const { HumanMessage, AIMessage } = require('@librechat/agents/langchain/messages');
|
||||
const messages = [
|
||||
new HumanMessage('Hello, how are you?'),
|
||||
new AIMessage('I am doing well, thank you!'),
|
||||
|
|
@ -1556,7 +1556,7 @@ describe('AgentClient - titleConvo', () => {
|
|||
});
|
||||
|
||||
it('should handle mixed content types correctly', async () => {
|
||||
const { HumanMessage } = require('@langchain/core/messages');
|
||||
const { HumanMessage } = require('@librechat/agents/langchain/messages');
|
||||
const { ContentTypes } = require('librechat-data-provider');
|
||||
|
||||
const messages = [
|
||||
|
|
@ -1593,7 +1593,7 @@ describe('AgentClient - titleConvo', () => {
|
|||
});
|
||||
|
||||
it('should preserve original messages without mutation', async () => {
|
||||
const { HumanMessage } = require('@langchain/core/messages');
|
||||
const { HumanMessage } = require('@librechat/agents/langchain/messages');
|
||||
const originalContent = [
|
||||
{
|
||||
type: 'text',
|
||||
|
|
@ -1622,7 +1622,7 @@ describe('AgentClient - titleConvo', () => {
|
|||
});
|
||||
|
||||
it('should handle message window size correctly', async () => {
|
||||
const { HumanMessage, AIMessage } = require('@langchain/core/messages');
|
||||
const { HumanMessage, AIMessage } = require('@librechat/agents/langchain/messages');
|
||||
const messages = [
|
||||
new HumanMessage('Message 1'),
|
||||
new AIMessage('Response 1'),
|
||||
|
|
@ -1646,7 +1646,7 @@ describe('AgentClient - titleConvo', () => {
|
|||
});
|
||||
|
||||
it('should return early if processMemory is not set', async () => {
|
||||
const { HumanMessage } = require('@langchain/core/messages');
|
||||
const { HumanMessage } = require('@librechat/agents/langchain/messages');
|
||||
client.processMemory = null;
|
||||
|
||||
const result = await client.runMemory([new HumanMessage('Test')]);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
const jwt = require('jsonwebtoken');
|
||||
const { nanoid } = require('nanoid');
|
||||
const { tool } = require('@langchain/core/tools');
|
||||
const { GraphEvents, sleep } = require('@librechat/agents');
|
||||
const { tool } = require('@librechat/agents/langchain/tools');
|
||||
const { logger, encryptV2, decryptV2 } = require('@librechat/data-schemas');
|
||||
const {
|
||||
sendEvent,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
const { tool } = require('@langchain/core/tools');
|
||||
const { tool } = require('@librechat/agents/langchain/tools');
|
||||
const { logger, getTenantId } = require('@librechat/data-schemas');
|
||||
const {
|
||||
Providers,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
const { logger } = require('@librechat/data-schemas');
|
||||
const { tool: toolFn, DynamicStructuredTool } = require('@langchain/core/tools');
|
||||
const { tool: toolFn, DynamicStructuredTool } = require('@librechat/agents/langchain/tools');
|
||||
const {
|
||||
sleep,
|
||||
StepTypes,
|
||||
GraphEvents,
|
||||
createToolSearch,
|
||||
Constants: AgentConstants,
|
||||
createBashExecutionTool,
|
||||
Constants: AgentConstants,
|
||||
createProgrammaticToolCallingTool,
|
||||
} = require('@librechat/agents');
|
||||
const {
|
||||
|
|
@ -17,10 +17,10 @@ const {
|
|||
GenerationJobManager,
|
||||
isActionDomainAllowed,
|
||||
buildWebSearchContext,
|
||||
buildWebSearchDynamicContext,
|
||||
buildImageToolContext,
|
||||
buildToolClassification,
|
||||
buildOAuthToolCallName,
|
||||
buildToolClassification,
|
||||
buildWebSearchDynamicContext,
|
||||
} = require('@librechat/api');
|
||||
const {
|
||||
Time,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { Tool } = require('@langchain/core/tools');
|
||||
const { Calculator } = require('@librechat/agents');
|
||||
const { logger } = require('@librechat/data-schemas');
|
||||
const { zodToJsonSchema } = require('zod-to-json-schema');
|
||||
const { Tool } = require('@librechat/agents/langchain/tools');
|
||||
const { Tools, ImageVisionTool } = require('librechat-data-provider');
|
||||
const { getToolkitKey, oaiToolkit, geminiToolkit } = require('@librechat/api');
|
||||
const { toolkits } = require('~/app/clients/tools/manifest');
|
||||
|
|
|
|||
|
|
@ -162,25 +162,25 @@
|
|||
|
||||
/**
|
||||
* @exports BaseMessage
|
||||
* @typedef {import('@langchain/core/messages').BaseMessage} BaseMessage
|
||||
* @typedef {import('@librechat/agents/langchain/messages').BaseMessage} BaseMessage
|
||||
* @memberof typedefs
|
||||
*/
|
||||
|
||||
/**
|
||||
* @exports UsageMetadata
|
||||
* @typedef {import('@langchain/core/messages').UsageMetadata} UsageMetadata
|
||||
* @typedef {import('@librechat/agents/langchain/messages').UsageMetadata} UsageMetadata
|
||||
* @memberof typedefs
|
||||
*/
|
||||
|
||||
/**
|
||||
* @exports LangChainToolCall
|
||||
* @typedef {import('@langchain/core/messages/tool').ToolCall} LangChainToolCall
|
||||
* @typedef {import('@librechat/agents/langchain/messages/tool').ToolCall} LangChainToolCall
|
||||
* @memberof typedefs
|
||||
*/
|
||||
|
||||
/**
|
||||
* @exports GraphRunnableConfig
|
||||
* @typedef {import('@langchain/core/runnables').RunnableConfig<{
|
||||
* @typedef {import('@librechat/agents/langchain/runnables').RunnableConfig<{
|
||||
* req: ServerRequest;
|
||||
* thread_id: string;
|
||||
* run_id: string;
|
||||
|
|
|
|||
2214
package-lock.json
generated
2214
package-lock.json
generated
File diff suppressed because it is too large
Load diff
16
package.json
16
package.json
|
|
@ -139,20 +139,15 @@
|
|||
"typescript-eslint": "^8.24.0"
|
||||
},
|
||||
"overrides": {
|
||||
"@anthropic-ai/sdk": "0.73.0",
|
||||
"@xmldom/xmldom": "^0.8.13",
|
||||
"@librechat/agents": {
|
||||
"@langchain/anthropic": {
|
||||
"@anthropic-ai/sdk": "0.73.0",
|
||||
"fast-xml-parser": "5.6.0"
|
||||
},
|
||||
"@anthropic-ai/sdk": "0.73.0",
|
||||
"fast-xml-parser": "5.6.0"
|
||||
},
|
||||
"elliptic": "^6.6.1",
|
||||
"fast-xml-parser": "5.6.0",
|
||||
"form-data": "^4.0.4",
|
||||
"langsmith": "^0.6.0",
|
||||
"postcss": "^8.5.13",
|
||||
"tslib": "^2.8.1",
|
||||
"@anthropic-ai/sdk": "^0.92.0",
|
||||
"fast-xml-parser": "5.7.2",
|
||||
"serialize-javascript": "7.0.5",
|
||||
"mdast-util-gfm-autolink-literal": "2.0.0",
|
||||
"remark-gfm": {
|
||||
"mdast-util-gfm-autolink-literal": "2.0.0"
|
||||
|
|
@ -169,7 +164,6 @@
|
|||
"katex": "^0.16.21"
|
||||
}
|
||||
},
|
||||
"langsmith": "0.4.12",
|
||||
"eslint": {
|
||||
"ajv": "6.14.0"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -89,13 +89,12 @@
|
|||
"@anthropic-ai/vertex-sdk": "^0.14.3",
|
||||
"@aws-sdk/client-bedrock-runtime": "^3.1013.0",
|
||||
"@aws-sdk/client-s3": "^3.980.0",
|
||||
"@azure/identity": "^4.7.0",
|
||||
"@azure/identity": "^4.13.1",
|
||||
"@azure/search-documents": "^12.0.0",
|
||||
"@azure/storage-blob": "^12.30.0",
|
||||
"@google/genai": "^1.19.0",
|
||||
"@keyv/redis": "^4.3.3",
|
||||
"@langchain/core": "^0.3.80",
|
||||
"@librechat/agents": "^3.1.75",
|
||||
"@librechat/agents": "^3.1.75-dev.1",
|
||||
"@librechat/data-schemas": "*",
|
||||
"@modelcontextprotocol/sdk": "^1.29.0",
|
||||
"@smithy/node-http-handler": "^4.4.5",
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ jest.mock('@librechat/agents', () => ({
|
|||
}));
|
||||
|
||||
import { Types } from 'mongoose';
|
||||
import { HumanMessage, AIMessage } from '@langchain/core/messages';
|
||||
import { HumanMessage, AIMessage } from '@librechat/agents/langchain/messages';
|
||||
import {
|
||||
scopeSkillIds,
|
||||
resolveSkillActive,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { PromptTemplate } from '@langchain/core/prompts';
|
||||
import { BaseMessage, getBufferString } from '@langchain/core/messages';
|
||||
import { PromptTemplate } from '@librechat/agents/langchain/prompts';
|
||||
import { BaseMessage, getBufferString } from '@librechat/agents/langchain/messages';
|
||||
import type { GraphEdge } from '@librechat/agents';
|
||||
|
||||
const DEFAULT_PROMPT_TEMPLATE = `Based on the following conversation and analysis from previous agents, please provide your insights:\n\n{convo}\n\nPlease add your specific expertise and perspective to this discussion.`;
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ import {
|
|||
estimateOpenAIImageTokens,
|
||||
estimateAnthropicImageTokens,
|
||||
} from '@librechat/agents';
|
||||
import type { BaseMessage } from '@librechat/agents/langchain/messages';
|
||||
import type { MessageContentComplex } from '@librechat/agents';
|
||||
import type { Agent, TMessage } from 'librechat-data-provider';
|
||||
import type { BaseMessage } from '@langchain/core/messages';
|
||||
import type { ServerRequest } from '~/types';
|
||||
import Tokenizer from '~/utils/tokenizer';
|
||||
import { logAxiosError } from '~/utils';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { z } from 'zod';
|
||||
import { Constants } from 'librechat-data-provider';
|
||||
import { DynamicStructuredTool } from '@langchain/core/tools';
|
||||
import { DynamicStructuredTool } from '@librechat/agents/langchain/tools';
|
||||
import type { Logger } from 'winston';
|
||||
import type { MCPManager } from '~/mcp/MCPManager';
|
||||
import type { AgentWithTools } from './context';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Constants } from 'librechat-data-provider';
|
||||
import { DynamicStructuredTool } from '@langchain/core/tools';
|
||||
import { DynamicStructuredTool } from '@librechat/agents/langchain/tools';
|
||||
import type { Agent, TEphemeralAgent } from 'librechat-data-provider';
|
||||
import type { LCTool } from '@librechat/agents';
|
||||
import type { Logger } from 'winston';
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ import type {
|
|||
ToolExecuteBatchRequest,
|
||||
} from '@librechat/agents';
|
||||
import { Types } from 'mongoose';
|
||||
import type { StructuredToolInterface } from '@langchain/core/tools';
|
||||
import type { StructuredToolInterface } from '@librechat/agents/langchain/tools';
|
||||
import type { SkillFileRecord } from './skillFiles';
|
||||
import type { ServerRequest } from '~/types';
|
||||
import { buildSkillPrimeMessage } from './skills';
|
||||
import { cleanCodeToolOutput } from './cleanup';
|
||||
import { primeSkillFiles } from './skillFiles';
|
||||
import type { SkillFileRecord } from './skillFiles';
|
||||
import { buildSkillPrimeMessage } from './skills';
|
||||
import { runOutsideTracing } from '~/utils';
|
||||
|
||||
export interface ToolEndCallbackData {
|
||||
|
|
@ -694,13 +694,13 @@ async function handleReadFileCall(
|
|||
}
|
||||
|
||||
const stream = await strategy.getDownloadStream(req, file.filepath);
|
||||
const chunks: Buffer[] = [];
|
||||
const chunks: Uint8Array[] = [];
|
||||
// Use the larger binary limit as streaming cap; cheaper type-specific
|
||||
// checks happen after binary detection on the assembled buffer.
|
||||
const streamLimit = MAX_BINARY_BYTES;
|
||||
let streamedBytes = 0;
|
||||
for await (const chunk of stream as AsyncIterable<Buffer>) {
|
||||
streamedBytes += chunk.length;
|
||||
for await (const chunk of stream as AsyncIterable<Uint8Array>) {
|
||||
streamedBytes += chunk.byteLength;
|
||||
if (streamedBytes > streamLimit) {
|
||||
// Destroy the stream if possible to free resources
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -326,7 +326,7 @@ describe('Memory Agent Header Resolution', () => {
|
|||
model: 'us.anthropic.claude-haiku-4-5-20251001-v1:0',
|
||||
};
|
||||
|
||||
const { HumanMessage } = await import('@langchain/core/messages');
|
||||
const { HumanMessage } = await import('@librechat/agents/langchain/messages');
|
||||
const testMessage = new HumanMessage('test chat content');
|
||||
|
||||
await processMemory({
|
||||
|
|
|
|||
|
|
@ -1,22 +1,22 @@
|
|||
/** Memories */
|
||||
import { z } from 'zod';
|
||||
import { tool } from '@langchain/core/tools';
|
||||
import { Tools } from 'librechat-data-provider';
|
||||
import { logger } from '@librechat/data-schemas';
|
||||
import { HumanMessage } from '@langchain/core/messages';
|
||||
import { tool } from '@librechat/agents/langchain/tools';
|
||||
import { Run, Providers, GraphEvents } from '@librechat/agents';
|
||||
import { HumanMessage } from '@librechat/agents/langchain/messages';
|
||||
import type {
|
||||
OpenAIClientOptions,
|
||||
StreamEventData,
|
||||
ToolEndCallback,
|
||||
ClientOptions,
|
||||
EventHandler,
|
||||
ToolEndData,
|
||||
LLMConfig,
|
||||
} from '@librechat/agents';
|
||||
import type { BaseMessage, ToolMessage } from '@librechat/agents/langchain/messages';
|
||||
import type { DynamicStructuredTool } from '@librechat/agents/langchain/tools';
|
||||
import type { ObjectId, MemoryMethods, IUser } from '@librechat/data-schemas';
|
||||
import type { TAttachment, MemoryArtifact } from 'librechat-data-provider';
|
||||
import type { BaseMessage, ToolMessage } from '@langchain/core/messages';
|
||||
import type { Response as ServerResponse } from 'express';
|
||||
import { GenerationJobManager } from '~/stream/GenerationJobManager';
|
||||
import { resolveHeaders, createSafeUser } from '~/utils';
|
||||
|
|
@ -32,6 +32,8 @@ type ToolEndMetadata = Record<string, unknown> & {
|
|||
thread_id?: string;
|
||||
};
|
||||
|
||||
type SanitizedMemoryLLMConfig = Omit<Partial<LLMConfig>, 'apiKey'> & { apiKey?: string };
|
||||
|
||||
export interface MemoryConfig {
|
||||
validKeys?: string[];
|
||||
instructions?: string;
|
||||
|
|
@ -39,6 +41,14 @@ export interface MemoryConfig {
|
|||
tokenLimit?: number;
|
||||
}
|
||||
|
||||
function normalizeMemoryLLMConfig(llmConfig?: Partial<LLMConfig>): SanitizedMemoryLLMConfig {
|
||||
const config = { ...(llmConfig ?? {}) } as Record<string, unknown>;
|
||||
if (typeof config.apiKey !== 'string') {
|
||||
delete config.apiKey;
|
||||
}
|
||||
return config as SanitizedMemoryLLMConfig;
|
||||
}
|
||||
|
||||
export const memoryInstructions =
|
||||
'The system automatically stores important user information and can update or delete memories based on user requests, enabling dynamic memory management.';
|
||||
|
||||
|
|
@ -88,7 +98,7 @@ export const createMemoryTool = ({
|
|||
validKeys?: string[];
|
||||
tokenLimit?: number;
|
||||
totalTokens?: number;
|
||||
}) => {
|
||||
}): DynamicStructuredTool => {
|
||||
const remainingTokens = tokenLimit ? tokenLimit - totalTokens : Infinity;
|
||||
const isOverflowing = tokenLimit ? remainingTokens <= 0 : false;
|
||||
|
||||
|
|
@ -342,15 +352,15 @@ ${memory ?? 'No existing memories'}`;
|
|||
disableStreaming: true,
|
||||
};
|
||||
|
||||
const finalLLMConfig: ClientOptions = {
|
||||
const finalLLMConfig = {
|
||||
...defaultLLMConfig,
|
||||
...llmConfig,
|
||||
...normalizeMemoryLLMConfig(llmConfig),
|
||||
/**
|
||||
* Ensure streaming is always disabled for memory processing
|
||||
*/
|
||||
streaming: false,
|
||||
disableStreaming: true,
|
||||
};
|
||||
} as LLMConfig;
|
||||
|
||||
// Handle GPT-5+ models
|
||||
if ('model' in finalLLMConfig && /\bgpt-[5-9](?:\.\d+)?\b/i.test(finalLLMConfig.model ?? '')) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { ToolMessage, AIMessage, HumanMessage } from '@langchain/core/messages';
|
||||
import { ToolMessage, AIMessage, HumanMessage } from '@librechat/agents/langchain/messages';
|
||||
import { extractDiscoveredToolsFromHistory } from './run';
|
||||
|
||||
describe('extractDiscoveredToolsFromHistory', () => {
|
||||
|
|
|
|||
|
|
@ -20,13 +20,18 @@ import type {
|
|||
IState,
|
||||
LCTool,
|
||||
} from '@librechat/agents';
|
||||
import type { Agent, AgentSubagentsConfig, SummarizationConfig } from 'librechat-data-provider';
|
||||
import type { BaseMessage } from '@langchain/core/messages';
|
||||
import type {
|
||||
Agent,
|
||||
AgentModelParameters,
|
||||
AgentSubagentsConfig,
|
||||
SummarizationConfig,
|
||||
} from 'librechat-data-provider';
|
||||
import type { BaseMessage } from '@librechat/agents/langchain/messages';
|
||||
import type { AppConfig, IUser } from '@librechat/data-schemas';
|
||||
import type * as t from '~/types';
|
||||
import { getProviderConfig } from '~/endpoints/config/providers';
|
||||
import { getOpenAIConfig } from '~/endpoints/openai/config';
|
||||
import { resolveHeaders, createSafeUser } from '~/utils/env';
|
||||
import { getOpenAIConfig } from '~/endpoints/openai/config';
|
||||
import { isUserProvided } from '~/utils/common';
|
||||
|
||||
/** Expected shape of JSON tool search results */
|
||||
|
|
@ -275,6 +280,31 @@ function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|||
return value != null && typeof value === 'object' && !Array.isArray(value);
|
||||
}
|
||||
|
||||
const nullableAgentModelParameterKeys = [
|
||||
'temperature',
|
||||
'maxContextTokens',
|
||||
'max_context_tokens',
|
||||
'max_output_tokens',
|
||||
'top_p',
|
||||
'frequency_penalty',
|
||||
'presence_penalty',
|
||||
] satisfies Array<keyof AgentModelParameters>;
|
||||
|
||||
function normalizeAgentModelParameters(
|
||||
modelParameters: AgentModelParameters | undefined,
|
||||
): Partial<AgentModelParameters> | undefined {
|
||||
if (!modelParameters) {
|
||||
return undefined;
|
||||
}
|
||||
const normalized: Partial<AgentModelParameters> = { ...modelParameters };
|
||||
for (const key of nullableAgentModelParameterKeys) {
|
||||
if (normalized[key] === null) {
|
||||
delete normalized[key];
|
||||
}
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges user-supplied summarization parameters on top of endpoint-resolved
|
||||
* overrides. User params win for top-level keys; `configuration` is
|
||||
|
|
@ -398,9 +428,11 @@ function resolveSummarizationProvider(
|
|||
},
|
||||
rawProvider,
|
||||
);
|
||||
const clientOverrides: SummarizationClientOverrides = {
|
||||
...llmConfig,
|
||||
};
|
||||
const { apiKey: resolvedApiKey, ...llmConfigOverrides } = llmConfig;
|
||||
const clientOverrides: SummarizationClientOverrides = { ...llmConfigOverrides };
|
||||
if (typeof resolvedApiKey === 'string') {
|
||||
clientOverrides.apiKey = resolvedApiKey;
|
||||
}
|
||||
if (configOptions) {
|
||||
clientOverrides.configuration = configOptions;
|
||||
}
|
||||
|
|
@ -718,14 +750,15 @@ export async function createRun({
|
|||
{ user, requestBody },
|
||||
);
|
||||
|
||||
const llmConfig: t.RunLLMConfig = Object.assign(
|
||||
const modelParameters = normalizeAgentModelParameters(agent.model_parameters);
|
||||
const llmConfig = Object.assign(
|
||||
{
|
||||
provider,
|
||||
streaming,
|
||||
streamUsage,
|
||||
},
|
||||
agent.model_parameters,
|
||||
);
|
||||
modelParameters,
|
||||
) as t.RunLLMConfig;
|
||||
|
||||
const joinInstructionMap = (map?: Record<string, unknown>) =>
|
||||
Object.values(map ?? {})
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { logger } from '@librechat/data-schemas';
|
||||
import { HumanMessage } from '@langchain/core/messages';
|
||||
import { isEphemeralAgentId } from 'librechat-data-provider';
|
||||
import { HumanMessage } from '@librechat/agents/langchain/messages';
|
||||
import { formatSkillCatalog, SkillToolDefinition } from '@librechat/agents';
|
||||
import type { LCToolRegistry, LCTool, InjectedMessage } from '@librechat/agents';
|
||||
import type { BaseMessage } from '@langchain/core/messages';
|
||||
import type { BaseMessage } from '@librechat/agents/langchain/messages';
|
||||
import type { Agent } from 'librechat-data-provider';
|
||||
import type { Types } from 'mongoose';
|
||||
import type { InitializeAgentDbMethods } from './initialize';
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ function getLLMConfig(
|
|||
let requestOptions: AnthropicClientOptions & { stream?: boolean } = {
|
||||
model: mergedOptions.model,
|
||||
stream: mergedOptions.stream,
|
||||
temperature: mergedOptions.temperature,
|
||||
temperature: mergedOptions.temperature ?? undefined,
|
||||
stopSequences: mergedOptions.stop,
|
||||
maxTokens:
|
||||
mergedOptions.maxOutputTokens || anthropicSettings.maxOutputTokens.reset(mergedOptions.model),
|
||||
|
|
|
|||
|
|
@ -384,7 +384,7 @@ describe('getGoogleConfig', () => {
|
|||
expect(result.llmConfig).toHaveProperty('thinkingConfig');
|
||||
expect((result.llmConfig as Record<string, unknown>).thinkingConfig).toMatchObject({
|
||||
includeThoughts: true,
|
||||
thinkingLevel: ThinkingLevel.high,
|
||||
thinkingLevel: 'HIGH',
|
||||
});
|
||||
expect((result.llmConfig as Record<string, unknown>).thinkingConfig).not.toHaveProperty(
|
||||
'thinkingBudget',
|
||||
|
|
@ -406,7 +406,26 @@ describe('getGoogleConfig', () => {
|
|||
|
||||
expect((result.llmConfig as Record<string, unknown>).thinkingConfig).toMatchObject({
|
||||
includeThoughts: true,
|
||||
thinkingLevel: ThinkingLevel.medium,
|
||||
thinkingLevel: 'MEDIUM',
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve minimal thinkingLevel for Gemini 3 Flash models', () => {
|
||||
const credentials = {
|
||||
[AuthKeys.GOOGLE_API_KEY]: 'test-api-key',
|
||||
};
|
||||
|
||||
const result = getGoogleConfig(credentials, {
|
||||
modelOptions: {
|
||||
model: 'gemini-3-flash-preview',
|
||||
thinking: true,
|
||||
thinkingLevel: ThinkingLevel.minimal,
|
||||
},
|
||||
});
|
||||
|
||||
expect((result.llmConfig as Record<string, unknown>).thinkingConfig).toMatchObject({
|
||||
includeThoughts: true,
|
||||
thinkingLevel: 'MINIMAL',
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -466,7 +485,7 @@ describe('getGoogleConfig', () => {
|
|||
expect(result.provider).toBe(Providers.VERTEXAI);
|
||||
expect((result.llmConfig as Record<string, unknown>).thinkingConfig).toMatchObject({
|
||||
includeThoughts: true,
|
||||
thinkingLevel: ThinkingLevel.low,
|
||||
thinkingLevel: 'LOW',
|
||||
});
|
||||
expect(result.llmConfig).toHaveProperty('includeThoughts', true);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,10 +1,24 @@
|
|||
import { Providers } from '@librechat/agents';
|
||||
import { googleSettings, AuthKeys, removeNullishValues } from 'librechat-data-provider';
|
||||
import type { GoogleClientOptions, VertexAIClientOptions } from '@librechat/agents';
|
||||
import type { GoogleAIToolType } from '@langchain/google-common';
|
||||
import type { GoogleAIToolType } from '@librechat/agents/langchain/google-common';
|
||||
import type * as t from '~/types';
|
||||
import { isEnabled } from '~/utils';
|
||||
|
||||
type GoogleThinkingLevel = 'THINKING_LEVEL_UNSPECIFIED' | 'MINIMAL' | 'LOW' | 'MEDIUM' | 'HIGH';
|
||||
type GoogleThinkingConfig = {
|
||||
includeThoughts: boolean;
|
||||
thinkingLevel?: GoogleThinkingLevel;
|
||||
};
|
||||
|
||||
const googleThinkingLevels = new Set<GoogleThinkingLevel>([
|
||||
'THINKING_LEVEL_UNSPECIFIED',
|
||||
'MINIMAL',
|
||||
'LOW',
|
||||
'MEDIUM',
|
||||
'HIGH',
|
||||
]);
|
||||
|
||||
/** Known Google/Vertex AI parameters that map directly to the client config */
|
||||
export const knownGoogleParams = new Set([
|
||||
'model',
|
||||
|
|
@ -70,6 +84,17 @@ function getThresholdMapping(model: string) {
|
|||
return (value: string) => value;
|
||||
}
|
||||
|
||||
function normalizeGoogleThinkingLevel(value: unknown): GoogleThinkingLevel | undefined {
|
||||
if (typeof value !== 'string') {
|
||||
return undefined;
|
||||
}
|
||||
const normalized = value.toUpperCase() as GoogleThinkingLevel;
|
||||
if (!googleThinkingLevels.has(normalized)) {
|
||||
return undefined;
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
|
||||
export function getSafetySettings(
|
||||
model?: string,
|
||||
): Array<{ category: string; threshold: string }> | undefined {
|
||||
|
|
@ -206,22 +231,23 @@ export function getGoogleConfig(
|
|||
* with `includeThoughts: true`. The `thinkingBudget` param is ignored for Gemini 3+.
|
||||
*
|
||||
* For Vertex AI, top-level `includeThoughts` is still required because
|
||||
* `@langchain/google-common`'s `formatGenerationConfig` reads it separately
|
||||
* `@librechat/agents/langchain/google-common`'s `formatGenerationConfig` reads it separately
|
||||
* from `thinkingConfig` — they serve different purposes in the request pipeline.
|
||||
*/
|
||||
const isGemini3Plus = /gemini-([3-9]|\d{2,})/i.test(modelName);
|
||||
|
||||
if (isGemini3Plus && thinking) {
|
||||
const thinkingConfig: { includeThoughts: boolean; thinkingLevel?: string } = {
|
||||
const thinkingConfig: GoogleThinkingConfig = {
|
||||
includeThoughts: true,
|
||||
};
|
||||
if (thinkingLevel) {
|
||||
thinkingConfig.thinkingLevel = thinkingLevel as string;
|
||||
const normalizedThinkingLevel = normalizeGoogleThinkingLevel(thinkingLevel);
|
||||
if (normalizedThinkingLevel) {
|
||||
thinkingConfig.thinkingLevel = normalizedThinkingLevel;
|
||||
}
|
||||
if (provider === Providers.GOOGLE) {
|
||||
(llmConfig as GoogleClientOptions).thinkingConfig = thinkingConfig;
|
||||
(llmConfig as { thinkingConfig?: GoogleThinkingConfig }).thinkingConfig = thinkingConfig;
|
||||
} else if (provider === Providers.VERTEXAI) {
|
||||
(llmConfig as Record<string, unknown>).thinkingConfig = thinkingConfig;
|
||||
(llmConfig as { thinkingConfig?: GoogleThinkingConfig }).thinkingConfig = thinkingConfig;
|
||||
(llmConfig as VertexAIClientOptions).includeThoughts = true;
|
||||
}
|
||||
} else if (!isGemini3Plus) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { EModelEndpoint, removeNullishValues } from 'librechat-data-provider';
|
||||
import type { BindToolsInput } from '@langchain/core/language_models/chat_models';
|
||||
import type { BindToolsInput } from '@librechat/agents/langchain/language_models/chat_models';
|
||||
import type { AzureOpenAIInput } from '@librechat/agents/langchain/openai';
|
||||
import type { SettingDefinition } from 'librechat-data-provider';
|
||||
import type { AzureOpenAIInput } from '@langchain/openai';
|
||||
import type { OpenAI } from 'openai';
|
||||
import type * as t from '~/types';
|
||||
import { sanitizeModelName, constructAzureURL } from '~/utils/azure';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { EModelEndpoint } from 'librechat-data-provider';
|
||||
import type { GoogleAIToolType } from '@langchain/google-common';
|
||||
import type { GoogleAIToolType } from '@librechat/agents/langchain/google-common';
|
||||
import type { ClientOptions } from '@librechat/agents';
|
||||
import type * as t from '~/types';
|
||||
import { knownOpenAIParams } from './llm';
|
||||
|
|
|
|||
2
packages/api/src/types/es2024-string.d.ts
vendored
2
packages/api/src/types/es2024-string.d.ts
vendored
|
|
@ -1,3 +1,5 @@
|
|||
/// <reference types="jest" />
|
||||
|
||||
/** String.prototype.isWellFormed — ES2024 API, available in Node 20+ but absent from TS 5.3 lib */
|
||||
interface String {
|
||||
isWellFormed(): boolean;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { z } from 'zod';
|
||||
import { openAISchema } from 'librechat-data-provider';
|
||||
import type { TConfig } from 'librechat-data-provider';
|
||||
import type { BindToolsInput } from '@librechat/agents/langchain/language_models/chat_models';
|
||||
import type { OpenAIClientOptions, Providers } from '@librechat/agents';
|
||||
import type { BindToolsInput } from '@langchain/core/language_models/chat_models';
|
||||
import type { TConfig } from 'librechat-data-provider';
|
||||
import type { AzureOptions } from './azure';
|
||||
|
||||
export type OpenAIParameters = z.infer<typeof openAISchema>;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { ContentTypes, ToolCallTypes } from 'librechat-data-provider';
|
||||
import type { Agents, PartMetadata, TMessageContentParts } from 'librechat-data-provider';
|
||||
import type { ToolCall } from '@langchain/core/messages/tool';
|
||||
import type { ToolCall } from '@librechat/agents/langchain/messages/tool';
|
||||
import { filterMalformedContentParts } from './content';
|
||||
|
||||
describe('filterMalformedContentParts', () => {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import type { BaseMessage } from '@langchain/core/messages';
|
||||
import type { BaseMessage } from '@librechat/agents/langchain/messages';
|
||||
|
||||
/** Signature for a function that counts tokens in a LangChain message. */
|
||||
export type TokenCounter = (message: BaseMessage) => number;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue