@librechat/agents 2.2.5 → 2.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/cjs/events.cjs +3 -0
  2. package/dist/cjs/events.cjs.map +1 -1
  3. package/dist/cjs/graphs/Graph.cjs +40 -2
  4. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  5. package/dist/cjs/llm/fake.cjs +45 -3
  6. package/dist/cjs/llm/fake.cjs.map +1 -1
  7. package/dist/cjs/messages/format.cjs +161 -80
  8. package/dist/cjs/messages/format.cjs.map +1 -1
  9. package/dist/cjs/tools/ToolNode.cjs +9 -1
  10. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  11. package/dist/esm/events.mjs +3 -0
  12. package/dist/esm/events.mjs.map +1 -1
  13. package/dist/esm/graphs/Graph.mjs +40 -2
  14. package/dist/esm/graphs/Graph.mjs.map +1 -1
  15. package/dist/esm/llm/fake.mjs +45 -3
  16. package/dist/esm/llm/fake.mjs.map +1 -1
  17. package/dist/esm/messages/format.mjs +162 -81
  18. package/dist/esm/messages/format.mjs.map +1 -1
  19. package/dist/esm/tools/ToolNode.mjs +9 -1
  20. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  21. package/dist/types/graphs/Graph.d.ts +3 -1
  22. package/dist/types/llm/fake.d.ts +14 -4
  23. package/dist/types/messages/format.d.ts +6 -15
  24. package/dist/types/tools/ToolNode.d.ts +2 -1
  25. package/dist/types/types/stream.d.ts +35 -1
  26. package/dist/types/types/tools.d.ts +3 -5
  27. package/package.json +6 -6
  28. package/src/events.ts +4 -0
  29. package/src/graphs/Graph.ts +52 -2
  30. package/src/llm/fake.ts +58 -8
  31. package/src/messages/format.ts +180 -111
  32. package/src/messages/formatAgentMessages.test.ts +2 -1
  33. package/src/messages/formatAgentMessages.tools.test.ts +349 -0
  34. package/src/scripts/image.ts +2 -2
  35. package/src/specs/tool-error.test.ts +156 -0
  36. package/src/tools/ToolNode.ts +9 -0
  37. package/src/types/stream.ts +41 -2
  38. package/src/types/tools.ts +3 -6
@@ -1 +1 @@
1
- {"version":3,"file":"format.mjs","sources":["../../../src/messages/format.ts"],"sourcesContent":["import { ToolMessage, BaseMessage } from '@langchain/core/messages';\nimport { HumanMessage, AIMessage, SystemMessage } from '@langchain/core/messages';\nimport { MessageContentImageUrl } from '@langchain/core/messages';\nimport type { ToolCall } from '@langchain/core/messages/tool';\nimport type { MessageContentComplex } from '@/types';\nimport { Providers, ContentTypes } from '@/common';\n\ninterface VisionMessageParams {\n message: {\n role: string;\n content: string;\n name?: string;\n [key: string]: any;\n };\n image_urls: MessageContentImageUrl[];\n endpoint?: Providers;\n}\n\n/**\n * Formats a message to OpenAI Vision API payload format.\n *\n * @param {VisionMessageParams} params - The parameters for formatting.\n * @returns {Object} - The formatted message.\n */\nexport const formatVisionMessage = ({ message, image_urls, endpoint }: VisionMessageParams): {\n role: string;\n content: MessageContentComplex[];\n name?: string;\n [key: string]: any;\n} => {\n // Create a new object to avoid mutating the input\n const result: {\n role: string;\n content: MessageContentComplex[];\n name?: string;\n [key: string]: any;\n } = {\n ...message,\n content: [] as MessageContentComplex[]\n };\n \n if (endpoint === Providers.ANTHROPIC) {\n result.content = [\n ...image_urls, \n { type: ContentTypes.TEXT, text: message.content }\n ] as MessageContentComplex[];\n return result;\n }\n\n result.content = [\n { type: ContentTypes.TEXT, text: message.content }, \n ...image_urls\n ] as MessageContentComplex[];\n\n return result;\n};\n\ninterface MessageInput {\n role?: string;\n _name?: string;\n sender?: string;\n text?: string;\n content?: string | MessageContentComplex[];\n image_urls?: MessageContentImageUrl[];\n lc_id?: string[];\n [key: string]: any;\n}\n\ninterface FormatMessageParams {\n message: MessageInput;\n userName?: string;\n assistantName?: string;\n endpoint?: Providers;\n langChain?: boolean;\n}\n\ninterface FormattedMessage {\n role: string;\n content: string | MessageContentComplex[];\n name?: string;\n [key: string]: any;\n}\n\n/**\n * Formats a message to OpenAI payload format based on the provided options.\n *\n * @param {FormatMessageParams} params - The parameters for formatting.\n * @returns {FormattedMessage | HumanMessage | AIMessage | SystemMessage} - The formatted message.\n */\nexport const formatMessage = ({ \n message, \n userName, \n assistantName, \n endpoint, \n langChain = false \n}: FormatMessageParams): FormattedMessage | HumanMessage | AIMessage | SystemMessage => {\n let { role: _role, _name, sender, text, content: _content, lc_id } = message;\n if (lc_id && lc_id[2] && !langChain) {\n const roleMapping: Record<string, string> = {\n SystemMessage: 'system',\n HumanMessage: 'user',\n AIMessage: 'assistant',\n };\n _role = roleMapping[lc_id[2]] || _role;\n }\n const role = _role ?? (sender && sender?.toLowerCase() === 'user' ? 'user' : 'assistant');\n const content = _content ?? text ?? '';\n const formattedMessage: FormattedMessage = {\n role,\n content,\n };\n\n const { image_urls } = message;\n if (Array.isArray(image_urls) && image_urls.length > 0 && role === 'user') {\n return formatVisionMessage({\n message: {\n ...formattedMessage,\n content: typeof formattedMessage.content === 'string' ? formattedMessage.content : ''\n },\n image_urls,\n endpoint,\n });\n }\n\n if (_name) {\n formattedMessage.name = _name;\n }\n\n if (userName && formattedMessage.role === 'user') {\n formattedMessage.name = userName;\n }\n\n if (assistantName && formattedMessage.role === 'assistant') {\n formattedMessage.name = assistantName;\n }\n\n if (formattedMessage.name) {\n // Conform to API regex: ^[a-zA-Z0-9_-]{1,64}$\n // https://community.openai.com/t/the-format-of-the-name-field-in-the-documentation-is-incorrect/175684/2\n formattedMessage.name = formattedMessage.name.replace(/[^a-zA-Z0-9_-]/g, '_');\n\n if (formattedMessage.name.length > 64) {\n formattedMessage.name = formattedMessage.name.substring(0, 64);\n }\n }\n\n if (!langChain) {\n return formattedMessage;\n }\n\n if (role === 'user') {\n return new HumanMessage(formattedMessage);\n } else if (role === 'assistant') {\n return new AIMessage(formattedMessage);\n } else {\n return new SystemMessage(formattedMessage);\n }\n};\n\n/**\n * Formats an array of messages for LangChain.\n *\n * @param {Array<MessageInput>} messages - The array of messages to format.\n * @param {Omit<FormatMessageParams, 'message' | 'langChain'>} formatOptions - The options for formatting each message.\n * @returns {Array<HumanMessage | AIMessage | SystemMessage>} - The array of formatted LangChain messages.\n */\nexport const formatLangChainMessages = (\n messages: Array<MessageInput>, \n formatOptions: Omit<FormatMessageParams, 'message' | 'langChain'>\n): Array<HumanMessage | AIMessage | SystemMessage> => {\n return messages.map((msg) => {\n const formatted = formatMessage({ ...formatOptions, message: msg, langChain: true });\n return formatted as HumanMessage | AIMessage | SystemMessage;\n });\n};\n\ninterface LangChainMessage {\n lc_kwargs?: {\n additional_kwargs?: Record<string, any>;\n [key: string]: any;\n };\n kwargs?: {\n additional_kwargs?: Record<string, any>;\n [key: string]: any;\n };\n [key: string]: any;\n}\n\n/**\n * Formats a LangChain message object by merging properties from `lc_kwargs` or `kwargs` and `additional_kwargs`.\n *\n * @param {LangChainMessage} message - The message object to format.\n * @returns {Record<string, any>} The formatted LangChain message.\n */\nexport const formatFromLangChain = (message: LangChainMessage): Record<string, any> => {\n const kwargs = message.lc_kwargs ?? message.kwargs ?? {};\n const { additional_kwargs = {}, ...message_kwargs } = kwargs;\n return {\n ...message_kwargs,\n ...additional_kwargs,\n };\n};\n\ninterface TMessage {\n role?: string;\n content?: string | Array<{\n type: ContentTypes;\n [ContentTypes.TEXT]?: string;\n text?: string;\n tool_call_ids?: string[];\n [key: string]: any;\n }>;\n [key: string]: any;\n}\n\ninterface ToolCallPart {\n type: ContentTypes.TOOL_CALL;\n tool_call: {\n id: string;\n name: string;\n args: string | Record<string, unknown>;\n output?: string;\n [key: string]: any;\n };\n}\n\n/**\n * Formats an array of messages for LangChain, handling tool calls and creating ToolMessage instances.\n *\n * @param {Array<Partial<TMessage>>} payload - The array of messages to format.\n * @param {Record<number, number>} [indexTokenCountMap] - Optional map of message indices to token counts.\n * @returns {Object} - Object containing formatted messages and updated indexTokenCountMap if provided.\n */\nexport const formatAgentMessages = (\n payload: Array<Partial<TMessage>>, \n indexTokenCountMap?: Record<number, number>\n): {\n messages: Array<HumanMessage | AIMessage | SystemMessage | ToolMessage>;\n indexTokenCountMap?: Record<number, number>;\n} => {\n const messages: Array<HumanMessage | AIMessage | SystemMessage | ToolMessage> = [];\n // If indexTokenCountMap is provided, create a new map to track the updated indices\n const updatedIndexTokenCountMap: Record<number, number> = {};\n // Keep track of the mapping from original payload indices to result indices\n const indexMapping: Record<number, number[]> = {};\n\n for (let i = 0; i < payload.length; i++) {\n const message = payload[i];\n // Q: Store the current length of messages to track where this payload message starts in the result?\n // const startIndex = messages.length;\n if (typeof message.content === 'string') {\n message.content = [{ type: ContentTypes.TEXT, [ContentTypes.TEXT]: message.content }];\n }\n if (message.role !== 'assistant') {\n messages.push(formatMessage({ \n message: message as MessageInput, \n langChain: true \n }) as HumanMessage | AIMessage | SystemMessage);\n \n // Update the index mapping for this message\n indexMapping[i] = [messages.length - 1];\n continue;\n }\n\n // For assistant messages, track the starting index before processing\n const startMessageIndex = messages.length;\n\n let currentContent: any[] = [];\n let lastAIMessage: AIMessage | null = null;\n\n let hasReasoning = false;\n if (Array.isArray(message.content)) {\n for (const part of message.content) {\n if (part.type === ContentTypes.TEXT && part.tool_call_ids) {\n /*\n If there's pending content, it needs to be aggregated as a single string to prepare for tool calls.\n For Anthropic models, the \"tool_calls\" field on a message is only respected if content is a string.\n */\n if (currentContent.length > 0) {\n let content = currentContent.reduce((acc, curr) => {\n if (curr.type === ContentTypes.TEXT) {\n return `${acc}${curr[ContentTypes.TEXT] || ''}\\n`;\n }\n return acc;\n }, '');\n content = `${content}\\n${part[ContentTypes.TEXT] ?? part.text ?? ''}`.trim();\n lastAIMessage = new AIMessage({ content });\n messages.push(lastAIMessage);\n currentContent = [];\n continue;\n }\n\n // Create a new AIMessage with this text and prepare for tool calls\n lastAIMessage = new AIMessage({\n content: part.text || '',\n });\n\n messages.push(lastAIMessage);\n } else if (part.type === ContentTypes.TOOL_CALL) {\n if (!lastAIMessage) {\n throw new Error('Invalid tool call structure: No preceding AIMessage with tool_call_ids');\n }\n\n // Note: `tool_calls` list is defined when constructed by `AIMessage` class, and outputs should be excluded from it\n const { output, args: _args, ...tool_call } = (part.tool_call as any);\n // TODO: investigate; args as dictionary may need to be providers-or-tool-specific\n let args: any = _args;\n try {\n if (typeof _args === 'string') {\n args = JSON.parse(_args);\n }\n } catch (e) {\n if (typeof _args === 'string') {\n args = { input: _args };\n }\n }\n\n tool_call.args = args;\n if (!lastAIMessage.tool_calls) {\n lastAIMessage.tool_calls = [];\n }\n lastAIMessage.tool_calls.push(tool_call as ToolCall);\n\n // Add the corresponding ToolMessage\n messages.push(\n new ToolMessage({\n tool_call_id: tool_call.id,\n name: tool_call.name,\n content: output || '',\n }),\n );\n } else if (part.type === ContentTypes.THINK) {\n hasReasoning = true;\n continue;\n } else if (part.type === ContentTypes.ERROR || part.type === ContentTypes.AGENT_UPDATE) {\n continue;\n } else {\n currentContent.push(part);\n }\n }\n }\n\n if (hasReasoning && currentContent.length > 0) {\n const content = currentContent\n .reduce((acc, curr) => {\n if (curr.type === ContentTypes.TEXT) {\n return `${acc}${curr[ContentTypes.TEXT] || ''}\\n`;\n }\n return acc;\n }, '')\n .trim();\n \n if (content) {\n messages.push(new AIMessage({ content }));\n }\n } else if (currentContent.length > 0) {\n messages.push(new AIMessage({ content: currentContent }));\n }\n \n // Update the index mapping for this assistant message\n // Store all indices that were created from this original message\n const endMessageIndex = messages.length;\n const resultIndices = [];\n for (let j = startMessageIndex; j < endMessageIndex; j++) {\n resultIndices.push(j);\n }\n indexMapping[i] = resultIndices;\n }\n\n // Update the token count map if it was provided\n if (indexTokenCountMap) {\n for (let originalIndex = 0; originalIndex < payload.length; originalIndex++) {\n const resultIndices = indexMapping[originalIndex] || [];\n const tokenCount = indexTokenCountMap[originalIndex];\n \n if (tokenCount !== undefined) {\n if (resultIndices.length === 1) {\n // Simple 1:1 mapping\n updatedIndexTokenCountMap[resultIndices[0]] = tokenCount;\n } else if (resultIndices.length > 1) {\n // If one message was split into multiple, distribute the token count\n // This is a simplification - in reality, you might want a more sophisticated distribution\n const countPerMessage = Math.floor(tokenCount / resultIndices.length);\n resultIndices.forEach((resultIndex, idx) => {\n if (idx === resultIndices.length - 1) {\n // Give any remainder to the last message\n updatedIndexTokenCountMap[resultIndex] = tokenCount - (countPerMessage * (resultIndices.length - 1));\n } else {\n updatedIndexTokenCountMap[resultIndex] = countPerMessage;\n }\n });\n }\n }\n }\n }\n\n return {\n messages,\n indexTokenCountMap: indexTokenCountMap ? updatedIndexTokenCountMap : undefined\n };\n};\n\n/**\n * Formats an array of messages for LangChain, making sure all content fields are strings\n * @param {Array<HumanMessage | AIMessage | SystemMessage | ToolMessage>} payload - The array of messages to format.\n * @returns {Array<HumanMessage | AIMessage | SystemMessage | ToolMessage>} - The array of formatted LangChain messages, including ToolMessages for tool calls.\n */\nexport const formatContentStrings = (payload: Array<BaseMessage>): Array<BaseMessage> => {\n // Create a copy of the payload to avoid modifying the original\n const result = [...payload];\n\n for (const message of result) {\n if (typeof message.content === 'string') {\n continue;\n }\n\n if (!Array.isArray(message.content)) {\n continue;\n }\n\n // Reduce text types to a single string, ignore all other types\n const content = message.content.reduce((acc, curr) => {\n if (curr.type === ContentTypes.TEXT) {\n return `${acc}${curr[ContentTypes.TEXT] || ''}\\n`;\n }\n return acc;\n }, '');\n\n message.content = content.trim();\n }\n\n return result;\n};\n\n/**\n * Adds a value at key 0 for system messages and shifts all key indices by one in an indexTokenCountMap.\n * This is useful when adding a system message at the beginning of a conversation.\n * \n * @param indexTokenCountMap - The original map of message indices to token counts\n * @param instructionsTokenCount - The token count for the system message to add at index 0\n * @returns A new map with the system message at index 0 and all other indices shifted by 1\n */\nexport function shiftIndexTokenCountMap(\n indexTokenCountMap: Record<number, number>,\n instructionsTokenCount: number\n): Record<number, number> {\n // Create a new map to avoid modifying the original\n const shiftedMap: Record<number, number> = {};\n \n // Add the system message token count at index 0\n shiftedMap[0] = instructionsTokenCount;\n \n // Shift all existing indices by 1\n for (const [indexStr, tokenCount] of Object.entries(indexTokenCountMap)) {\n const index = Number(indexStr);\n shiftedMap[index + 1] = tokenCount;\n }\n \n return shiftedMap;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"format.mjs","sources":["../../../src/messages/format.ts"],"sourcesContent":["import { ToolMessage, BaseMessage } from '@langchain/core/messages';\nimport { HumanMessage, AIMessage, SystemMessage, getBufferString } from '@langchain/core/messages';\nimport type { MessageContentImageUrl } from '@langchain/core/messages';\nimport type { ToolCall } from '@langchain/core/messages/tool';\nimport type { MessageContentComplex, ToolCallPart, TPayload, TMessage } from '@/types';\nimport { Providers, ContentTypes } from '@/common';\n\ninterface VisionMessageParams {\n message: {\n role: string;\n content: string;\n name?: string;\n [key: string]: any;\n };\n image_urls: MessageContentImageUrl[];\n endpoint?: Providers;\n}\n\n/**\n * Formats a message to OpenAI Vision API payload format.\n *\n * @param {VisionMessageParams} params - The parameters for formatting.\n * @returns {Object} - The formatted message.\n */\nexport const formatVisionMessage = ({ message, image_urls, endpoint }: VisionMessageParams): {\n role: string;\n content: MessageContentComplex[];\n name?: string;\n [key: string]: any;\n} => {\n // Create a new object to avoid mutating the input\n const result: {\n role: string;\n content: MessageContentComplex[];\n name?: string;\n [key: string]: any;\n } = {\n ...message,\n content: [] as MessageContentComplex[]\n };\n \n if (endpoint === Providers.ANTHROPIC) {\n result.content = [\n ...image_urls, \n { type: ContentTypes.TEXT, text: message.content }\n ] as MessageContentComplex[];\n return result;\n }\n\n result.content = [\n { type: ContentTypes.TEXT, text: message.content }, \n ...image_urls\n ] as MessageContentComplex[];\n\n return result;\n};\n\ninterface MessageInput {\n role?: string;\n _name?: string;\n sender?: string;\n text?: string;\n content?: string | MessageContentComplex[];\n image_urls?: MessageContentImageUrl[];\n lc_id?: string[];\n [key: string]: any;\n}\n\ninterface FormatMessageParams {\n message: MessageInput;\n userName?: string;\n assistantName?: string;\n endpoint?: Providers;\n langChain?: boolean;\n}\n\ninterface FormattedMessage {\n role: string;\n content: string | MessageContentComplex[];\n name?: string;\n [key: string]: any;\n}\n\n/**\n * Formats a message to OpenAI payload format based on the provided options.\n *\n * @param {FormatMessageParams} params - The parameters for formatting.\n * @returns {FormattedMessage | HumanMessage | AIMessage | SystemMessage} - The formatted message.\n */\nexport const formatMessage = ({ \n message, \n userName, \n assistantName, \n endpoint, \n langChain = false \n}: FormatMessageParams): FormattedMessage | HumanMessage | AIMessage | SystemMessage => {\n let { role: _role, _name, sender, text, content: _content, lc_id } = message;\n if (lc_id && lc_id[2] && !langChain) {\n const roleMapping: Record<string, string> = {\n SystemMessage: 'system',\n HumanMessage: 'user',\n AIMessage: 'assistant',\n };\n _role = roleMapping[lc_id[2]] || _role;\n }\n const role = _role ?? (sender && sender?.toLowerCase() === 'user' ? 'user' : 'assistant');\n const content = _content ?? text ?? '';\n const formattedMessage: FormattedMessage = {\n role,\n content,\n };\n\n const { image_urls } = message;\n if (Array.isArray(image_urls) && image_urls.length > 0 && role === 'user') {\n return formatVisionMessage({\n message: {\n ...formattedMessage,\n content: typeof formattedMessage.content === 'string' ? formattedMessage.content : ''\n },\n image_urls,\n endpoint,\n });\n }\n\n if (_name) {\n formattedMessage.name = _name;\n }\n\n if (userName && formattedMessage.role === 'user') {\n formattedMessage.name = userName;\n }\n\n if (assistantName && formattedMessage.role === 'assistant') {\n formattedMessage.name = assistantName;\n }\n\n if (formattedMessage.name) {\n // Conform to API regex: ^[a-zA-Z0-9_-]{1,64}$\n // https://community.openai.com/t/the-format-of-the-name-field-in-the-documentation-is-incorrect/175684/2\n formattedMessage.name = formattedMessage.name.replace(/[^a-zA-Z0-9_-]/g, '_');\n\n if (formattedMessage.name.length > 64) {\n formattedMessage.name = formattedMessage.name.substring(0, 64);\n }\n }\n\n if (!langChain) {\n return formattedMessage;\n }\n\n if (role === 'user') {\n return new HumanMessage(formattedMessage);\n } else if (role === 'assistant') {\n return new AIMessage(formattedMessage);\n } else {\n return new SystemMessage(formattedMessage);\n }\n};\n\n/**\n * Formats an array of messages for LangChain.\n *\n * @param {Array<MessageInput>} messages - The array of messages to format.\n * @param {Omit<FormatMessageParams, 'message' | 'langChain'>} formatOptions - The options for formatting each message.\n * @returns {Array<HumanMessage | AIMessage | SystemMessage>} - The array of formatted LangChain messages.\n */\nexport const formatLangChainMessages = (\n messages: Array<MessageInput>, \n formatOptions: Omit<FormatMessageParams, 'message' | 'langChain'>\n): Array<HumanMessage | AIMessage | SystemMessage> => {\n return messages.map((msg) => {\n const formatted = formatMessage({ ...formatOptions, message: msg, langChain: true });\n return formatted as HumanMessage | AIMessage | SystemMessage;\n });\n};\n\ninterface LangChainMessage {\n lc_kwargs?: {\n additional_kwargs?: Record<string, any>;\n [key: string]: any;\n };\n kwargs?: {\n additional_kwargs?: Record<string, any>;\n [key: string]: any;\n };\n [key: string]: any;\n}\n\n/**\n * Formats a LangChain message object by merging properties from `lc_kwargs` or `kwargs` and `additional_kwargs`.\n *\n * @param {LangChainMessage} message - The message object to format.\n * @returns {Record<string, any>} The formatted LangChain message.\n */\nexport const formatFromLangChain = (message: LangChainMessage): Record<string, any> => {\n const kwargs = message.lc_kwargs ?? message.kwargs ?? {};\n const { additional_kwargs = {}, ...message_kwargs } = kwargs;\n return {\n ...message_kwargs,\n ...additional_kwargs,\n };\n};\n\n/**\n * Helper function to format an assistant message\n * @param message The message to format\n * @returns Array of formatted messages\n */\nfunction formatAssistantMessage(message: Partial<TMessage>): Array<AIMessage | ToolMessage> {\n const formattedMessages: Array<AIMessage | ToolMessage> = [];\n let currentContent: MessageContentComplex[] = [];\n let lastAIMessage: AIMessage | null = null;\n let hasReasoning = false;\n\n if (Array.isArray(message.content)) {\n for (const part of message.content) {\n if (part.type === ContentTypes.TEXT && part.tool_call_ids) {\n /*\n If there's pending content, it needs to be aggregated as a single string to prepare for tool calls.\n For Anthropic models, the \"tool_calls\" field on a message is only respected if content is a string.\n */\n if (currentContent.length > 0) {\n let content = currentContent.reduce((acc, curr) => {\n if (curr.type === ContentTypes.TEXT) {\n return `${acc}${curr[ContentTypes.TEXT] || ''}\\n`;\n }\n return acc;\n }, '');\n content = `${content}\\n${part[ContentTypes.TEXT] ?? part.text ?? ''}`.trim();\n lastAIMessage = new AIMessage({ content });\n formattedMessages.push(lastAIMessage);\n currentContent = [];\n continue;\n }\n // Create a new AIMessage with this text and prepare for tool calls\n lastAIMessage = new AIMessage({\n content: part.text || '',\n });\n formattedMessages.push(lastAIMessage);\n } else if (part?.type === ContentTypes.TOOL_CALL) {\n if (!lastAIMessage) {\n throw new Error('Invalid tool call structure: No preceding AIMessage with tool_call_ids');\n }\n\n // Note: `tool_calls` list is defined when constructed by `AIMessage` class, and outputs should be excluded from it\n const { output, args: _args, ..._tool_call } = (part.tool_call as ToolCallPart);\n const tool_call: ToolCallPart = _tool_call;\n // TODO: investigate; args as dictionary may need to be providers-or-tool-specific\n let args: any = _args;\n try {\n if (typeof _args === 'string') {\n args = JSON.parse(_args);\n }\n } catch (e) {\n if (typeof _args === 'string') {\n args = { input: _args };\n }\n }\n\n tool_call.args = args;\n if (!lastAIMessage.tool_calls) {\n lastAIMessage.tool_calls = [];\n }\n lastAIMessage.tool_calls.push(tool_call as ToolCall);\n\n formattedMessages.push(\n new ToolMessage({\n tool_call_id: tool_call.id ?? '',\n name: tool_call.name,\n content: output || '',\n }),\n );\n } else if (part.type === ContentTypes.THINK) {\n hasReasoning = true;\n continue;\n } else if (part.type === ContentTypes.ERROR || part.type === ContentTypes.AGENT_UPDATE) {\n continue;\n } else {\n currentContent.push(part);\n }\n }\n }\n\n if (hasReasoning && currentContent.length > 0) {\n const content = currentContent\n .reduce((acc, curr) => {\n if (curr.type === ContentTypes.TEXT) {\n return `${acc}${curr[ContentTypes.TEXT] || ''}\\n`;\n }\n return acc;\n }, '')\n .trim();\n \n if (content) {\n formattedMessages.push(new AIMessage({ content }));\n }\n } else if (currentContent.length > 0) {\n formattedMessages.push(new AIMessage({ content: currentContent }));\n }\n\n return formattedMessages;\n}\n\n/**\n * Formats an array of messages for LangChain, handling tool calls and creating ToolMessage instances.\n *\n * @param {TPayload} payload - The array of messages to format.\n * @param {Record<number, number>} [indexTokenCountMap] - Optional map of message indices to token counts.\n * @param {Set<string>} [tools] - Optional set of tool names that are allowed in the request.\n * @returns {Object} - Object containing formatted messages and updated indexTokenCountMap if provided.\n */\nexport const formatAgentMessages = (\n payload: TPayload, \n indexTokenCountMap?: Record<number, number>,\n tools?: Set<string>\n): {\n messages: Array<HumanMessage | AIMessage | SystemMessage | ToolMessage>;\n indexTokenCountMap?: Record<number, number>;\n} => {\n const messages: Array<HumanMessage | AIMessage | SystemMessage | ToolMessage> = [];\n // If indexTokenCountMap is provided, create a new map to track the updated indices\n const updatedIndexTokenCountMap: Record<number, number> = {};\n // Keep track of the mapping from original payload indices to result indices\n const indexMapping: Record<number, number[]> = {};\n\n // Process messages with tool conversion if tools set is provided\n for (let i = 0; i < payload.length; i++) {\n const message = payload[i];\n // Q: Store the current length of messages to track where this payload message starts in the result?\n // const startIndex = messages.length;\n if (typeof message.content === 'string') {\n message.content = [{ type: ContentTypes.TEXT, [ContentTypes.TEXT]: message.content }];\n }\n if (message.role !== 'assistant') {\n messages.push(formatMessage({ \n message: message as MessageInput, \n langChain: true \n }) as HumanMessage | AIMessage | SystemMessage);\n \n // Update the index mapping for this message\n indexMapping[i] = [messages.length - 1];\n continue;\n }\n\n // For assistant messages, track the starting index before processing\n const startMessageIndex = messages.length;\n\n // If tools set is provided, we need to check if we need to convert tool messages to a string\n if (tools) {\n // First, check if this message contains tool calls\n let hasToolCalls = false;\n let hasInvalidTool = false;\n let toolNames: string[] = [];\n \n const content = message.content;\n if (content && Array.isArray(content)) {\n for (const part of content) {\n if (part?.type === ContentTypes.TOOL_CALL) {\n hasToolCalls = true;\n if (tools.size === 0) {\n hasInvalidTool = true;\n break;\n }\n const toolName = part.tool_call.name;\n toolNames.push(toolName);\n if (!tools.has(toolName)) {\n hasInvalidTool = true;\n }\n }\n }\n }\n \n // If this message has tool calls and at least one is invalid, we need to convert it\n if (hasToolCalls && hasInvalidTool) {\n // We need to collect all related messages (this message and any subsequent tool messages)\n const toolSequence: BaseMessage[] = [];\n let sequenceEndIndex = i;\n \n // Process the current assistant message to get the AIMessage with tool calls\n const formattedMessages = formatAssistantMessage(message);\n toolSequence.push(...formattedMessages);\n \n // Look ahead for any subsequent assistant messages that might be part of this tool sequence\n let j = i + 1;\n while (j < payload.length && payload[j].role === 'assistant') {\n // Check if this is a continuation of the tool sequence\n let isToolResponse = false;\n const content = payload[j].content;\n if (content && Array.isArray(content)) {\n for (const part of content) {\n if (part?.type === ContentTypes.TOOL_CALL) {\n isToolResponse = true;\n break;\n }\n }\n }\n \n if (isToolResponse) {\n // This is part of the tool sequence, add it\n const nextMessages = formatAssistantMessage(payload[j]);\n toolSequence.push(...nextMessages);\n sequenceEndIndex = j;\n j++;\n } else {\n // This is not part of the tool sequence, stop looking\n break;\n }\n }\n \n // Convert the sequence to a string\n const bufferString = getBufferString(toolSequence);\n messages.push(new AIMessage({ content: bufferString }));\n \n // Skip the messages we've already processed\n i = sequenceEndIndex;\n \n // Update the index mapping for this sequence\n const resultIndices = [messages.length - 1];\n for (let k = i; k >= i && k <= sequenceEndIndex; k++) {\n indexMapping[k] = resultIndices;\n }\n \n continue;\n }\n }\n\n // Process the assistant message using the helper function\n const formattedMessages = formatAssistantMessage(message);\n messages.push(...formattedMessages);\n \n // Update the index mapping for this assistant message\n // Store all indices that were created from this original message\n const endMessageIndex = messages.length;\n const resultIndices = [];\n for (let j = startMessageIndex; j < endMessageIndex; j++) {\n resultIndices.push(j);\n }\n indexMapping[i] = resultIndices;\n }\n\n // Update the token count map if it was provided\n if (indexTokenCountMap) {\n for (let originalIndex = 0; originalIndex < payload.length; originalIndex++) {\n const resultIndices = indexMapping[originalIndex] || [];\n const tokenCount = indexTokenCountMap[originalIndex];\n \n if (tokenCount !== undefined) {\n if (resultIndices.length === 1) {\n // Simple 1:1 mapping\n updatedIndexTokenCountMap[resultIndices[0]] = tokenCount;\n } else if (resultIndices.length > 1) {\n // If one message was split into multiple, distribute the token count\n // This is a simplification - in reality, you might want a more sophisticated distribution\n const countPerMessage = Math.floor(tokenCount / resultIndices.length);\n resultIndices.forEach((resultIndex, idx) => {\n if (idx === resultIndices.length - 1) {\n // Give any remainder to the last message\n updatedIndexTokenCountMap[resultIndex] = tokenCount - (countPerMessage * (resultIndices.length - 1));\n } else {\n updatedIndexTokenCountMap[resultIndex] = countPerMessage;\n }\n });\n }\n }\n }\n }\n\n return {\n messages,\n indexTokenCountMap: indexTokenCountMap ? updatedIndexTokenCountMap : undefined\n };\n};\n\n/**\n * Formats an array of messages for LangChain, making sure all content fields are strings\n * @param {Array<HumanMessage | AIMessage | SystemMessage | ToolMessage>} payload - The array of messages to format.\n * @returns {Array<HumanMessage | AIMessage | SystemMessage | ToolMessage>} - The array of formatted LangChain messages, including ToolMessages for tool calls.\n */\nexport const formatContentStrings = (payload: Array<BaseMessage>): Array<BaseMessage> => {\n // Create a copy of the payload to avoid modifying the original\n const result = [...payload];\n\n for (const message of result) {\n if (typeof message.content === 'string') {\n continue;\n }\n\n if (!Array.isArray(message.content)) {\n continue;\n }\n\n // Reduce text types to a single string, ignore all other types\n const content = message.content.reduce((acc, curr) => {\n if (curr.type === ContentTypes.TEXT) {\n return `${acc}${curr[ContentTypes.TEXT] || ''}\\n`;\n }\n return acc;\n }, '');\n\n message.content = content.trim();\n }\n\n return result;\n};\n\n/**\n * Adds a value at key 0 for system messages and shifts all key indices by one in an indexTokenCountMap.\n * This is useful when adding a system message at the beginning of a conversation.\n * \n * @param indexTokenCountMap - The original map of message indices to token counts\n * @param instructionsTokenCount - The token count for the system message to add at index 0\n * @returns A new map with the system message at index 0 and all other indices shifted by 1\n */\nexport function shiftIndexTokenCountMap(\n indexTokenCountMap: Record<number, number>,\n instructionsTokenCount: number\n): Record<number, number> {\n // Create a new map to avoid modifying the original\n const shiftedMap: Record<number, number> = {};\n shiftedMap[0] = instructionsTokenCount;\n \n // Shift all existing indices by 1\n for (const [indexStr, tokenCount] of Object.entries(indexTokenCountMap)) {\n const index = Number(indexStr);\n shiftedMap[index + 1] = tokenCount;\n }\n \n return shiftedMap;\n}\n"],"names":[],"mappings":"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"}
@@ -11,13 +11,15 @@ class ToolNode extends RunnableCallable {
11
11
  loadRuntimeTools;
12
12
  handleToolErrors = true;
13
13
  toolCallStepIds;
14
- constructor({ tools, toolMap, name, tags, toolCallStepIds, handleToolErrors, loadRuntimeTools, }) {
14
+ errorHandler;
15
+ constructor({ tools, toolMap, name, tags, errorHandler, toolCallStepIds, handleToolErrors, loadRuntimeTools, }) {
15
16
  super({ name, tags, func: (input, config) => this.run(input, config) });
16
17
  this.tools = tools;
17
18
  this.toolMap = toolMap ?? new Map(tools.map(tool => [tool.name, tool]));
18
19
  this.toolCallStepIds = toolCallStepIds;
19
20
  this.handleToolErrors = handleToolErrors ?? this.handleToolErrors;
20
21
  this.loadRuntimeTools = loadRuntimeTools;
22
+ this.errorHandler = errorHandler;
21
23
  }
22
24
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
23
25
  async run(input, config) {
@@ -61,6 +63,12 @@ class ToolNode extends RunnableCallable {
61
63
  if (isGraphInterrupt(e)) {
62
64
  throw e;
63
65
  }
66
+ this.errorHandler?.({
67
+ error: e,
68
+ id: call.id,
69
+ name: call.name,
70
+ input: call.args,
71
+ }, config?.metadata);
64
72
  return new ToolMessage({
65
73
  content: `Error: ${e.message}\n Please fix your mistakes.`,
66
74
  name: call.name,
@@ -1 +1 @@
1
- {"version":3,"file":"ToolNode.mjs","sources":["../../../src/tools/ToolNode.ts"],"sourcesContent":["import { END, MessagesAnnotation, isCommand, isGraphInterrupt } from '@langchain/langgraph';\nimport { ToolMessage, isBaseMessage } from '@langchain/core/messages';\nimport type { RunnableConfig, RunnableToolLike } from '@langchain/core/runnables';\nimport type { BaseMessage, AIMessage } from '@langchain/core/messages';\nimport type { StructuredToolInterface } from '@langchain/core/tools';\nimport type * as t from '@/types';\nimport{ RunnableCallable } from '@/utils';\nimport { GraphNodeKeys } from '@/common';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class ToolNode<T = any> extends RunnableCallable<T, T> {\n tools: t.GenericTool[];\n private toolMap: Map<string, StructuredToolInterface | RunnableToolLike>;\n private loadRuntimeTools?: t.ToolRefGenerator;\n handleToolErrors = true;\n toolCallStepIds?: Map<string, string>;\n\n constructor({\n tools,\n toolMap,\n name,\n tags,\n toolCallStepIds,\n handleToolErrors,\n loadRuntimeTools,\n }: t.ToolNodeConstructorParams) {\n super({ name, tags, func: (input, config) => this.run(input, config) });\n this.tools = tools;\n this.toolMap = toolMap ?? new Map(tools.map(tool => [tool.name, tool]));\n this.toolCallStepIds = toolCallStepIds;\n this.handleToolErrors = handleToolErrors ?? this.handleToolErrors;\n this.loadRuntimeTools = loadRuntimeTools;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n protected async run(input: any, config: RunnableConfig): Promise<T> {\n const message = Array.isArray(input)\n ? input[input.length - 1]\n : input.messages[input.messages.length - 1];\n\n if (message._getType() !== 'ai') {\n throw new Error('ToolNode only accepts AIMessages as input.');\n }\n\n if (this.loadRuntimeTools) {\n const { tools, toolMap } = this.loadRuntimeTools(\n (message as AIMessage).tool_calls ?? []\n );\n this.tools = tools;\n this.toolMap = toolMap ?? new Map(tools.map(tool => [tool.name, tool]));\n }\n const outputs = await Promise.all(\n (message as AIMessage).tool_calls?.map(async (call) => {\n const tool = this.toolMap.get(call.name);\n try {\n if (tool === undefined) {\n throw new Error(`Tool \"${call.name}\" not found.`);\n }\n const args = call.args;\n const stepId = this.toolCallStepIds?.get(call.id!);\n const output = await tool.invoke(\n { ...call, args, type: 'tool_call', stepId },\n config,\n );\n if (\n (isBaseMessage(output) && output._getType() === 'tool') ||\n isCommand(output)\n ) {\n return output;\n } else {\n return new ToolMessage({\n name: tool.name,\n content:\n typeof output === 'string' ? output : JSON.stringify(output),\n tool_call_id: call.id!,\n });\n }\n } catch (_e: unknown) {\n const e = _e as Error;\n if (!this.handleToolErrors) {\n throw e;\n }\n if (isGraphInterrupt(e)) {\n throw e;\n }\n return new ToolMessage({\n content: `Error: ${e.message}\\n Please fix your mistakes.`,\n name: call.name,\n tool_call_id: call.id ?? '',\n });\n }\n }) ?? []\n );\n\n if (!outputs.some(isCommand)) {\n return (Array.isArray(input) ? outputs : { messages: outputs }) as T;\n }\n\n const combinedOutputs = outputs.map((output) => {\n if (isCommand(output)) {\n return output;\n }\n return Array.isArray(input) ? [output] : { messages: [output] };\n });\n return combinedOutputs as T;\n }\n}\n\nexport function toolsCondition(\n state: BaseMessage[] | typeof MessagesAnnotation.State\n): 'tools' | typeof END {\n const message = Array.isArray(state)\n ? state[state.length - 1]\n : state.messages[state.messages.length - 1];\n\n if (\n 'tool_calls' in message &&\n ((message as AIMessage).tool_calls?.length ?? 0) > 0\n ) {\n return GraphNodeKeys.TOOLS;\n } else {\n return END;\n }\n}"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ToolNode.mjs","sources":["../../../src/tools/ToolNode.ts"],"sourcesContent":["import { END, MessagesAnnotation, isCommand, isGraphInterrupt } from '@langchain/langgraph';\nimport { ToolMessage, isBaseMessage } from '@langchain/core/messages';\nimport type { RunnableConfig, RunnableToolLike } from '@langchain/core/runnables';\nimport type { BaseMessage, AIMessage } from '@langchain/core/messages';\nimport type { StructuredToolInterface } from '@langchain/core/tools';\nimport type * as t from '@/types';\nimport{ RunnableCallable } from '@/utils';\nimport { GraphNodeKeys } from '@/common';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport class ToolNode<T = any> extends RunnableCallable<T, T> {\n tools: t.GenericTool[];\n private toolMap: Map<string, StructuredToolInterface | RunnableToolLike>;\n private loadRuntimeTools?: t.ToolRefGenerator;\n handleToolErrors = true;\n toolCallStepIds?: Map<string, string>;\n errorHandler?: t.ToolNodeConstructorParams['errorHandler'];\n\n constructor({\n tools,\n toolMap,\n name,\n tags,\n errorHandler,\n toolCallStepIds,\n handleToolErrors,\n loadRuntimeTools,\n }: t.ToolNodeConstructorParams) {\n super({ name, tags, func: (input, config) => this.run(input, config) });\n this.tools = tools;\n this.toolMap = toolMap ?? new Map(tools.map(tool => [tool.name, tool]));\n this.toolCallStepIds = toolCallStepIds;\n this.handleToolErrors = handleToolErrors ?? this.handleToolErrors;\n this.loadRuntimeTools = loadRuntimeTools;\n this.errorHandler = errorHandler;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n protected async run(input: any, config: RunnableConfig): Promise<T> {\n const message = Array.isArray(input)\n ? input[input.length - 1]\n : input.messages[input.messages.length - 1];\n\n if (message._getType() !== 'ai') {\n throw new Error('ToolNode only accepts AIMessages as input.');\n }\n\n if (this.loadRuntimeTools) {\n const { tools, toolMap } = this.loadRuntimeTools(\n (message as AIMessage).tool_calls ?? []\n );\n this.tools = tools;\n this.toolMap = toolMap ?? new Map(tools.map(tool => [tool.name, tool]));\n }\n const outputs = await Promise.all(\n (message as AIMessage).tool_calls?.map(async (call) => {\n const tool = this.toolMap.get(call.name);\n try {\n if (tool === undefined) {\n throw new Error(`Tool \"${call.name}\" not found.`);\n }\n const args = call.args;\n const stepId = this.toolCallStepIds?.get(call.id!);\n const output = await tool.invoke(\n { ...call, args, type: 'tool_call', stepId },\n config,\n );\n if (\n (isBaseMessage(output) && output._getType() === 'tool') ||\n isCommand(output)\n ) {\n return output;\n } else {\n return new ToolMessage({\n name: tool.name,\n content:\n typeof output === 'string' ? output : JSON.stringify(output),\n tool_call_id: call.id!,\n });\n }\n } catch (_e: unknown) {\n const e = _e as Error;\n if (!this.handleToolErrors) {\n throw e;\n }\n if (isGraphInterrupt(e)) {\n throw e;\n }\n this.errorHandler?.({\n error: e,\n id: call.id!,\n name: call.name,\n input: call.args,\n }, config?.metadata);\n return new ToolMessage({\n content: `Error: ${e.message}\\n Please fix your mistakes.`,\n name: call.name,\n tool_call_id: call.id ?? '',\n });\n }\n }) ?? []\n );\n\n if (!outputs.some(isCommand)) {\n return (Array.isArray(input) ? outputs : { messages: outputs }) as T;\n }\n\n const combinedOutputs = outputs.map((output) => {\n if (isCommand(output)) {\n return output;\n }\n return Array.isArray(input) ? [output] : { messages: [output] };\n });\n return combinedOutputs as T;\n }\n}\n\nexport function toolsCondition(\n state: BaseMessage[] | typeof MessagesAnnotation.State\n): 'tools' | typeof END {\n const message = Array.isArray(state)\n ? state[state.length - 1]\n : state.messages[state.messages.length - 1];\n\n if (\n 'tool_calls' in message &&\n ((message as AIMessage).tool_calls?.length ?? 0) > 0\n ) {\n return GraphNodeKeys.TOOLS;\n } else {\n return END;\n }\n}"],"names":[],"mappings":"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"}
@@ -5,6 +5,7 @@ import { SystemMessage } from '@langchain/core/messages';
5
5
  import type { BaseMessage, UsageMetadata } from '@langchain/core/messages';
6
6
  import type * as t from '@/types';
7
7
  import { Providers, GraphNodeKeys, Callback, ContentTypes } from '@/common';
8
+ import type { ToolCall } from '@langchain/core/messages/tool';
8
9
  import { ToolNode as CustomToolNode } from '@/tools/ToolNode';
9
10
  import { createPruneMessages } from '@/messages';
10
11
  import { HandlerRegistry } from '@/events';
@@ -88,7 +89,7 @@ export declare class StandardGraph extends Graph<t.BaseGraphState, GraphNode> {
88
89
  createGraphState(): t.GraphStateChannels<t.BaseGraphState>;
89
90
  initializeTools(): CustomToolNode<t.BaseGraphState> | ToolNode<t.BaseGraphState>;
90
91
  initializeModel(): Runnable;
91
- overrideTestModel(responses: string[], sleep?: number): void;
92
+ overrideTestModel(responses: string[], sleep?: number, toolCalls?: ToolCall[]): void;
92
93
  getNewModel({ clientOptions, omitOriginalOptions, }: {
93
94
  clientOptions?: t.ClientOptions;
94
95
  omitOriginalOptions?: string[];
@@ -101,6 +102,7 @@ export declare class StandardGraph extends Graph<t.BaseGraphState, GraphNode> {
101
102
  */
102
103
  dispatchRunStep(stepKey: string, stepDetails: t.StepDetails): string;
103
104
  handleToolCallCompleted(data: t.ToolEndData, metadata?: Record<string, unknown>): void;
105
+ handleToolCallError(data: t.ToolErrorData, metadata?: Record<string, unknown>): void;
104
106
  dispatchRunStepDelta(id: string, delta: t.ToolCallDelta): void;
105
107
  dispatchMessageDelta(id: string, delta: t.MessageDelta): void;
106
108
  dispatchReasoningDelta: (stepId: string, delta: t.ReasoningDelta) => void;
@@ -1,21 +1,31 @@
1
- import type { BaseMessage } from '@langchain/core/messages';
2
- import type { ChatGenerationChunk } from '@langchain/core/outputs';
1
+ import { ChatGenerationChunk } from '@langchain/core/outputs';
3
2
  import type { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';
3
+ import type { BaseMessage } from '@langchain/core/messages';
4
4
  import { FakeListChatModel } from '@langchain/core/utils/testing';
5
+ import { ToolCall, ToolCallChunk } from '@langchain/core/messages/tool';
5
6
  type SplitStrategy = {
6
7
  type: 'regex' | 'fixed';
7
8
  value: RegExp | number;
8
9
  };
9
10
  export declare class FakeChatModel extends FakeListChatModel {
10
11
  private splitStrategy;
11
- constructor({ responses, sleep, emitCustomEvent, splitStrategy }: {
12
+ private toolCalls;
13
+ private addedToolCalls;
14
+ constructor({ responses, sleep, emitCustomEvent, splitStrategy, toolCalls }: {
12
15
  responses: string[];
13
16
  sleep?: number;
14
17
  emitCustomEvent?: boolean;
15
18
  splitStrategy?: SplitStrategy;
19
+ toolCalls?: ToolCall[];
16
20
  });
17
21
  private splitText;
22
+ _createResponseChunk(text: string, tool_call_chunks?: ToolCallChunk[]): ChatGenerationChunk;
18
23
  _streamResponseChunks(_messages: BaseMessage[], options: this['ParsedCallOptions'], runManager?: CallbackManagerForLLMRun): AsyncGenerator<ChatGenerationChunk>;
19
24
  }
20
- export declare function createFakeStreamingLLM(responses: string[], sleep?: number, splitStrategy?: SplitStrategy): FakeChatModel;
25
+ export declare function createFakeStreamingLLM({ responses, sleep, splitStrategy, toolCalls, }: {
26
+ responses: string[];
27
+ sleep?: number;
28
+ splitStrategy?: SplitStrategy;
29
+ toolCalls?: ToolCall[];
30
+ }): FakeChatModel;
21
31
  export {};
@@ -1,8 +1,8 @@
1
1
  import { ToolMessage, BaseMessage } from '@langchain/core/messages';
2
2
  import { HumanMessage, AIMessage, SystemMessage } from '@langchain/core/messages';
3
- import { MessageContentImageUrl } from '@langchain/core/messages';
4
- import type { MessageContentComplex } from '@/types';
5
- import { Providers, ContentTypes } from '@/common';
3
+ import type { MessageContentImageUrl } from '@langchain/core/messages';
4
+ import type { MessageContentComplex, TPayload } from '@/types';
5
+ import { Providers } from '@/common';
6
6
  interface VisionMessageParams {
7
7
  message: {
8
8
  role: string;
@@ -81,24 +81,15 @@ interface LangChainMessage {
81
81
  * @returns {Record<string, any>} The formatted LangChain message.
82
82
  */
83
83
  export declare const formatFromLangChain: (message: LangChainMessage) => Record<string, any>;
84
- interface TMessage {
85
- role?: string;
86
- content?: string | Array<{
87
- type: ContentTypes;
88
- text?: string;
89
- tool_call_ids?: string[];
90
- [key: string]: any;
91
- }>;
92
- [key: string]: any;
93
- }
94
84
  /**
95
85
  * Formats an array of messages for LangChain, handling tool calls and creating ToolMessage instances.
96
86
  *
97
- * @param {Array<Partial<TMessage>>} payload - The array of messages to format.
87
+ * @param {TPayload} payload - The array of messages to format.
98
88
  * @param {Record<number, number>} [indexTokenCountMap] - Optional map of message indices to token counts.
89
+ * @param {Set<string>} [tools] - Optional set of tool names that are allowed in the request.
99
90
  * @returns {Object} - Object containing formatted messages and updated indexTokenCountMap if provided.
100
91
  */
101
- export declare const formatAgentMessages: (payload: Array<Partial<TMessage>>, indexTokenCountMap?: Record<number, number>) => {
92
+ export declare const formatAgentMessages: (payload: TPayload, indexTokenCountMap?: Record<number, number>, tools?: Set<string>) => {
102
93
  messages: Array<HumanMessage | AIMessage | SystemMessage | ToolMessage>;
103
94
  indexTokenCountMap?: Record<number, number>;
104
95
  };
@@ -9,7 +9,8 @@ export declare class ToolNode<T = any> extends RunnableCallable<T, T> {
9
9
  private loadRuntimeTools?;
10
10
  handleToolErrors: boolean;
11
11
  toolCallStepIds?: Map<string, string>;
12
- constructor({ tools, toolMap, name, tags, toolCallStepIds, handleToolErrors, loadRuntimeTools, }: t.ToolNodeConstructorParams);
12
+ errorHandler?: t.ToolNodeConstructorParams['errorHandler'];
13
+ constructor({ tools, toolMap, name, tags, errorHandler, toolCallStepIds, handleToolErrors, loadRuntimeTools, }: t.ToolNodeConstructorParams);
13
14
  protected run(input: any, config: RunnableConfig): Promise<T>;
14
15
  }
15
16
  export declare function toolsCondition(state: BaseMessage[] | typeof MessagesAnnotation.State): 'tools' | typeof END;
@@ -66,6 +66,11 @@ export type ToolEndData = {
66
66
  input: string | Record<string, unknown>;
67
67
  output?: ToolMessage;
68
68
  };
69
+ export type ToolErrorData = {
70
+ id: string;
71
+ name: string;
72
+ error?: Error;
73
+ } & Pick<ToolEndData, 'input'>;
69
74
  export type ToolEndCallback = (data: ToolEndData, metadata?: Record<string, unknown>) => void;
70
75
  export type ProcessedToolCall = {
71
76
  name: string;
@@ -202,13 +207,42 @@ export type BedrockReasoningContentText = {
202
207
  signature?: string;
203
208
  };
204
209
  };
205
- export type MessageContentComplex = (ThinkingContentText | AgentUpdate | ReasoningContentText | MessageContentText | MessageContentImageUrl | (Record<string, any> & {
210
+ /**
211
+ * A call to a tool.
212
+ */
213
+ export type ToolCallPart = {
214
+ /** Type ("tool_call") according to Assistants Tool Call Structure */
215
+ type: ContentTypes.TOOL_CALL;
216
+ /** The name of the tool to be called */
217
+ name: string;
218
+ /** The arguments to the tool call */
219
+ args?: string | Record<string, any>;
220
+ /** If provided, an identifier associated with the tool call */
221
+ id?: string;
222
+ /** If provided, the output of the tool call */
223
+ output?: string;
224
+ /** Auth URL */
225
+ auth?: string;
226
+ /** Expiration time */
227
+ expires_at?: number;
228
+ };
229
+ export type ToolCallContent = {
230
+ type: ContentTypes.TOOL_CALL;
231
+ tool_call?: ToolCallPart;
232
+ };
233
+ export type MessageContentComplex = (ThinkingContentText | AgentUpdate | ToolCallContent | ReasoningContentText | MessageContentText | MessageContentImageUrl | (Record<string, any> & {
206
234
  type?: 'text' | 'image_url' | 'think' | 'thinking' | string;
207
235
  }) | (Record<string, any> & {
208
236
  type?: never;
209
237
  })) & {
210
238
  tool_call_ids?: string[];
211
239
  };
240
+ export interface TMessage {
241
+ role?: string;
242
+ content?: MessageContentComplex[] | string;
243
+ [key: string]: any;
244
+ }
245
+ export type TPayload = Array<Partial<TMessage>>;
212
246
  export type CustomChunk = Partial<OpenAITypes.ChatCompletionChunk> & {
213
247
  choices?: Partial<Array<Partial<OpenAITypes.Chat.Completions.ChatCompletionChunk.Choice> & {
214
248
  delta?: Partial<OpenAITypes.Chat.Completions.ChatCompletionChunk.Choice.Delta> & {
@@ -1,7 +1,8 @@
1
1
  import type { RunnableToolLike } from '@langchain/core/runnables';
2
2
  import type { StructuredToolInterface } from '@langchain/core/tools';
3
3
  import type { ToolCall } from '@langchain/core/messages/tool';
4
- import { ContentTypes, EnvVar } from '@/common';
4
+ import type { ToolErrorData } from './stream';
5
+ import { EnvVar } from '@/common';
5
6
  /** Replacement type for `import type { ToolCall } from '@langchain/core/messages/tool'` in order to have stringified args typed */
6
7
  export type CustomToolCall = {
7
8
  name: string;
@@ -23,6 +24,7 @@ export type ToolNodeOptions = {
23
24
  handleToolErrors?: boolean;
24
25
  loadRuntimeTools?: ToolRefGenerator;
25
26
  toolCallStepIds?: Map<string, string>;
27
+ errorHandler?: (data: ToolErrorData, metadata?: Record<string, unknown>) => void;
26
28
  };
27
29
  export type ToolNodeConstructorParams = ToolRefs & ToolNodeOptions;
28
30
  export type ToolEndEvent = {
@@ -33,10 +35,6 @@ export type ToolEndEvent = {
33
35
  /** The content index of the tool call */
34
36
  index: number;
35
37
  };
36
- export type ToolCallContent = {
37
- type: ContentTypes.TOOL_CALL;
38
- tool_call: ToolCall;
39
- };
40
38
  export type CodeEnvFile = {
41
39
  id: string;
42
40
  name: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@librechat/agents",
3
- "version": "2.2.5",
3
+ "version": "2.2.7",
4
4
  "main": "./dist/cjs/main.cjs",
5
5
  "module": "./dist/esm/main.mjs",
6
6
  "types": "./dist/types/index.d.ts",
@@ -43,7 +43,7 @@
43
43
  "content": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/content.ts --provider 'anthropic' --name 'Jo' --location 'New York, NY'",
44
44
  "stream": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/stream.ts --provider 'anthropic' --name 'Jo' --location 'New York, NY'",
45
45
  "code_exec": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/code_exec.ts --provider 'google' --name 'Jo' --location 'New York, NY'",
46
- "image": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/image.ts --provider 'vertexai' --name 'Jo' --location 'New York, NY'",
46
+ "image": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/image.ts --provider 'google' --name 'Jo' --location 'New York, NY'",
47
47
  "code_exec_simple": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/code_exec_simple.ts --provider 'openAI' --name 'Jo' --location 'New York, NY'",
48
48
  "simple": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/simple.ts --provider 'openrouter' --name 'Jo' --location 'New York, NY'",
49
49
  "caching": "node -r dotenv/config --loader ./tsconfig-paths-bootstrap.mjs --experimental-specifier-resolution=node ./src/scripts/caching.ts --name 'Jo' --location 'New York, NY'",
@@ -73,12 +73,12 @@
73
73
  "@aws-sdk/credential-provider-node": "^3.613.0",
74
74
  "@aws-sdk/types": "^3.609.0",
75
75
  "@langchain/anthropic": "^0.3.14",
76
- "@langchain/aws": "^0.1.6",
77
- "@langchain/community": "^0.3.27",
76
+ "@langchain/aws": "^0.1.7",
77
+ "@langchain/community": "^0.3.35",
78
78
  "@langchain/core": "^0.3.40",
79
79
  "@langchain/deepseek": "^0.0.1",
80
- "@langchain/google-genai": "^0.1.9",
81
- "@langchain/google-vertexai": "^0.2.0",
80
+ "@langchain/google-genai": "^0.1.11",
81
+ "@langchain/google-vertexai": "^0.2.2",
82
82
  "@langchain/langgraph": "^0.2.49",
83
83
  "@langchain/mistralai": "^0.0.26",
84
84
  "@langchain/ollama": "^0.1.5",
package/src/events.ts CHANGED
@@ -38,6 +38,10 @@ export class ModelEndHandler implements t.EventHandler {
38
38
  this.collectedUsage.push(usage);
39
39
  }
40
40
 
41
+ if (metadata.ls_provider === 'FakeListChatModel') {
42
+ return handleToolCalls(data?.output?.tool_calls, metadata, graph);
43
+ }
44
+
41
45
  console.log(`====== ${event.toUpperCase()} ======`);
42
46
  console.dir({
43
47
  usage,
@@ -11,6 +11,7 @@ import { AIMessageChunk, ToolMessage, SystemMessage } from '@langchain/core/mess
11
11
  import type { BaseMessage, BaseMessageFields, UsageMetadata } from '@langchain/core/messages';
12
12
  import type * as t from '@/types';
13
13
  import { Providers, GraphEvents, GraphNodeKeys, StepTypes, Callback, ContentTypes } from '@/common';
14
+ import type { ToolCall } from '@langchain/core/messages/tool';
14
15
  import { getChatModelClass, manualToolStreamProviders } from '@/llm/providers';
15
16
  import { ToolNode as CustomToolNode, toolsCondition } from '@/tools/ToolNode';
16
17
  import {
@@ -288,6 +289,7 @@ export class StandardGraph extends Graph<
288
289
  tools: this.tools || [],
289
290
  toolMap: this.toolMap,
290
291
  toolCallStepIds: this.toolCallStepIds,
292
+ errorHandler: this.handleToolCallError.bind(this),
291
293
  });
292
294
  }
293
295
 
@@ -317,8 +319,12 @@ export class StandardGraph extends Graph<
317
319
 
318
320
  return (model as t.ModelWithTools).bindTools(this.tools);
319
321
  }
320
- overrideTestModel(responses: string[], sleep?: number): void {
321
- this.boundModel = createFakeStreamingLLM(responses, sleep);
322
+ overrideTestModel(responses: string[], sleep?: number, toolCalls?: ToolCall[]): void {
323
+ this.boundModel = createFakeStreamingLLM({
324
+ responses,
325
+ sleep,
326
+ toolCalls,
327
+ });
322
328
  }
323
329
 
324
330
  getNewModel({
@@ -549,6 +555,50 @@ export class StandardGraph extends Graph<
549
555
  this,
550
556
  );
551
557
  }
558
+ handleToolCallError(data: t.ToolErrorData, metadata?: Record<string, unknown>): void {
559
+ if (!this.config) {
560
+ throw new Error('No config provided');
561
+ }
562
+
563
+ if (!data.id) {
564
+ console.warn('No Tool ID provided for Tool Error');
565
+ return;
566
+ }
567
+
568
+ const stepId = this.toolCallStepIds.get(data.id) ?? '';
569
+ if (!stepId) {
570
+ throw new Error(`No stepId found for tool_call_id ${data.id}`);
571
+ }
572
+
573
+ const { name, input, error } = data;
574
+
575
+ const runStep = this.getRunStep(stepId);
576
+ if (!runStep) {
577
+ throw new Error(`No run step found for stepId ${stepId}`);
578
+ }
579
+
580
+ const args = typeof input === 'string' ? input : input.input;
581
+ const tool_call = {
582
+ id: data.id,
583
+ name: name ?? '',
584
+ args: typeof args === 'string' ? args : JSON.stringify(args),
585
+ output: `Error processing tool${error?.message ? `: ${error.message}` : ''}`,
586
+ progress: 1,
587
+ };
588
+
589
+ this.handlerRegistry?.getHandler(GraphEvents.ON_RUN_STEP_COMPLETED)?.handle(
590
+ GraphEvents.ON_RUN_STEP_COMPLETED,
591
+ { result: {
592
+ id: stepId,
593
+ index: runStep.index,
594
+ type: 'tool_call',
595
+ tool_call
596
+ } as t.ToolCompleteEvent,
597
+ },
598
+ metadata,
599
+ this,
600
+ );
601
+ }
552
602
 
553
603
  dispatchRunStepDelta(id: string, delta: t.ToolCallDelta): void {
554
604
  if (!this.config) {