@langchain/anthropic 1.3.11 → 1.3.13

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.
@@ -1 +1 @@
1
- {"version":3,"file":"message_inputs.cjs","names":["imageUrl: string","parsedUrl: URL","messages: BaseMessage[]","HumanMessage","toolCall: ToolCall","content: ContentBlock[]","toolCalls?: ToolCall[]","standardContentBlockConverter","_isAnthropicImageBlockParam","_isAnthropicThinkingBlock","block: AnthropicThinkingBlockParam","_isAnthropicRedactedThinkingBlock","block: AnthropicRedactedThinkingBlockParam","_isAnthropicSearchResultBlock","block: AnthropicSearchResultBlockParam","message: BaseMessage","AIMessage","_formatStandardContent","messages: AnthropicMessageCreateParams[\"messages\"]","result: AnthropicMessageCreateParams[\"messages\"]","content:\n | string\n | Array<\n | AnthropicTextBlockParam\n | AnthropicImageBlockParam\n | AnthropicToolUseBlockParam\n | AnthropicToolResultBlockParam\n | AnthropicDocumentBlockParam\n | AnthropicThinkingBlockParam\n | AnthropicRedactedThinkingBlockParam\n | AnthropicServerToolUseBlockParam\n | AnthropicWebSearchToolResultBlockParam\n | AnthropicSearchResultBlockParam\n >","msg: (typeof messages)[0]"],"sources":["../../src/utils/message_inputs.ts"],"sourcesContent":["/**\n * This util file contains functions for converting LangChain messages to Anthropic messages.\n */\nimport type Anthropic from \"@anthropic-ai/sdk\";\nimport {\n type BaseMessage,\n HumanMessage,\n ToolMessage,\n MessageContentComplex,\n isDataContentBlock,\n convertToProviderContentBlock,\n parseBase64DataUrl,\n ContentBlock,\n AIMessage,\n} from \"@langchain/core/messages\";\nimport { ToolCall } from \"@langchain/core/messages/tool\";\nimport {\n AnthropicImageBlockParam,\n AnthropicMessageCreateParams,\n AnthropicTextBlockParam,\n AnthropicToolResultBlockParam,\n AnthropicToolUseBlockParam,\n AnthropicDocumentBlockParam,\n AnthropicThinkingBlockParam,\n AnthropicRedactedThinkingBlockParam,\n AnthropicServerToolUseBlockParam,\n AnthropicWebSearchToolResultBlockParam,\n AnthropicSearchResultBlockParam,\n AnthropicToolResponse,\n AnthropicContainerUploadBlockParam,\n} from \"../types.js\";\nimport {\n _isAnthropicImageBlockParam,\n _isAnthropicRedactedThinkingBlock,\n _isAnthropicSearchResultBlock,\n _isAnthropicThinkingBlock,\n standardContentBlockConverter,\n} from \"./content.js\";\nimport { _formatStandardContent } from \"./standard.js\";\n\nfunction _formatImage(imageUrl: string) {\n const parsed = parseBase64DataUrl({ dataUrl: imageUrl });\n if (parsed) {\n return {\n type: \"base64\",\n media_type: parsed.mime_type,\n data: parsed.data,\n };\n }\n let parsedUrl: URL;\n\n try {\n parsedUrl = new URL(imageUrl);\n } catch {\n throw new Error(\n [\n `Malformed image URL: ${JSON.stringify(\n imageUrl\n )}. Content blocks of type 'image_url' must be a valid http, https, or base64-encoded data URL.`,\n \"Example: data:image/png;base64,/9j/4AAQSk...\",\n \"Example: https://example.com/image.jpg\",\n ].join(\"\\n\\n\")\n );\n }\n\n if (parsedUrl.protocol === \"http:\" || parsedUrl.protocol === \"https:\") {\n return {\n type: \"url\",\n url: imageUrl,\n };\n }\n\n throw new Error(\n [\n `Invalid image URL protocol: ${JSON.stringify(\n parsedUrl.protocol\n )}. Anthropic only supports images as http, https, or base64-encoded data URLs on 'image_url' content blocks.`,\n \"Example: data:image/png;base64,/9j/4AAQSk...\",\n \"Example: https://example.com/image.jpg\",\n ].join(\"\\n\\n\")\n );\n}\n\nfunction _ensureMessageContents(messages: BaseMessage[]): BaseMessage[] {\n // Merge runs of human/tool messages into single human messages with content blocks.\n const updatedMsgs = [];\n for (const message of messages) {\n if (message._getType() === \"tool\") {\n if (typeof message.content === \"string\") {\n const previousMessage = updatedMsgs[updatedMsgs.length - 1];\n if (\n previousMessage?._getType() === \"human\" &&\n Array.isArray(previousMessage.content) &&\n \"type\" in previousMessage.content[0] &&\n previousMessage.content[0].type === \"tool_result\"\n ) {\n // If the previous message was a tool result, we merge this tool message into it.\n (previousMessage.content as MessageContentComplex[]).push({\n type: \"tool_result\",\n content: message.content,\n tool_use_id: (message as ToolMessage).tool_call_id,\n });\n } else {\n // If not, we create a new human message with the tool result.\n updatedMsgs.push(\n new HumanMessage({\n content: [\n {\n type: \"tool_result\",\n content: message.content,\n tool_use_id: (message as ToolMessage).tool_call_id,\n },\n ],\n })\n );\n }\n } else {\n updatedMsgs.push(\n new HumanMessage({\n content: [\n {\n type: \"tool_result\",\n // rare case: message.content could be undefined\n ...(message.content != null\n ? { content: _formatContent(message) }\n : {}),\n tool_use_id: (message as ToolMessage).tool_call_id,\n },\n ],\n })\n );\n }\n } else {\n updatedMsgs.push(message);\n }\n }\n return updatedMsgs;\n}\n\nexport function _convertLangChainToolCallToAnthropic(\n toolCall: ToolCall\n): AnthropicToolResponse {\n if (toolCall.id === undefined) {\n throw new Error(`Anthropic requires all tool calls to have an \"id\".`);\n }\n return {\n type: \"tool_use\",\n id: toolCall.id,\n name: toolCall.name,\n input: toolCall.args,\n };\n}\n\nfunction* _formatContentBlocks(\n content: ContentBlock[],\n toolCalls?: ToolCall[]\n): Generator<Anthropic.Beta.BetaContentBlockParam> {\n const toolTypes = [\n \"bash_code_execution_tool_result\",\n \"input_json_delta\",\n \"server_tool_use\",\n \"text_editor_code_execution_tool_result\",\n \"tool_result\",\n \"tool_use\",\n \"web_search_result\",\n \"web_search_tool_result\",\n ];\n const textTypes = [\"text\", \"text_delta\"];\n for (const contentPart of content) {\n if (isDataContentBlock(contentPart)) {\n yield convertToProviderContentBlock(\n contentPart,\n standardContentBlockConverter\n );\n }\n\n const cacheControl =\n \"cache_control\" in contentPart ? contentPart.cache_control : undefined;\n\n if (contentPart.type === \"image_url\") {\n let source;\n if (typeof contentPart.image_url === \"string\") {\n source = _formatImage(contentPart.image_url);\n } else if (\n typeof contentPart.image_url === \"object\" &&\n contentPart.image_url !== null &&\n \"url\" in contentPart.image_url &&\n typeof contentPart.image_url.url === \"string\"\n ) {\n source = _formatImage(contentPart.image_url.url);\n }\n if (source) {\n yield {\n type: \"image\" as const, // Explicitly setting the type as \"image\"\n source,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n } as Anthropic.Messages.ImageBlockParam;\n }\n } else if (_isAnthropicImageBlockParam(contentPart)) {\n return contentPart;\n } else if (contentPart.type === \"document\") {\n // PDF\n yield {\n ...contentPart,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n } as Anthropic.Messages.DocumentBlockParam;\n } else if (_isAnthropicThinkingBlock(contentPart)) {\n const block: AnthropicThinkingBlockParam = {\n type: \"thinking\" as const, // Explicitly setting the type as \"thinking\"\n thinking: contentPart.thinking,\n signature: contentPart.signature,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n };\n yield block;\n } else if (_isAnthropicRedactedThinkingBlock(contentPart)) {\n const block: AnthropicRedactedThinkingBlockParam = {\n type: \"redacted_thinking\" as const, // Explicitly setting the type as \"redacted_thinking\"\n data: contentPart.data,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n };\n yield block;\n } else if (_isAnthropicSearchResultBlock(contentPart)) {\n const block: AnthropicSearchResultBlockParam = {\n type: \"search_result\" as const, // Explicitly setting the type as \"search_result\"\n title: contentPart.title,\n source: contentPart.source,\n ...(\"cache_control\" in contentPart && contentPart.cache_control\n ? { cache_control: contentPart.cache_control }\n : {}),\n ...(\"citations\" in contentPart && contentPart.citations\n ? { citations: contentPart.citations }\n : {}),\n content: contentPart.content,\n };\n yield block as Anthropic.Beta.BetaSearchResultBlockParam;\n } else if (\n textTypes.find((t) => t === contentPart.type) &&\n \"text\" in contentPart\n ) {\n // Assuming contentPart is of type MessageContentText here\n yield {\n type: \"text\" as const, // Explicitly setting the type as \"text\"\n text: contentPart.text,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n ...(\"citations\" in contentPart && contentPart.citations\n ? { citations: contentPart.citations }\n : {}),\n } as Anthropic.Messages.TextBlockParam;\n } else if (toolTypes.find((t) => t === contentPart.type)) {\n const contentPartCopy = { ...contentPart };\n\n if (contentPartCopy.type === \"input_json_delta\") {\n // `input_json_delta` type only represents yielding partial tool inputs\n // and is not a valid type for Anthropic messages.\n // These blocks appear in streaming responses and should be skipped\n // as their input data is already captured in tool_calls.\n continue;\n }\n\n if (\n contentPartCopy.type === \"tool_use\" &&\n typeof contentPartCopy.input === \"string\"\n ) {\n // First, try to get the input from the corresponding tool_call.\n // This is the most reliable source since tool_calls are properly\n // consolidated from tool_call_chunks during streaming.\n const matchingToolCall = toolCalls?.find(\n (tc) => tc.id === contentPartCopy.id\n );\n if (matchingToolCall) {\n contentPartCopy.input = matchingToolCall.args;\n } else {\n // Fallback: `tool_use` content part may be followed by `input_json_delta`\n // content parts which are chunks of a stringified JSON input,\n // so we need to collect them and merge their inputs.\n const inputDeltas = content.filter(\n (nestedContentPart) =>\n nestedContentPart.index === contentPartCopy.index &&\n nestedContentPart.type === \"input_json_delta\" &&\n typeof nestedContentPart.input === \"string\"\n );\n // If no `input_json_delta` parts are found, this line will just\n // return `contentPartCopy.input`, so no additional check is needed\n contentPartCopy.input = inputDeltas.reduce(\n (accumulator, nestedContentPart) =>\n accumulator + nestedContentPart.input,\n contentPartCopy.input\n );\n }\n }\n\n if (\"index\" in contentPartCopy) {\n // Anthropic does not support passing the index field here, so we remove it.\n delete contentPartCopy.index;\n }\n\n if (\"input\" in contentPartCopy) {\n // Anthropic tool use inputs should be valid objects, when applicable.\n if (typeof contentPartCopy.input === \"string\") {\n try {\n contentPartCopy.input = JSON.parse(contentPartCopy.input);\n } catch {\n contentPartCopy.input = {};\n }\n }\n }\n // TODO: Fix when SDK types are fixed\n yield {\n ...contentPartCopy,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any;\n } else if (contentPart.type === \"container_upload\") {\n yield {\n ...contentPart,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n } as AnthropicContainerUploadBlockParam;\n }\n\n // Note that we are intentionally dropping any blocks that we don't\n // recognize. This is to allow for cross-compatibility between different\n // providers that may have different block types. Ie if we take a message\n // output from OpenAI and send it to Anthropic, we want to drop any blocks\n // that Anthropic doesn't understand.\n }\n}\n\nfunction _formatContent(message: BaseMessage, toolCalls?: ToolCall[]) {\n const { content } = message;\n\n if (typeof content === \"string\") {\n return content;\n } else {\n return Array.from(_formatContentBlocks(content, toolCalls));\n }\n}\n\n/**\n * Formats messages as a prompt for the model.\n * Used in LangSmith, export is important here.\n * @param messages The base messages to format as a prompt.\n * @returns The formatted prompt.\n */\nexport function _convertMessagesToAnthropicPayload(\n messages: BaseMessage[]\n): AnthropicMessageCreateParams {\n const mergedMessages = _ensureMessageContents(messages);\n let system;\n if (mergedMessages.length > 0 && mergedMessages[0]._getType() === \"system\") {\n system = messages[0].content;\n }\n const conversationMessages =\n system !== undefined ? mergedMessages.slice(1) : mergedMessages;\n const formattedMessages = conversationMessages.map((message) => {\n let role;\n if (message._getType() === \"human\") {\n role = \"user\" as const;\n } else if (message._getType() === \"ai\") {\n role = \"assistant\" as const;\n } else if (message._getType() === \"tool\") {\n role = \"user\" as const;\n } else if (message._getType() === \"system\") {\n throw new Error(\n \"System messages are only permitted as the first passed message.\"\n );\n } else {\n throw new Error(`Message type \"${message.type}\" is not supported.`);\n }\n if (\n AIMessage.isInstance(message) &&\n message.response_metadata?.output_version === \"v1\"\n ) {\n return {\n role,\n content: _formatStandardContent(message),\n };\n }\n if (AIMessage.isInstance(message) && !!message.tool_calls?.length) {\n if (typeof message.content === \"string\") {\n if (message.content === \"\") {\n return {\n role,\n content: message.tool_calls.map(\n _convertLangChainToolCallToAnthropic\n ),\n };\n } else {\n return {\n role,\n content: [\n { type: \"text\", text: message.content },\n ...message.tool_calls.map(_convertLangChainToolCallToAnthropic),\n ],\n };\n }\n } else {\n const { content } = message;\n const hasMismatchedToolCalls = !message.tool_calls.every((toolCall) =>\n content.find(\n (contentPart) =>\n (contentPart.type === \"tool_use\" ||\n contentPart.type === \"input_json_delta\" ||\n contentPart.type === \"server_tool_use\") &&\n contentPart.id === toolCall.id\n )\n );\n if (hasMismatchedToolCalls) {\n console.warn(\n `The \"tool_calls\" field on a message is only respected if content is a string.`\n );\n }\n return {\n role,\n content: _formatContent(message, message.tool_calls),\n };\n }\n } else {\n return {\n role,\n content: _formatContent(\n message,\n AIMessage.isInstance(message) ? message.tool_calls : undefined\n ),\n };\n }\n });\n return {\n messages: mergeMessages(\n formattedMessages as AnthropicMessageCreateParams[\"messages\"]\n ),\n system,\n } as AnthropicMessageCreateParams;\n}\n\nfunction mergeMessages(messages: AnthropicMessageCreateParams[\"messages\"]) {\n if (!messages || messages.length <= 1) {\n return messages;\n }\n\n const result: AnthropicMessageCreateParams[\"messages\"] = [];\n let currentMessage = messages[0];\n\n const normalizeContent = (\n content:\n | string\n | Array<\n | AnthropicTextBlockParam\n | AnthropicImageBlockParam\n | AnthropicToolUseBlockParam\n | AnthropicToolResultBlockParam\n | AnthropicDocumentBlockParam\n | AnthropicThinkingBlockParam\n | AnthropicRedactedThinkingBlockParam\n | AnthropicServerToolUseBlockParam\n | AnthropicWebSearchToolResultBlockParam\n | AnthropicSearchResultBlockParam\n >\n ): Array<\n | AnthropicTextBlockParam\n | AnthropicImageBlockParam\n | AnthropicToolUseBlockParam\n | AnthropicToolResultBlockParam\n | AnthropicDocumentBlockParam\n | AnthropicThinkingBlockParam\n | AnthropicRedactedThinkingBlockParam\n | AnthropicServerToolUseBlockParam\n | AnthropicWebSearchToolResultBlockParam\n | AnthropicSearchResultBlockParam\n > => {\n if (typeof content === \"string\") {\n return [\n {\n type: \"text\",\n text: content,\n },\n ];\n }\n return content;\n };\n\n const isToolResultMessage = (msg: (typeof messages)[0]) => {\n if (msg.role !== \"user\") return false;\n\n if (typeof msg.content === \"string\") {\n return false;\n }\n\n return (\n Array.isArray(msg.content) &&\n msg.content.every((item) => item.type === \"tool_result\")\n );\n };\n\n for (let i = 1; i < messages.length; i += 1) {\n const nextMessage = messages[i];\n\n if (\n isToolResultMessage(currentMessage) &&\n isToolResultMessage(nextMessage)\n ) {\n // Merge the messages by combining their content arrays\n currentMessage = {\n ...currentMessage,\n content: [\n ...normalizeContent(currentMessage.content),\n ...normalizeContent(nextMessage.content),\n ],\n };\n } else {\n result.push(currentMessage);\n currentMessage = nextMessage;\n }\n }\n\n result.push(currentMessage);\n return result;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"message_inputs.cjs","names":["imageUrl: string","parsedUrl: URL","messages: BaseMessage[]","HumanMessage","toolCall: ToolCall","content: ContentBlock[]","toolCalls?: ToolCall[]","standardContentBlockConverter","_isAnthropicImageBlockParam","source:\n | { type: \"url\"; url: string }\n | { type: \"base64\"; media_type: string; data: string }\n | { type: \"file\"; file_id: string }\n | undefined","_isAnthropicThinkingBlock","block: AnthropicThinkingBlockParam","_isAnthropicRedactedThinkingBlock","block: AnthropicRedactedThinkingBlockParam","_isAnthropicSearchResultBlock","block: AnthropicSearchResultBlockParam","message: BaseMessage","AIMessage","_formatStandardContent","payload: AnthropicMessageCreateParams","cacheControl: CacheControl","messages: AnthropicMessageCreateParams[\"messages\"]","result: AnthropicMessageCreateParams[\"messages\"]","content:\n | string\n | Array<\n | AnthropicTextBlockParam\n | AnthropicImageBlockParam\n | AnthropicToolUseBlockParam\n | AnthropicToolResultBlockParam\n | AnthropicDocumentBlockParam\n | AnthropicThinkingBlockParam\n | AnthropicRedactedThinkingBlockParam\n | AnthropicServerToolUseBlockParam\n | AnthropicWebSearchToolResultBlockParam\n | AnthropicSearchResultBlockParam\n >","msg: (typeof messages)[0]"],"sources":["../../src/utils/message_inputs.ts"],"sourcesContent":["/**\n * This util file contains functions for converting LangChain messages to Anthropic messages.\n */\nimport type Anthropic from \"@anthropic-ai/sdk\";\nimport {\n type BaseMessage,\n HumanMessage,\n ToolMessage,\n MessageContentComplex,\n isDataContentBlock,\n convertToProviderContentBlock,\n parseBase64DataUrl,\n ContentBlock,\n AIMessage,\n} from \"@langchain/core/messages\";\nimport { ToolCall } from \"@langchain/core/messages/tool\";\nimport {\n AnthropicImageBlockParam,\n AnthropicMessageCreateParams,\n AnthropicTextBlockParam,\n AnthropicToolResultBlockParam,\n AnthropicToolUseBlockParam,\n AnthropicDocumentBlockParam,\n AnthropicThinkingBlockParam,\n AnthropicRedactedThinkingBlockParam,\n AnthropicServerToolUseBlockParam,\n AnthropicWebSearchToolResultBlockParam,\n AnthropicSearchResultBlockParam,\n AnthropicToolResponse,\n AnthropicContainerUploadBlockParam,\n} from \"../types.js\";\nimport {\n _isAnthropicImageBlockParam,\n _isAnthropicRedactedThinkingBlock,\n _isAnthropicSearchResultBlock,\n _isAnthropicThinkingBlock,\n standardContentBlockConverter,\n} from \"./content.js\";\nimport { _formatStandardContent } from \"./standard.js\";\n\nfunction _formatImage(imageUrl: string) {\n const parsed = parseBase64DataUrl({ dataUrl: imageUrl });\n if (parsed) {\n return {\n type: \"base64\",\n media_type: parsed.mime_type,\n data: parsed.data,\n };\n }\n let parsedUrl: URL;\n\n try {\n parsedUrl = new URL(imageUrl);\n } catch {\n throw new Error(\n [\n `Malformed image URL: ${JSON.stringify(\n imageUrl\n )}. Content blocks of type 'image_url' must be a valid http, https, or base64-encoded data URL.`,\n \"Example: data:image/png;base64,/9j/4AAQSk...\",\n \"Example: https://example.com/image.jpg\",\n ].join(\"\\n\\n\")\n );\n }\n\n if (parsedUrl.protocol === \"http:\" || parsedUrl.protocol === \"https:\") {\n return {\n type: \"url\",\n url: imageUrl,\n };\n }\n\n throw new Error(\n [\n `Invalid image URL protocol: ${JSON.stringify(\n parsedUrl.protocol\n )}. Anthropic only supports images as http, https, or base64-encoded data URLs on 'image_url' content blocks.`,\n \"Example: data:image/png;base64,/9j/4AAQSk...\",\n \"Example: https://example.com/image.jpg\",\n ].join(\"\\n\\n\")\n );\n}\n\nfunction _ensureMessageContents(messages: BaseMessage[]): BaseMessage[] {\n // Merge runs of human/tool messages into single human messages with content blocks.\n const updatedMsgs = [];\n for (const message of messages) {\n if (message._getType() === \"tool\") {\n if (typeof message.content === \"string\") {\n const previousMessage = updatedMsgs[updatedMsgs.length - 1];\n if (\n previousMessage?._getType() === \"human\" &&\n Array.isArray(previousMessage.content) &&\n \"type\" in previousMessage.content[0] &&\n previousMessage.content[0].type === \"tool_result\"\n ) {\n // If the previous message was a tool result, we merge this tool message into it.\n (previousMessage.content as MessageContentComplex[]).push({\n type: \"tool_result\",\n content: message.content,\n tool_use_id: (message as ToolMessage).tool_call_id,\n });\n } else {\n // If not, we create a new human message with the tool result.\n updatedMsgs.push(\n new HumanMessage({\n content: [\n {\n type: \"tool_result\",\n content: message.content,\n tool_use_id: (message as ToolMessage).tool_call_id,\n },\n ],\n })\n );\n }\n } else {\n updatedMsgs.push(\n new HumanMessage({\n content: [\n {\n type: \"tool_result\",\n // rare case: message.content could be undefined\n ...(message.content != null\n ? { content: _formatContent(message) }\n : {}),\n tool_use_id: (message as ToolMessage).tool_call_id,\n },\n ],\n })\n );\n }\n } else {\n updatedMsgs.push(message);\n }\n }\n return updatedMsgs;\n}\n\nexport function _convertLangChainToolCallToAnthropic(\n toolCall: ToolCall\n): AnthropicToolResponse {\n if (toolCall.id === undefined) {\n throw new Error(`Anthropic requires all tool calls to have an \"id\".`);\n }\n return {\n type: \"tool_use\",\n id: toolCall.id,\n name: toolCall.name,\n input: toolCall.args,\n };\n}\n\nfunction* _formatContentBlocks(\n content: ContentBlock[],\n toolCalls?: ToolCall[]\n): Generator<Anthropic.Beta.BetaContentBlockParam> {\n const toolTypes = [\n \"bash_code_execution_tool_result\",\n \"input_json_delta\",\n \"server_tool_use\",\n \"text_editor_code_execution_tool_result\",\n \"tool_result\",\n \"tool_use\",\n \"web_search_result\",\n \"web_search_tool_result\",\n ];\n const textTypes = [\"text\", \"text_delta\"];\n for (const contentPart of content) {\n if (isDataContentBlock(contentPart)) {\n yield convertToProviderContentBlock(\n contentPart,\n standardContentBlockConverter\n );\n }\n\n const cacheControl =\n \"cache_control\" in contentPart ? contentPart.cache_control : undefined;\n\n if (contentPart.type === \"image_url\") {\n let source;\n if (typeof contentPart.image_url === \"string\") {\n source = _formatImage(contentPart.image_url);\n } else if (\n typeof contentPart.image_url === \"object\" &&\n contentPart.image_url !== null &&\n \"url\" in contentPart.image_url &&\n typeof contentPart.image_url.url === \"string\"\n ) {\n source = _formatImage(contentPart.image_url.url);\n }\n if (source) {\n yield {\n type: \"image\" as const, // Explicitly setting the type as \"image\"\n source,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n } as Anthropic.Messages.ImageBlockParam;\n }\n } else if (_isAnthropicImageBlockParam(contentPart)) {\n yield contentPart;\n } else if (contentPart.type === \"image\") {\n // Handle new ContentBlock.Multimodal.Image format\n let source;\n\n if (\"url\" in contentPart && typeof contentPart.url === \"string\") {\n // URL-based image\n source = _formatImage(contentPart.url);\n } else if (\n \"data\" in contentPart &&\n (typeof contentPart.data === \"string\" ||\n // eslint-disable-next-line no-instanceof/no-instanceof\n contentPart.data instanceof Uint8Array)\n ) {\n // Base64-based image\n const mimeType =\n \"mimeType\" in contentPart && typeof contentPart.mimeType === \"string\"\n ? contentPart.mimeType\n : \"image/jpeg\";\n const data =\n typeof contentPart.data === \"string\"\n ? contentPart.data\n : Buffer.from(contentPart.data).toString(\"base64\");\n source = {\n type: \"base64\" as const,\n media_type: mimeType as\n | \"image/jpeg\"\n | \"image/png\"\n | \"image/gif\"\n | \"image/webp\",\n data,\n };\n } else if (\n \"fileId\" in contentPart &&\n typeof contentPart.fileId === \"string\"\n ) {\n // File ID-based image\n // Note: Anthropic supports file IDs for images that have been uploaded\n // to their servers via the Files API\n source = {\n type: \"file\" as const,\n file_id: contentPart.fileId,\n };\n }\n\n if (source) {\n yield {\n type: \"image\" as const,\n source,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n } as Anthropic.Messages.ImageBlockParam;\n }\n } else if (contentPart.type === \"file\") {\n // Handle new ContentBlock.Multimodal.File format\n let source:\n | { type: \"url\"; url: string }\n | { type: \"base64\"; media_type: string; data: string }\n | { type: \"file\"; file_id: string }\n | undefined;\n\n if (\"url\" in contentPart && typeof contentPart.url === \"string\") {\n // File with URL\n source = {\n type: \"url\" as const,\n url: contentPart.url,\n };\n } else if (\n \"data\" in contentPart &&\n (typeof contentPart.data === \"string\" ||\n // eslint-disable-next-line no-instanceof/no-instanceof\n contentPart.data instanceof Uint8Array)\n ) {\n // File with base64 data (string or Uint8Array)\n const media_type =\n \"mimeType\" in contentPart && typeof contentPart.mimeType === \"string\"\n ? contentPart.mimeType\n : \"application/pdf\";\n const data =\n typeof contentPart.data === \"string\"\n ? contentPart.data\n : Buffer.from(contentPart.data).toString(\"base64\");\n\n source = {\n type: \"base64\" as const,\n media_type,\n data,\n };\n } else if (\n \"fileId\" in contentPart &&\n typeof contentPart.fileId === \"string\"\n ) {\n // File ID from Anthropic Files API\n // https://platform.claude.com/docs/en/build-with-claude/pdf-support#option-3-files-api\n source = {\n type: \"file\" as const,\n file_id: contentPart.fileId,\n };\n }\n\n if (source) {\n yield {\n type: \"document\" as const,\n source,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n } as Anthropic.Messages.DocumentBlockParam;\n }\n } else if (contentPart.type === \"document\") {\n // PDF\n yield {\n ...contentPart,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n } as Anthropic.Messages.DocumentBlockParam;\n } else if (_isAnthropicThinkingBlock(contentPart)) {\n const block: AnthropicThinkingBlockParam = {\n type: \"thinking\" as const, // Explicitly setting the type as \"thinking\"\n thinking: contentPart.thinking,\n signature: contentPart.signature,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n };\n yield block;\n } else if (_isAnthropicRedactedThinkingBlock(contentPart)) {\n const block: AnthropicRedactedThinkingBlockParam = {\n type: \"redacted_thinking\" as const, // Explicitly setting the type as \"redacted_thinking\"\n data: contentPart.data,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n };\n yield block;\n } else if (_isAnthropicSearchResultBlock(contentPart)) {\n const block: AnthropicSearchResultBlockParam = {\n type: \"search_result\" as const, // Explicitly setting the type as \"search_result\"\n title: contentPart.title,\n source: contentPart.source,\n ...(\"cache_control\" in contentPart && contentPart.cache_control\n ? { cache_control: contentPart.cache_control }\n : {}),\n ...(\"citations\" in contentPart && contentPart.citations\n ? { citations: contentPart.citations }\n : {}),\n content: contentPart.content,\n };\n yield block as Anthropic.Beta.BetaSearchResultBlockParam;\n } else if (\n textTypes.find((t) => t === contentPart.type) &&\n \"text\" in contentPart\n ) {\n // Assuming contentPart is of type MessageContentText here\n yield {\n type: \"text\" as const, // Explicitly setting the type as \"text\"\n text: contentPart.text,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n ...(\"citations\" in contentPart && contentPart.citations\n ? { citations: contentPart.citations }\n : {}),\n } as Anthropic.Messages.TextBlockParam;\n } else if (toolTypes.find((t) => t === contentPart.type)) {\n const contentPartCopy = { ...contentPart };\n\n if (contentPartCopy.type === \"input_json_delta\") {\n // `input_json_delta` type only represents yielding partial tool inputs\n // and is not a valid type for Anthropic messages.\n // These blocks appear in streaming responses and should be skipped\n // as their input data is already captured in tool_calls.\n continue;\n }\n\n if (\n contentPartCopy.type === \"tool_use\" &&\n typeof contentPartCopy.input === \"string\"\n ) {\n // First, try to get the input from the corresponding tool_call.\n // This is the most reliable source since tool_calls are properly\n // consolidated from tool_call_chunks during streaming.\n const matchingToolCall = toolCalls?.find(\n (tc) => tc.id === contentPartCopy.id\n );\n if (matchingToolCall) {\n contentPartCopy.input = matchingToolCall.args;\n } else {\n // Fallback: `tool_use` content part may be followed by `input_json_delta`\n // content parts which are chunks of a stringified JSON input,\n // so we need to collect them and merge their inputs.\n const inputDeltas = content.filter(\n (nestedContentPart) =>\n nestedContentPart.index === contentPartCopy.index &&\n nestedContentPart.type === \"input_json_delta\" &&\n typeof nestedContentPart.input === \"string\"\n );\n // If no `input_json_delta` parts are found, this line will just\n // return `contentPartCopy.input`, so no additional check is needed\n contentPartCopy.input = inputDeltas.reduce(\n (accumulator, nestedContentPart) =>\n accumulator + nestedContentPart.input,\n contentPartCopy.input\n );\n }\n }\n\n if (\"index\" in contentPartCopy) {\n // Anthropic does not support passing the index field here, so we remove it.\n delete contentPartCopy.index;\n }\n\n if (\"input\" in contentPartCopy) {\n // Anthropic tool use inputs should be valid objects, when applicable.\n if (typeof contentPartCopy.input === \"string\") {\n try {\n contentPartCopy.input = JSON.parse(contentPartCopy.input);\n } catch {\n contentPartCopy.input = {};\n }\n }\n }\n // TODO: Fix when SDK types are fixed\n yield {\n ...contentPartCopy,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any;\n } else if (contentPart.type === \"container_upload\") {\n yield {\n ...contentPart,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n } as AnthropicContainerUploadBlockParam;\n }\n\n // Note that we are intentionally dropping any blocks that we don't\n // recognize. This is to allow for cross-compatibility between different\n // providers that may have different block types. Ie if we take a message\n // output from OpenAI and send it to Anthropic, we want to drop any blocks\n // that Anthropic doesn't understand.\n }\n}\n\nfunction _formatContent(message: BaseMessage, toolCalls?: ToolCall[]) {\n const { content } = message;\n\n if (typeof content === \"string\") {\n return content;\n } else {\n return Array.from(_formatContentBlocks(content, toolCalls));\n }\n}\n\n/**\n * Formats messages as a prompt for the model.\n * Used in LangSmith, export is important here.\n * @param messages The base messages to format as a prompt.\n * @returns The formatted prompt.\n */\nexport function _convertMessagesToAnthropicPayload(\n messages: BaseMessage[]\n): AnthropicMessageCreateParams {\n const mergedMessages = _ensureMessageContents(messages);\n let system;\n if (mergedMessages.length > 0 && mergedMessages[0]._getType() === \"system\") {\n system = messages[0].content;\n }\n const conversationMessages =\n system !== undefined ? mergedMessages.slice(1) : mergedMessages;\n const formattedMessages = conversationMessages.map((message) => {\n let role;\n if (message._getType() === \"human\") {\n role = \"user\" as const;\n } else if (message._getType() === \"ai\") {\n role = \"assistant\" as const;\n } else if (message._getType() === \"tool\") {\n role = \"user\" as const;\n } else if (message._getType() === \"system\") {\n throw new Error(\n \"System messages are only permitted as the first passed message.\"\n );\n } else {\n throw new Error(`Message type \"${message.type}\" is not supported.`);\n }\n if (\n AIMessage.isInstance(message) &&\n message.response_metadata?.output_version === \"v1\"\n ) {\n return {\n role,\n content: _formatStandardContent(message),\n };\n }\n if (AIMessage.isInstance(message) && !!message.tool_calls?.length) {\n if (typeof message.content === \"string\") {\n if (message.content === \"\") {\n return {\n role,\n content: message.tool_calls.map(\n _convertLangChainToolCallToAnthropic\n ),\n };\n } else {\n return {\n role,\n content: [\n { type: \"text\", text: message.content },\n ...message.tool_calls.map(_convertLangChainToolCallToAnthropic),\n ],\n };\n }\n } else {\n const { content } = message;\n const hasMismatchedToolCalls = !message.tool_calls.every((toolCall) =>\n content.find(\n (contentPart) =>\n (contentPart.type === \"tool_use\" ||\n contentPart.type === \"input_json_delta\" ||\n contentPart.type === \"server_tool_use\") &&\n contentPart.id === toolCall.id\n )\n );\n if (hasMismatchedToolCalls) {\n console.warn(\n `The \"tool_calls\" field on a message is only respected if content is a string.`\n );\n }\n return {\n role,\n content: _formatContent(message, message.tool_calls),\n };\n }\n } else {\n return {\n role,\n content: _formatContent(\n message,\n AIMessage.isInstance(message) ? message.tool_calls : undefined\n ),\n };\n }\n });\n return {\n messages: mergeMessages(\n formattedMessages as AnthropicMessageCreateParams[\"messages\"]\n ),\n system,\n } as AnthropicMessageCreateParams;\n}\n\n/**\n * Cache control configuration for Anthropic prompt caching.\n */\ninterface CacheControl {\n type: \"ephemeral\";\n ttl?: \"5m\" | \"1h\";\n}\n\n/**\n * Applies cache_control to the last content block of the last message in the payload.\n * This is the recommended approach for prompt caching as it applies the cache_control\n * at the final formatting layer, after all message processing is complete.\n *\n * This matches the Python langchain-anthropic implementation where cache_control\n * is applied via model_settings rather than modifying message content blocks directly.\n *\n * @param payload - The formatted Anthropic message payload\n * @param cacheControl - The cache control configuration to apply\n * @returns The payload with cache_control applied to the last content block\n */\nexport function applyCacheControlToPayload(\n payload: AnthropicMessageCreateParams,\n cacheControl: CacheControl\n): AnthropicMessageCreateParams {\n if (!payload.messages || payload.messages.length === 0) {\n return payload;\n }\n\n const messages = [...payload.messages];\n const lastMessageIndex = messages.length - 1;\n const lastMessage = messages[lastMessageIndex];\n\n if (!lastMessage) {\n return payload;\n }\n\n // Handle string content - convert to text block with cache_control\n if (typeof lastMessage.content === \"string\") {\n messages[lastMessageIndex] = {\n ...lastMessage,\n content: [\n {\n type: \"text\",\n text: lastMessage.content,\n cache_control: cacheControl,\n },\n ],\n };\n return { ...payload, messages };\n }\n\n // Handle array content - add cache_control to the last block\n if (Array.isArray(lastMessage.content) && lastMessage.content.length > 0) {\n const content = [...lastMessage.content];\n const lastBlockIndex = content.length - 1;\n const lastBlock = content[lastBlockIndex];\n\n // Add cache_control to the last block\n content[lastBlockIndex] = {\n ...lastBlock,\n cache_control: cacheControl,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any;\n\n messages[lastMessageIndex] = {\n ...lastMessage,\n content,\n };\n return { ...payload, messages };\n }\n\n return payload;\n}\n\nfunction mergeMessages(messages: AnthropicMessageCreateParams[\"messages\"]) {\n if (!messages || messages.length <= 1) {\n return messages;\n }\n\n const result: AnthropicMessageCreateParams[\"messages\"] = [];\n let currentMessage = messages[0];\n\n const normalizeContent = (\n content:\n | string\n | Array<\n | AnthropicTextBlockParam\n | AnthropicImageBlockParam\n | AnthropicToolUseBlockParam\n | AnthropicToolResultBlockParam\n | AnthropicDocumentBlockParam\n | AnthropicThinkingBlockParam\n | AnthropicRedactedThinkingBlockParam\n | AnthropicServerToolUseBlockParam\n | AnthropicWebSearchToolResultBlockParam\n | AnthropicSearchResultBlockParam\n >\n ): Array<\n | AnthropicTextBlockParam\n | AnthropicImageBlockParam\n | AnthropicToolUseBlockParam\n | AnthropicToolResultBlockParam\n | AnthropicDocumentBlockParam\n | AnthropicThinkingBlockParam\n | AnthropicRedactedThinkingBlockParam\n | AnthropicServerToolUseBlockParam\n | AnthropicWebSearchToolResultBlockParam\n | AnthropicSearchResultBlockParam\n > => {\n if (typeof content === \"string\") {\n return [\n {\n type: \"text\",\n text: content,\n },\n ];\n }\n return content;\n };\n\n const isToolResultMessage = (msg: (typeof messages)[0]) => {\n if (msg.role !== \"user\") return false;\n\n if (typeof msg.content === \"string\") {\n return false;\n }\n\n return (\n Array.isArray(msg.content) &&\n msg.content.every((item) => item.type === \"tool_result\")\n );\n };\n\n for (let i = 1; i < messages.length; i += 1) {\n const nextMessage = messages[i];\n\n if (\n isToolResultMessage(currentMessage) &&\n isToolResultMessage(nextMessage)\n ) {\n // Merge the messages by combining their content arrays\n currentMessage = {\n ...currentMessage,\n content: [\n ...normalizeContent(currentMessage.content),\n ...normalizeContent(nextMessage.content),\n ],\n };\n } else {\n result.push(currentMessage);\n currentMessage = nextMessage;\n }\n }\n\n result.push(currentMessage);\n return result;\n}\n"],"mappings":"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"}
@@ -85,8 +85,51 @@ function* _formatContentBlocks(content, toolCalls) {
85
85
  source,
86
86
  ...cacheControl ? { cache_control: cacheControl } : {}
87
87
  };
88
- } else if (_isAnthropicImageBlockParam(contentPart)) return contentPart;
89
- else if (contentPart.type === "document") yield {
88
+ } else if (_isAnthropicImageBlockParam(contentPart)) yield contentPart;
89
+ else if (contentPart.type === "image") {
90
+ let source;
91
+ if ("url" in contentPart && typeof contentPart.url === "string") source = _formatImage(contentPart.url);
92
+ else if ("data" in contentPart && (typeof contentPart.data === "string" || contentPart.data instanceof Uint8Array)) {
93
+ const mimeType = "mimeType" in contentPart && typeof contentPart.mimeType === "string" ? contentPart.mimeType : "image/jpeg";
94
+ const data = typeof contentPart.data === "string" ? contentPart.data : Buffer.from(contentPart.data).toString("base64");
95
+ source = {
96
+ type: "base64",
97
+ media_type: mimeType,
98
+ data
99
+ };
100
+ } else if ("fileId" in contentPart && typeof contentPart.fileId === "string") source = {
101
+ type: "file",
102
+ file_id: contentPart.fileId
103
+ };
104
+ if (source) yield {
105
+ type: "image",
106
+ source,
107
+ ...cacheControl ? { cache_control: cacheControl } : {}
108
+ };
109
+ } else if (contentPart.type === "file") {
110
+ let source;
111
+ if ("url" in contentPart && typeof contentPart.url === "string") source = {
112
+ type: "url",
113
+ url: contentPart.url
114
+ };
115
+ else if ("data" in contentPart && (typeof contentPart.data === "string" || contentPart.data instanceof Uint8Array)) {
116
+ const media_type = "mimeType" in contentPart && typeof contentPart.mimeType === "string" ? contentPart.mimeType : "application/pdf";
117
+ const data = typeof contentPart.data === "string" ? contentPart.data : Buffer.from(contentPart.data).toString("base64");
118
+ source = {
119
+ type: "base64",
120
+ media_type,
121
+ data
122
+ };
123
+ } else if ("fileId" in contentPart && typeof contentPart.fileId === "string") source = {
124
+ type: "file",
125
+ file_id: contentPart.fileId
126
+ };
127
+ if (source) yield {
128
+ type: "document",
129
+ source,
130
+ ...cacheControl ? { cache_control: cacheControl } : {}
131
+ };
132
+ } else if (contentPart.type === "document") yield {
90
133
  ...contentPart,
91
134
  ...cacheControl ? { cache_control: cacheControl } : {}
92
135
  };
@@ -207,6 +250,57 @@ function _convertMessagesToAnthropicPayload(messages) {
207
250
  system
208
251
  };
209
252
  }
253
+ /**
254
+ * Applies cache_control to the last content block of the last message in the payload.
255
+ * This is the recommended approach for prompt caching as it applies the cache_control
256
+ * at the final formatting layer, after all message processing is complete.
257
+ *
258
+ * This matches the Python langchain-anthropic implementation where cache_control
259
+ * is applied via model_settings rather than modifying message content blocks directly.
260
+ *
261
+ * @param payload - The formatted Anthropic message payload
262
+ * @param cacheControl - The cache control configuration to apply
263
+ * @returns The payload with cache_control applied to the last content block
264
+ */
265
+ function applyCacheControlToPayload(payload, cacheControl) {
266
+ if (!payload.messages || payload.messages.length === 0) return payload;
267
+ const messages = [...payload.messages];
268
+ const lastMessageIndex = messages.length - 1;
269
+ const lastMessage = messages[lastMessageIndex];
270
+ if (!lastMessage) return payload;
271
+ if (typeof lastMessage.content === "string") {
272
+ messages[lastMessageIndex] = {
273
+ ...lastMessage,
274
+ content: [{
275
+ type: "text",
276
+ text: lastMessage.content,
277
+ cache_control: cacheControl
278
+ }]
279
+ };
280
+ return {
281
+ ...payload,
282
+ messages
283
+ };
284
+ }
285
+ if (Array.isArray(lastMessage.content) && lastMessage.content.length > 0) {
286
+ const content = [...lastMessage.content];
287
+ const lastBlockIndex = content.length - 1;
288
+ const lastBlock = content[lastBlockIndex];
289
+ content[lastBlockIndex] = {
290
+ ...lastBlock,
291
+ cache_control: cacheControl
292
+ };
293
+ messages[lastMessageIndex] = {
294
+ ...lastMessage,
295
+ content
296
+ };
297
+ return {
298
+ ...payload,
299
+ messages
300
+ };
301
+ }
302
+ return payload;
303
+ }
210
304
  function mergeMessages(messages) {
211
305
  if (!messages || messages.length <= 1) return messages;
212
306
  const result = [];
@@ -239,5 +333,5 @@ function mergeMessages(messages) {
239
333
  }
240
334
 
241
335
  //#endregion
242
- export { _convertMessagesToAnthropicPayload };
336
+ export { _convertMessagesToAnthropicPayload, applyCacheControlToPayload };
243
337
  //# sourceMappingURL=message_inputs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"message_inputs.js","names":["imageUrl: string","parsedUrl: URL","messages: BaseMessage[]","toolCall: ToolCall","content: ContentBlock[]","toolCalls?: ToolCall[]","block: AnthropicThinkingBlockParam","block: AnthropicRedactedThinkingBlockParam","block: AnthropicSearchResultBlockParam","message: BaseMessage","messages: AnthropicMessageCreateParams[\"messages\"]","result: AnthropicMessageCreateParams[\"messages\"]","content:\n | string\n | Array<\n | AnthropicTextBlockParam\n | AnthropicImageBlockParam\n | AnthropicToolUseBlockParam\n | AnthropicToolResultBlockParam\n | AnthropicDocumentBlockParam\n | AnthropicThinkingBlockParam\n | AnthropicRedactedThinkingBlockParam\n | AnthropicServerToolUseBlockParam\n | AnthropicWebSearchToolResultBlockParam\n | AnthropicSearchResultBlockParam\n >","msg: (typeof messages)[0]"],"sources":["../../src/utils/message_inputs.ts"],"sourcesContent":["/**\n * This util file contains functions for converting LangChain messages to Anthropic messages.\n */\nimport type Anthropic from \"@anthropic-ai/sdk\";\nimport {\n type BaseMessage,\n HumanMessage,\n ToolMessage,\n MessageContentComplex,\n isDataContentBlock,\n convertToProviderContentBlock,\n parseBase64DataUrl,\n ContentBlock,\n AIMessage,\n} from \"@langchain/core/messages\";\nimport { ToolCall } from \"@langchain/core/messages/tool\";\nimport {\n AnthropicImageBlockParam,\n AnthropicMessageCreateParams,\n AnthropicTextBlockParam,\n AnthropicToolResultBlockParam,\n AnthropicToolUseBlockParam,\n AnthropicDocumentBlockParam,\n AnthropicThinkingBlockParam,\n AnthropicRedactedThinkingBlockParam,\n AnthropicServerToolUseBlockParam,\n AnthropicWebSearchToolResultBlockParam,\n AnthropicSearchResultBlockParam,\n AnthropicToolResponse,\n AnthropicContainerUploadBlockParam,\n} from \"../types.js\";\nimport {\n _isAnthropicImageBlockParam,\n _isAnthropicRedactedThinkingBlock,\n _isAnthropicSearchResultBlock,\n _isAnthropicThinkingBlock,\n standardContentBlockConverter,\n} from \"./content.js\";\nimport { _formatStandardContent } from \"./standard.js\";\n\nfunction _formatImage(imageUrl: string) {\n const parsed = parseBase64DataUrl({ dataUrl: imageUrl });\n if (parsed) {\n return {\n type: \"base64\",\n media_type: parsed.mime_type,\n data: parsed.data,\n };\n }\n let parsedUrl: URL;\n\n try {\n parsedUrl = new URL(imageUrl);\n } catch {\n throw new Error(\n [\n `Malformed image URL: ${JSON.stringify(\n imageUrl\n )}. Content blocks of type 'image_url' must be a valid http, https, or base64-encoded data URL.`,\n \"Example: data:image/png;base64,/9j/4AAQSk...\",\n \"Example: https://example.com/image.jpg\",\n ].join(\"\\n\\n\")\n );\n }\n\n if (parsedUrl.protocol === \"http:\" || parsedUrl.protocol === \"https:\") {\n return {\n type: \"url\",\n url: imageUrl,\n };\n }\n\n throw new Error(\n [\n `Invalid image URL protocol: ${JSON.stringify(\n parsedUrl.protocol\n )}. Anthropic only supports images as http, https, or base64-encoded data URLs on 'image_url' content blocks.`,\n \"Example: data:image/png;base64,/9j/4AAQSk...\",\n \"Example: https://example.com/image.jpg\",\n ].join(\"\\n\\n\")\n );\n}\n\nfunction _ensureMessageContents(messages: BaseMessage[]): BaseMessage[] {\n // Merge runs of human/tool messages into single human messages with content blocks.\n const updatedMsgs = [];\n for (const message of messages) {\n if (message._getType() === \"tool\") {\n if (typeof message.content === \"string\") {\n const previousMessage = updatedMsgs[updatedMsgs.length - 1];\n if (\n previousMessage?._getType() === \"human\" &&\n Array.isArray(previousMessage.content) &&\n \"type\" in previousMessage.content[0] &&\n previousMessage.content[0].type === \"tool_result\"\n ) {\n // If the previous message was a tool result, we merge this tool message into it.\n (previousMessage.content as MessageContentComplex[]).push({\n type: \"tool_result\",\n content: message.content,\n tool_use_id: (message as ToolMessage).tool_call_id,\n });\n } else {\n // If not, we create a new human message with the tool result.\n updatedMsgs.push(\n new HumanMessage({\n content: [\n {\n type: \"tool_result\",\n content: message.content,\n tool_use_id: (message as ToolMessage).tool_call_id,\n },\n ],\n })\n );\n }\n } else {\n updatedMsgs.push(\n new HumanMessage({\n content: [\n {\n type: \"tool_result\",\n // rare case: message.content could be undefined\n ...(message.content != null\n ? { content: _formatContent(message) }\n : {}),\n tool_use_id: (message as ToolMessage).tool_call_id,\n },\n ],\n })\n );\n }\n } else {\n updatedMsgs.push(message);\n }\n }\n return updatedMsgs;\n}\n\nexport function _convertLangChainToolCallToAnthropic(\n toolCall: ToolCall\n): AnthropicToolResponse {\n if (toolCall.id === undefined) {\n throw new Error(`Anthropic requires all tool calls to have an \"id\".`);\n }\n return {\n type: \"tool_use\",\n id: toolCall.id,\n name: toolCall.name,\n input: toolCall.args,\n };\n}\n\nfunction* _formatContentBlocks(\n content: ContentBlock[],\n toolCalls?: ToolCall[]\n): Generator<Anthropic.Beta.BetaContentBlockParam> {\n const toolTypes = [\n \"bash_code_execution_tool_result\",\n \"input_json_delta\",\n \"server_tool_use\",\n \"text_editor_code_execution_tool_result\",\n \"tool_result\",\n \"tool_use\",\n \"web_search_result\",\n \"web_search_tool_result\",\n ];\n const textTypes = [\"text\", \"text_delta\"];\n for (const contentPart of content) {\n if (isDataContentBlock(contentPart)) {\n yield convertToProviderContentBlock(\n contentPart,\n standardContentBlockConverter\n );\n }\n\n const cacheControl =\n \"cache_control\" in contentPart ? contentPart.cache_control : undefined;\n\n if (contentPart.type === \"image_url\") {\n let source;\n if (typeof contentPart.image_url === \"string\") {\n source = _formatImage(contentPart.image_url);\n } else if (\n typeof contentPart.image_url === \"object\" &&\n contentPart.image_url !== null &&\n \"url\" in contentPart.image_url &&\n typeof contentPart.image_url.url === \"string\"\n ) {\n source = _formatImage(contentPart.image_url.url);\n }\n if (source) {\n yield {\n type: \"image\" as const, // Explicitly setting the type as \"image\"\n source,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n } as Anthropic.Messages.ImageBlockParam;\n }\n } else if (_isAnthropicImageBlockParam(contentPart)) {\n return contentPart;\n } else if (contentPart.type === \"document\") {\n // PDF\n yield {\n ...contentPart,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n } as Anthropic.Messages.DocumentBlockParam;\n } else if (_isAnthropicThinkingBlock(contentPart)) {\n const block: AnthropicThinkingBlockParam = {\n type: \"thinking\" as const, // Explicitly setting the type as \"thinking\"\n thinking: contentPart.thinking,\n signature: contentPart.signature,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n };\n yield block;\n } else if (_isAnthropicRedactedThinkingBlock(contentPart)) {\n const block: AnthropicRedactedThinkingBlockParam = {\n type: \"redacted_thinking\" as const, // Explicitly setting the type as \"redacted_thinking\"\n data: contentPart.data,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n };\n yield block;\n } else if (_isAnthropicSearchResultBlock(contentPart)) {\n const block: AnthropicSearchResultBlockParam = {\n type: \"search_result\" as const, // Explicitly setting the type as \"search_result\"\n title: contentPart.title,\n source: contentPart.source,\n ...(\"cache_control\" in contentPart && contentPart.cache_control\n ? { cache_control: contentPart.cache_control }\n : {}),\n ...(\"citations\" in contentPart && contentPart.citations\n ? { citations: contentPart.citations }\n : {}),\n content: contentPart.content,\n };\n yield block as Anthropic.Beta.BetaSearchResultBlockParam;\n } else if (\n textTypes.find((t) => t === contentPart.type) &&\n \"text\" in contentPart\n ) {\n // Assuming contentPart is of type MessageContentText here\n yield {\n type: \"text\" as const, // Explicitly setting the type as \"text\"\n text: contentPart.text,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n ...(\"citations\" in contentPart && contentPart.citations\n ? { citations: contentPart.citations }\n : {}),\n } as Anthropic.Messages.TextBlockParam;\n } else if (toolTypes.find((t) => t === contentPart.type)) {\n const contentPartCopy = { ...contentPart };\n\n if (contentPartCopy.type === \"input_json_delta\") {\n // `input_json_delta` type only represents yielding partial tool inputs\n // and is not a valid type for Anthropic messages.\n // These blocks appear in streaming responses and should be skipped\n // as their input data is already captured in tool_calls.\n continue;\n }\n\n if (\n contentPartCopy.type === \"tool_use\" &&\n typeof contentPartCopy.input === \"string\"\n ) {\n // First, try to get the input from the corresponding tool_call.\n // This is the most reliable source since tool_calls are properly\n // consolidated from tool_call_chunks during streaming.\n const matchingToolCall = toolCalls?.find(\n (tc) => tc.id === contentPartCopy.id\n );\n if (matchingToolCall) {\n contentPartCopy.input = matchingToolCall.args;\n } else {\n // Fallback: `tool_use` content part may be followed by `input_json_delta`\n // content parts which are chunks of a stringified JSON input,\n // so we need to collect them and merge their inputs.\n const inputDeltas = content.filter(\n (nestedContentPart) =>\n nestedContentPart.index === contentPartCopy.index &&\n nestedContentPart.type === \"input_json_delta\" &&\n typeof nestedContentPart.input === \"string\"\n );\n // If no `input_json_delta` parts are found, this line will just\n // return `contentPartCopy.input`, so no additional check is needed\n contentPartCopy.input = inputDeltas.reduce(\n (accumulator, nestedContentPart) =>\n accumulator + nestedContentPart.input,\n contentPartCopy.input\n );\n }\n }\n\n if (\"index\" in contentPartCopy) {\n // Anthropic does not support passing the index field here, so we remove it.\n delete contentPartCopy.index;\n }\n\n if (\"input\" in contentPartCopy) {\n // Anthropic tool use inputs should be valid objects, when applicable.\n if (typeof contentPartCopy.input === \"string\") {\n try {\n contentPartCopy.input = JSON.parse(contentPartCopy.input);\n } catch {\n contentPartCopy.input = {};\n }\n }\n }\n // TODO: Fix when SDK types are fixed\n yield {\n ...contentPartCopy,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any;\n } else if (contentPart.type === \"container_upload\") {\n yield {\n ...contentPart,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n } as AnthropicContainerUploadBlockParam;\n }\n\n // Note that we are intentionally dropping any blocks that we don't\n // recognize. This is to allow for cross-compatibility between different\n // providers that may have different block types. Ie if we take a message\n // output from OpenAI and send it to Anthropic, we want to drop any blocks\n // that Anthropic doesn't understand.\n }\n}\n\nfunction _formatContent(message: BaseMessage, toolCalls?: ToolCall[]) {\n const { content } = message;\n\n if (typeof content === \"string\") {\n return content;\n } else {\n return Array.from(_formatContentBlocks(content, toolCalls));\n }\n}\n\n/**\n * Formats messages as a prompt for the model.\n * Used in LangSmith, export is important here.\n * @param messages The base messages to format as a prompt.\n * @returns The formatted prompt.\n */\nexport function _convertMessagesToAnthropicPayload(\n messages: BaseMessage[]\n): AnthropicMessageCreateParams {\n const mergedMessages = _ensureMessageContents(messages);\n let system;\n if (mergedMessages.length > 0 && mergedMessages[0]._getType() === \"system\") {\n system = messages[0].content;\n }\n const conversationMessages =\n system !== undefined ? mergedMessages.slice(1) : mergedMessages;\n const formattedMessages = conversationMessages.map((message) => {\n let role;\n if (message._getType() === \"human\") {\n role = \"user\" as const;\n } else if (message._getType() === \"ai\") {\n role = \"assistant\" as const;\n } else if (message._getType() === \"tool\") {\n role = \"user\" as const;\n } else if (message._getType() === \"system\") {\n throw new Error(\n \"System messages are only permitted as the first passed message.\"\n );\n } else {\n throw new Error(`Message type \"${message.type}\" is not supported.`);\n }\n if (\n AIMessage.isInstance(message) &&\n message.response_metadata?.output_version === \"v1\"\n ) {\n return {\n role,\n content: _formatStandardContent(message),\n };\n }\n if (AIMessage.isInstance(message) && !!message.tool_calls?.length) {\n if (typeof message.content === \"string\") {\n if (message.content === \"\") {\n return {\n role,\n content: message.tool_calls.map(\n _convertLangChainToolCallToAnthropic\n ),\n };\n } else {\n return {\n role,\n content: [\n { type: \"text\", text: message.content },\n ...message.tool_calls.map(_convertLangChainToolCallToAnthropic),\n ],\n };\n }\n } else {\n const { content } = message;\n const hasMismatchedToolCalls = !message.tool_calls.every((toolCall) =>\n content.find(\n (contentPart) =>\n (contentPart.type === \"tool_use\" ||\n contentPart.type === \"input_json_delta\" ||\n contentPart.type === \"server_tool_use\") &&\n contentPart.id === toolCall.id\n )\n );\n if (hasMismatchedToolCalls) {\n console.warn(\n `The \"tool_calls\" field on a message is only respected if content is a string.`\n );\n }\n return {\n role,\n content: _formatContent(message, message.tool_calls),\n };\n }\n } else {\n return {\n role,\n content: _formatContent(\n message,\n AIMessage.isInstance(message) ? message.tool_calls : undefined\n ),\n };\n }\n });\n return {\n messages: mergeMessages(\n formattedMessages as AnthropicMessageCreateParams[\"messages\"]\n ),\n system,\n } as AnthropicMessageCreateParams;\n}\n\nfunction mergeMessages(messages: AnthropicMessageCreateParams[\"messages\"]) {\n if (!messages || messages.length <= 1) {\n return messages;\n }\n\n const result: AnthropicMessageCreateParams[\"messages\"] = [];\n let currentMessage = messages[0];\n\n const normalizeContent = (\n content:\n | string\n | Array<\n | AnthropicTextBlockParam\n | AnthropicImageBlockParam\n | AnthropicToolUseBlockParam\n | AnthropicToolResultBlockParam\n | AnthropicDocumentBlockParam\n | AnthropicThinkingBlockParam\n | AnthropicRedactedThinkingBlockParam\n | AnthropicServerToolUseBlockParam\n | AnthropicWebSearchToolResultBlockParam\n | AnthropicSearchResultBlockParam\n >\n ): Array<\n | AnthropicTextBlockParam\n | AnthropicImageBlockParam\n | AnthropicToolUseBlockParam\n | AnthropicToolResultBlockParam\n | AnthropicDocumentBlockParam\n | AnthropicThinkingBlockParam\n | AnthropicRedactedThinkingBlockParam\n | AnthropicServerToolUseBlockParam\n | AnthropicWebSearchToolResultBlockParam\n | AnthropicSearchResultBlockParam\n > => {\n if (typeof content === \"string\") {\n return [\n {\n type: \"text\",\n text: content,\n },\n ];\n }\n return content;\n };\n\n const isToolResultMessage = (msg: (typeof messages)[0]) => {\n if (msg.role !== \"user\") return false;\n\n if (typeof msg.content === \"string\") {\n return false;\n }\n\n return (\n Array.isArray(msg.content) &&\n msg.content.every((item) => item.type === \"tool_result\")\n );\n };\n\n for (let i = 1; i < messages.length; i += 1) {\n const nextMessage = messages[i];\n\n if (\n isToolResultMessage(currentMessage) &&\n isToolResultMessage(nextMessage)\n ) {\n // Merge the messages by combining their content arrays\n currentMessage = {\n ...currentMessage,\n content: [\n ...normalizeContent(currentMessage.content),\n ...normalizeContent(nextMessage.content),\n ],\n };\n } else {\n result.push(currentMessage);\n currentMessage = nextMessage;\n }\n }\n\n result.push(currentMessage);\n return result;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"message_inputs.js","names":["imageUrl: string","parsedUrl: URL","messages: BaseMessage[]","toolCall: ToolCall","content: ContentBlock[]","toolCalls?: ToolCall[]","source:\n | { type: \"url\"; url: string }\n | { type: \"base64\"; media_type: string; data: string }\n | { type: \"file\"; file_id: string }\n | undefined","block: AnthropicThinkingBlockParam","block: AnthropicRedactedThinkingBlockParam","block: AnthropicSearchResultBlockParam","message: BaseMessage","payload: AnthropicMessageCreateParams","cacheControl: CacheControl","messages: AnthropicMessageCreateParams[\"messages\"]","result: AnthropicMessageCreateParams[\"messages\"]","content:\n | string\n | Array<\n | AnthropicTextBlockParam\n | AnthropicImageBlockParam\n | AnthropicToolUseBlockParam\n | AnthropicToolResultBlockParam\n | AnthropicDocumentBlockParam\n | AnthropicThinkingBlockParam\n | AnthropicRedactedThinkingBlockParam\n | AnthropicServerToolUseBlockParam\n | AnthropicWebSearchToolResultBlockParam\n | AnthropicSearchResultBlockParam\n >","msg: (typeof messages)[0]"],"sources":["../../src/utils/message_inputs.ts"],"sourcesContent":["/**\n * This util file contains functions for converting LangChain messages to Anthropic messages.\n */\nimport type Anthropic from \"@anthropic-ai/sdk\";\nimport {\n type BaseMessage,\n HumanMessage,\n ToolMessage,\n MessageContentComplex,\n isDataContentBlock,\n convertToProviderContentBlock,\n parseBase64DataUrl,\n ContentBlock,\n AIMessage,\n} from \"@langchain/core/messages\";\nimport { ToolCall } from \"@langchain/core/messages/tool\";\nimport {\n AnthropicImageBlockParam,\n AnthropicMessageCreateParams,\n AnthropicTextBlockParam,\n AnthropicToolResultBlockParam,\n AnthropicToolUseBlockParam,\n AnthropicDocumentBlockParam,\n AnthropicThinkingBlockParam,\n AnthropicRedactedThinkingBlockParam,\n AnthropicServerToolUseBlockParam,\n AnthropicWebSearchToolResultBlockParam,\n AnthropicSearchResultBlockParam,\n AnthropicToolResponse,\n AnthropicContainerUploadBlockParam,\n} from \"../types.js\";\nimport {\n _isAnthropicImageBlockParam,\n _isAnthropicRedactedThinkingBlock,\n _isAnthropicSearchResultBlock,\n _isAnthropicThinkingBlock,\n standardContentBlockConverter,\n} from \"./content.js\";\nimport { _formatStandardContent } from \"./standard.js\";\n\nfunction _formatImage(imageUrl: string) {\n const parsed = parseBase64DataUrl({ dataUrl: imageUrl });\n if (parsed) {\n return {\n type: \"base64\",\n media_type: parsed.mime_type,\n data: parsed.data,\n };\n }\n let parsedUrl: URL;\n\n try {\n parsedUrl = new URL(imageUrl);\n } catch {\n throw new Error(\n [\n `Malformed image URL: ${JSON.stringify(\n imageUrl\n )}. Content blocks of type 'image_url' must be a valid http, https, or base64-encoded data URL.`,\n \"Example: data:image/png;base64,/9j/4AAQSk...\",\n \"Example: https://example.com/image.jpg\",\n ].join(\"\\n\\n\")\n );\n }\n\n if (parsedUrl.protocol === \"http:\" || parsedUrl.protocol === \"https:\") {\n return {\n type: \"url\",\n url: imageUrl,\n };\n }\n\n throw new Error(\n [\n `Invalid image URL protocol: ${JSON.stringify(\n parsedUrl.protocol\n )}. Anthropic only supports images as http, https, or base64-encoded data URLs on 'image_url' content blocks.`,\n \"Example: data:image/png;base64,/9j/4AAQSk...\",\n \"Example: https://example.com/image.jpg\",\n ].join(\"\\n\\n\")\n );\n}\n\nfunction _ensureMessageContents(messages: BaseMessage[]): BaseMessage[] {\n // Merge runs of human/tool messages into single human messages with content blocks.\n const updatedMsgs = [];\n for (const message of messages) {\n if (message._getType() === \"tool\") {\n if (typeof message.content === \"string\") {\n const previousMessage = updatedMsgs[updatedMsgs.length - 1];\n if (\n previousMessage?._getType() === \"human\" &&\n Array.isArray(previousMessage.content) &&\n \"type\" in previousMessage.content[0] &&\n previousMessage.content[0].type === \"tool_result\"\n ) {\n // If the previous message was a tool result, we merge this tool message into it.\n (previousMessage.content as MessageContentComplex[]).push({\n type: \"tool_result\",\n content: message.content,\n tool_use_id: (message as ToolMessage).tool_call_id,\n });\n } else {\n // If not, we create a new human message with the tool result.\n updatedMsgs.push(\n new HumanMessage({\n content: [\n {\n type: \"tool_result\",\n content: message.content,\n tool_use_id: (message as ToolMessage).tool_call_id,\n },\n ],\n })\n );\n }\n } else {\n updatedMsgs.push(\n new HumanMessage({\n content: [\n {\n type: \"tool_result\",\n // rare case: message.content could be undefined\n ...(message.content != null\n ? { content: _formatContent(message) }\n : {}),\n tool_use_id: (message as ToolMessage).tool_call_id,\n },\n ],\n })\n );\n }\n } else {\n updatedMsgs.push(message);\n }\n }\n return updatedMsgs;\n}\n\nexport function _convertLangChainToolCallToAnthropic(\n toolCall: ToolCall\n): AnthropicToolResponse {\n if (toolCall.id === undefined) {\n throw new Error(`Anthropic requires all tool calls to have an \"id\".`);\n }\n return {\n type: \"tool_use\",\n id: toolCall.id,\n name: toolCall.name,\n input: toolCall.args,\n };\n}\n\nfunction* _formatContentBlocks(\n content: ContentBlock[],\n toolCalls?: ToolCall[]\n): Generator<Anthropic.Beta.BetaContentBlockParam> {\n const toolTypes = [\n \"bash_code_execution_tool_result\",\n \"input_json_delta\",\n \"server_tool_use\",\n \"text_editor_code_execution_tool_result\",\n \"tool_result\",\n \"tool_use\",\n \"web_search_result\",\n \"web_search_tool_result\",\n ];\n const textTypes = [\"text\", \"text_delta\"];\n for (const contentPart of content) {\n if (isDataContentBlock(contentPart)) {\n yield convertToProviderContentBlock(\n contentPart,\n standardContentBlockConverter\n );\n }\n\n const cacheControl =\n \"cache_control\" in contentPart ? contentPart.cache_control : undefined;\n\n if (contentPart.type === \"image_url\") {\n let source;\n if (typeof contentPart.image_url === \"string\") {\n source = _formatImage(contentPart.image_url);\n } else if (\n typeof contentPart.image_url === \"object\" &&\n contentPart.image_url !== null &&\n \"url\" in contentPart.image_url &&\n typeof contentPart.image_url.url === \"string\"\n ) {\n source = _formatImage(contentPart.image_url.url);\n }\n if (source) {\n yield {\n type: \"image\" as const, // Explicitly setting the type as \"image\"\n source,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n } as Anthropic.Messages.ImageBlockParam;\n }\n } else if (_isAnthropicImageBlockParam(contentPart)) {\n yield contentPart;\n } else if (contentPart.type === \"image\") {\n // Handle new ContentBlock.Multimodal.Image format\n let source;\n\n if (\"url\" in contentPart && typeof contentPart.url === \"string\") {\n // URL-based image\n source = _formatImage(contentPart.url);\n } else if (\n \"data\" in contentPart &&\n (typeof contentPart.data === \"string\" ||\n // eslint-disable-next-line no-instanceof/no-instanceof\n contentPart.data instanceof Uint8Array)\n ) {\n // Base64-based image\n const mimeType =\n \"mimeType\" in contentPart && typeof contentPart.mimeType === \"string\"\n ? contentPart.mimeType\n : \"image/jpeg\";\n const data =\n typeof contentPart.data === \"string\"\n ? contentPart.data\n : Buffer.from(contentPart.data).toString(\"base64\");\n source = {\n type: \"base64\" as const,\n media_type: mimeType as\n | \"image/jpeg\"\n | \"image/png\"\n | \"image/gif\"\n | \"image/webp\",\n data,\n };\n } else if (\n \"fileId\" in contentPart &&\n typeof contentPart.fileId === \"string\"\n ) {\n // File ID-based image\n // Note: Anthropic supports file IDs for images that have been uploaded\n // to their servers via the Files API\n source = {\n type: \"file\" as const,\n file_id: contentPart.fileId,\n };\n }\n\n if (source) {\n yield {\n type: \"image\" as const,\n source,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n } as Anthropic.Messages.ImageBlockParam;\n }\n } else if (contentPart.type === \"file\") {\n // Handle new ContentBlock.Multimodal.File format\n let source:\n | { type: \"url\"; url: string }\n | { type: \"base64\"; media_type: string; data: string }\n | { type: \"file\"; file_id: string }\n | undefined;\n\n if (\"url\" in contentPart && typeof contentPart.url === \"string\") {\n // File with URL\n source = {\n type: \"url\" as const,\n url: contentPart.url,\n };\n } else if (\n \"data\" in contentPart &&\n (typeof contentPart.data === \"string\" ||\n // eslint-disable-next-line no-instanceof/no-instanceof\n contentPart.data instanceof Uint8Array)\n ) {\n // File with base64 data (string or Uint8Array)\n const media_type =\n \"mimeType\" in contentPart && typeof contentPart.mimeType === \"string\"\n ? contentPart.mimeType\n : \"application/pdf\";\n const data =\n typeof contentPart.data === \"string\"\n ? contentPart.data\n : Buffer.from(contentPart.data).toString(\"base64\");\n\n source = {\n type: \"base64\" as const,\n media_type,\n data,\n };\n } else if (\n \"fileId\" in contentPart &&\n typeof contentPart.fileId === \"string\"\n ) {\n // File ID from Anthropic Files API\n // https://platform.claude.com/docs/en/build-with-claude/pdf-support#option-3-files-api\n source = {\n type: \"file\" as const,\n file_id: contentPart.fileId,\n };\n }\n\n if (source) {\n yield {\n type: \"document\" as const,\n source,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n } as Anthropic.Messages.DocumentBlockParam;\n }\n } else if (contentPart.type === \"document\") {\n // PDF\n yield {\n ...contentPart,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n } as Anthropic.Messages.DocumentBlockParam;\n } else if (_isAnthropicThinkingBlock(contentPart)) {\n const block: AnthropicThinkingBlockParam = {\n type: \"thinking\" as const, // Explicitly setting the type as \"thinking\"\n thinking: contentPart.thinking,\n signature: contentPart.signature,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n };\n yield block;\n } else if (_isAnthropicRedactedThinkingBlock(contentPart)) {\n const block: AnthropicRedactedThinkingBlockParam = {\n type: \"redacted_thinking\" as const, // Explicitly setting the type as \"redacted_thinking\"\n data: contentPart.data,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n };\n yield block;\n } else if (_isAnthropicSearchResultBlock(contentPart)) {\n const block: AnthropicSearchResultBlockParam = {\n type: \"search_result\" as const, // Explicitly setting the type as \"search_result\"\n title: contentPart.title,\n source: contentPart.source,\n ...(\"cache_control\" in contentPart && contentPart.cache_control\n ? { cache_control: contentPart.cache_control }\n : {}),\n ...(\"citations\" in contentPart && contentPart.citations\n ? { citations: contentPart.citations }\n : {}),\n content: contentPart.content,\n };\n yield block as Anthropic.Beta.BetaSearchResultBlockParam;\n } else if (\n textTypes.find((t) => t === contentPart.type) &&\n \"text\" in contentPart\n ) {\n // Assuming contentPart is of type MessageContentText here\n yield {\n type: \"text\" as const, // Explicitly setting the type as \"text\"\n text: contentPart.text,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n ...(\"citations\" in contentPart && contentPart.citations\n ? { citations: contentPart.citations }\n : {}),\n } as Anthropic.Messages.TextBlockParam;\n } else if (toolTypes.find((t) => t === contentPart.type)) {\n const contentPartCopy = { ...contentPart };\n\n if (contentPartCopy.type === \"input_json_delta\") {\n // `input_json_delta` type only represents yielding partial tool inputs\n // and is not a valid type for Anthropic messages.\n // These blocks appear in streaming responses and should be skipped\n // as their input data is already captured in tool_calls.\n continue;\n }\n\n if (\n contentPartCopy.type === \"tool_use\" &&\n typeof contentPartCopy.input === \"string\"\n ) {\n // First, try to get the input from the corresponding tool_call.\n // This is the most reliable source since tool_calls are properly\n // consolidated from tool_call_chunks during streaming.\n const matchingToolCall = toolCalls?.find(\n (tc) => tc.id === contentPartCopy.id\n );\n if (matchingToolCall) {\n contentPartCopy.input = matchingToolCall.args;\n } else {\n // Fallback: `tool_use` content part may be followed by `input_json_delta`\n // content parts which are chunks of a stringified JSON input,\n // so we need to collect them and merge their inputs.\n const inputDeltas = content.filter(\n (nestedContentPart) =>\n nestedContentPart.index === contentPartCopy.index &&\n nestedContentPart.type === \"input_json_delta\" &&\n typeof nestedContentPart.input === \"string\"\n );\n // If no `input_json_delta` parts are found, this line will just\n // return `contentPartCopy.input`, so no additional check is needed\n contentPartCopy.input = inputDeltas.reduce(\n (accumulator, nestedContentPart) =>\n accumulator + nestedContentPart.input,\n contentPartCopy.input\n );\n }\n }\n\n if (\"index\" in contentPartCopy) {\n // Anthropic does not support passing the index field here, so we remove it.\n delete contentPartCopy.index;\n }\n\n if (\"input\" in contentPartCopy) {\n // Anthropic tool use inputs should be valid objects, when applicable.\n if (typeof contentPartCopy.input === \"string\") {\n try {\n contentPartCopy.input = JSON.parse(contentPartCopy.input);\n } catch {\n contentPartCopy.input = {};\n }\n }\n }\n // TODO: Fix when SDK types are fixed\n yield {\n ...contentPartCopy,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any;\n } else if (contentPart.type === \"container_upload\") {\n yield {\n ...contentPart,\n ...(cacheControl ? { cache_control: cacheControl } : {}),\n } as AnthropicContainerUploadBlockParam;\n }\n\n // Note that we are intentionally dropping any blocks that we don't\n // recognize. This is to allow for cross-compatibility between different\n // providers that may have different block types. Ie if we take a message\n // output from OpenAI and send it to Anthropic, we want to drop any blocks\n // that Anthropic doesn't understand.\n }\n}\n\nfunction _formatContent(message: BaseMessage, toolCalls?: ToolCall[]) {\n const { content } = message;\n\n if (typeof content === \"string\") {\n return content;\n } else {\n return Array.from(_formatContentBlocks(content, toolCalls));\n }\n}\n\n/**\n * Formats messages as a prompt for the model.\n * Used in LangSmith, export is important here.\n * @param messages The base messages to format as a prompt.\n * @returns The formatted prompt.\n */\nexport function _convertMessagesToAnthropicPayload(\n messages: BaseMessage[]\n): AnthropicMessageCreateParams {\n const mergedMessages = _ensureMessageContents(messages);\n let system;\n if (mergedMessages.length > 0 && mergedMessages[0]._getType() === \"system\") {\n system = messages[0].content;\n }\n const conversationMessages =\n system !== undefined ? mergedMessages.slice(1) : mergedMessages;\n const formattedMessages = conversationMessages.map((message) => {\n let role;\n if (message._getType() === \"human\") {\n role = \"user\" as const;\n } else if (message._getType() === \"ai\") {\n role = \"assistant\" as const;\n } else if (message._getType() === \"tool\") {\n role = \"user\" as const;\n } else if (message._getType() === \"system\") {\n throw new Error(\n \"System messages are only permitted as the first passed message.\"\n );\n } else {\n throw new Error(`Message type \"${message.type}\" is not supported.`);\n }\n if (\n AIMessage.isInstance(message) &&\n message.response_metadata?.output_version === \"v1\"\n ) {\n return {\n role,\n content: _formatStandardContent(message),\n };\n }\n if (AIMessage.isInstance(message) && !!message.tool_calls?.length) {\n if (typeof message.content === \"string\") {\n if (message.content === \"\") {\n return {\n role,\n content: message.tool_calls.map(\n _convertLangChainToolCallToAnthropic\n ),\n };\n } else {\n return {\n role,\n content: [\n { type: \"text\", text: message.content },\n ...message.tool_calls.map(_convertLangChainToolCallToAnthropic),\n ],\n };\n }\n } else {\n const { content } = message;\n const hasMismatchedToolCalls = !message.tool_calls.every((toolCall) =>\n content.find(\n (contentPart) =>\n (contentPart.type === \"tool_use\" ||\n contentPart.type === \"input_json_delta\" ||\n contentPart.type === \"server_tool_use\") &&\n contentPart.id === toolCall.id\n )\n );\n if (hasMismatchedToolCalls) {\n console.warn(\n `The \"tool_calls\" field on a message is only respected if content is a string.`\n );\n }\n return {\n role,\n content: _formatContent(message, message.tool_calls),\n };\n }\n } else {\n return {\n role,\n content: _formatContent(\n message,\n AIMessage.isInstance(message) ? message.tool_calls : undefined\n ),\n };\n }\n });\n return {\n messages: mergeMessages(\n formattedMessages as AnthropicMessageCreateParams[\"messages\"]\n ),\n system,\n } as AnthropicMessageCreateParams;\n}\n\n/**\n * Cache control configuration for Anthropic prompt caching.\n */\ninterface CacheControl {\n type: \"ephemeral\";\n ttl?: \"5m\" | \"1h\";\n}\n\n/**\n * Applies cache_control to the last content block of the last message in the payload.\n * This is the recommended approach for prompt caching as it applies the cache_control\n * at the final formatting layer, after all message processing is complete.\n *\n * This matches the Python langchain-anthropic implementation where cache_control\n * is applied via model_settings rather than modifying message content blocks directly.\n *\n * @param payload - The formatted Anthropic message payload\n * @param cacheControl - The cache control configuration to apply\n * @returns The payload with cache_control applied to the last content block\n */\nexport function applyCacheControlToPayload(\n payload: AnthropicMessageCreateParams,\n cacheControl: CacheControl\n): AnthropicMessageCreateParams {\n if (!payload.messages || payload.messages.length === 0) {\n return payload;\n }\n\n const messages = [...payload.messages];\n const lastMessageIndex = messages.length - 1;\n const lastMessage = messages[lastMessageIndex];\n\n if (!lastMessage) {\n return payload;\n }\n\n // Handle string content - convert to text block with cache_control\n if (typeof lastMessage.content === \"string\") {\n messages[lastMessageIndex] = {\n ...lastMessage,\n content: [\n {\n type: \"text\",\n text: lastMessage.content,\n cache_control: cacheControl,\n },\n ],\n };\n return { ...payload, messages };\n }\n\n // Handle array content - add cache_control to the last block\n if (Array.isArray(lastMessage.content) && lastMessage.content.length > 0) {\n const content = [...lastMessage.content];\n const lastBlockIndex = content.length - 1;\n const lastBlock = content[lastBlockIndex];\n\n // Add cache_control to the last block\n content[lastBlockIndex] = {\n ...lastBlock,\n cache_control: cacheControl,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n } as any;\n\n messages[lastMessageIndex] = {\n ...lastMessage,\n content,\n };\n return { ...payload, messages };\n }\n\n return payload;\n}\n\nfunction mergeMessages(messages: AnthropicMessageCreateParams[\"messages\"]) {\n if (!messages || messages.length <= 1) {\n return messages;\n }\n\n const result: AnthropicMessageCreateParams[\"messages\"] = [];\n let currentMessage = messages[0];\n\n const normalizeContent = (\n content:\n | string\n | Array<\n | AnthropicTextBlockParam\n | AnthropicImageBlockParam\n | AnthropicToolUseBlockParam\n | AnthropicToolResultBlockParam\n | AnthropicDocumentBlockParam\n | AnthropicThinkingBlockParam\n | AnthropicRedactedThinkingBlockParam\n | AnthropicServerToolUseBlockParam\n | AnthropicWebSearchToolResultBlockParam\n | AnthropicSearchResultBlockParam\n >\n ): Array<\n | AnthropicTextBlockParam\n | AnthropicImageBlockParam\n | AnthropicToolUseBlockParam\n | AnthropicToolResultBlockParam\n | AnthropicDocumentBlockParam\n | AnthropicThinkingBlockParam\n | AnthropicRedactedThinkingBlockParam\n | AnthropicServerToolUseBlockParam\n | AnthropicWebSearchToolResultBlockParam\n | AnthropicSearchResultBlockParam\n > => {\n if (typeof content === \"string\") {\n return [\n {\n type: \"text\",\n text: content,\n },\n ];\n }\n return content;\n };\n\n const isToolResultMessage = (msg: (typeof messages)[0]) => {\n if (msg.role !== \"user\") return false;\n\n if (typeof msg.content === \"string\") {\n return false;\n }\n\n return (\n Array.isArray(msg.content) &&\n msg.content.every((item) => item.type === \"tool_result\")\n );\n };\n\n for (let i = 1; i < messages.length; i += 1) {\n const nextMessage = messages[i];\n\n if (\n isToolResultMessage(currentMessage) &&\n isToolResultMessage(nextMessage)\n ) {\n // Merge the messages by combining their content arrays\n currentMessage = {\n ...currentMessage,\n content: [\n ...normalizeContent(currentMessage.content),\n ...normalizeContent(nextMessage.content),\n ],\n };\n } else {\n result.push(currentMessage);\n currentMessage = nextMessage;\n }\n }\n\n result.push(currentMessage);\n return result;\n}\n"],"mappings":"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"}
@@ -10,16 +10,7 @@ function _makeMessageChunkFromAnthropicEvent(data, fields) {
10
10
  const filteredAdditionalKwargs = {};
11
11
  for (const [key, value] of Object.entries(additionalKwargs)) if (value !== void 0 && value !== null) filteredAdditionalKwargs[key] = value;
12
12
  const { input_tokens, output_tokens,...rest } = usage ?? {};
13
- const totalInputTokens = input_tokens + rest.cache_creation_input_tokens + rest.cache_read_input_tokens;
14
- const usageMetadata = {
15
- input_tokens: totalInputTokens,
16
- output_tokens,
17
- total_tokens: totalInputTokens + output_tokens,
18
- input_token_details: {
19
- cache_creation: rest.cache_creation_input_tokens,
20
- cache_read: rest.cache_read_input_tokens
21
- }
22
- };
13
+ const usageMetadata = buildUsageMetadata(usage);
23
14
  return { chunk: new __langchain_core_messages.AIMessageChunk({
24
15
  content: fields.coerceContentToString ? "" : [],
25
16
  additional_kwargs: filteredAdditionalKwargs,
@@ -149,15 +140,7 @@ function anthropicResponseToChatMessages(messages, additionalKwargs) {
149
140
  model_provider: "anthropic"
150
141
  };
151
142
  const usage = additionalKwargs.usage;
152
- const usageMetadata = usage != null ? {
153
- input_tokens: usage.input_tokens ?? 0,
154
- output_tokens: usage.output_tokens ?? 0,
155
- total_tokens: (usage.input_tokens ?? 0) + (usage.output_tokens ?? 0),
156
- input_token_details: {
157
- cache_creation: usage.cache_creation_input_tokens,
158
- cache_read: usage.cache_read_input_tokens
159
- }
160
- } : void 0;
143
+ const usageMetadata = usage != null ? buildUsageMetadata(usage) : void 0;
161
144
  if (messages.length === 1 && messages[0].type === "text") return [{
162
145
  text: messages[0].text,
163
146
  message: new __langchain_core_messages.AIMessage({
@@ -184,6 +167,20 @@ function anthropicResponseToChatMessages(messages, additionalKwargs) {
184
167
  return generations;
185
168
  }
186
169
  }
170
+ function buildUsageMetadata(usage) {
171
+ const cacheCreationInputTokens = usage.cache_creation_input_tokens ?? 0;
172
+ const cacheReadInputTokens = usage.cache_read_input_tokens ?? 0;
173
+ const totalInputTokens = usage.input_tokens + cacheCreationInputTokens + cacheReadInputTokens;
174
+ return {
175
+ input_tokens: totalInputTokens,
176
+ output_tokens: usage.output_tokens,
177
+ total_tokens: totalInputTokens + usage.output_tokens,
178
+ input_token_details: {
179
+ cache_creation: cacheCreationInputTokens,
180
+ cache_read: cacheReadInputTokens
181
+ }
182
+ };
183
+ }
187
184
 
188
185
  //#endregion
189
186
  exports._makeMessageChunkFromAnthropicEvent = _makeMessageChunkFromAnthropicEvent;
@@ -1 +1 @@
1
- {"version":3,"file":"message_outputs.cjs","names":["data: Anthropic.Messages.RawMessageStreamEvent","fields: {\n streamUsage: boolean;\n coerceContentToString: boolean;\n }","filteredAdditionalKwargs: Record<string, any>","usageMetadata: UsageMetadata","AIMessageChunk","toolCallChunks: ToolCallChunk[]","contentBlock: Record<string, any>","messages: AnthropicMessageResponse[]","additionalKwargs: Record<string, unknown>","usage: Record<string, number> | null | undefined","AIMessage","extractToolCalls","generations: ChatGeneration[]"],"sources":["../../src/utils/message_outputs.ts"],"sourcesContent":["/**\n * This util file contains functions for converting Anthropic messages to LangChain messages.\n */\nimport Anthropic from \"@anthropic-ai/sdk\";\nimport {\n AIMessage,\n AIMessageChunk,\n UsageMetadata,\n} from \"@langchain/core/messages\";\nimport type { ToolCallChunk } from \"@langchain/core/messages/tool\";\nimport { ChatGeneration } from \"@langchain/core/outputs\";\nimport { AnthropicMessageResponse } from \"../types.js\";\nimport { extractToolCalls } from \"../output_parsers.js\";\n\nexport function _makeMessageChunkFromAnthropicEvent(\n data: Anthropic.Messages.RawMessageStreamEvent,\n fields: {\n streamUsage: boolean;\n coerceContentToString: boolean;\n }\n): {\n chunk: AIMessageChunk;\n} | null {\n const response_metadata = { model_provider: \"anthropic\" };\n if (data.type === \"message_start\") {\n const { content, usage, ...additionalKwargs } = data.message;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const filteredAdditionalKwargs: Record<string, any> = {};\n for (const [key, value] of Object.entries(additionalKwargs)) {\n if (value !== undefined && value !== null) {\n filteredAdditionalKwargs[key] = value;\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const { input_tokens, output_tokens, ...rest }: Record<string, any> =\n usage ?? {};\n // Total input tokens in a Claude API request is the summation of `input_tokens`, `cache_creation_input_tokens`, and `cache_read_input_tokens`.\n // ref: https://platform.claude.com/docs/en/api/messages\n const totalInputTokens =\n input_tokens +\n rest.cache_creation_input_tokens +\n rest.cache_read_input_tokens;\n const usageMetadata: UsageMetadata = {\n input_tokens: totalInputTokens,\n output_tokens,\n total_tokens: totalInputTokens + output_tokens,\n input_token_details: {\n cache_creation: rest.cache_creation_input_tokens,\n cache_read: rest.cache_read_input_tokens,\n },\n };\n return {\n chunk: new AIMessageChunk({\n content: fields.coerceContentToString ? \"\" : [],\n additional_kwargs: filteredAdditionalKwargs,\n usage_metadata: fields.streamUsage ? usageMetadata : undefined,\n response_metadata: {\n ...response_metadata,\n usage: {\n ...rest,\n },\n },\n id: data.message.id,\n }),\n };\n } else if (data.type === \"message_delta\") {\n const usageMetadata: UsageMetadata = {\n input_tokens: 0,\n output_tokens: data.usage.output_tokens,\n total_tokens: data.usage.output_tokens,\n input_token_details: {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n cache_creation: (data.usage as any).cache_creation_input_tokens,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n cache_read: (data.usage as any).cache_read_input_tokens,\n },\n };\n const responseMetadata =\n \"context_management\" in data.delta\n ? { context_management: data.delta.context_management }\n : undefined;\n return {\n chunk: new AIMessageChunk({\n content: fields.coerceContentToString ? \"\" : [],\n response_metadata: responseMetadata,\n additional_kwargs: { ...data.delta },\n usage_metadata: fields.streamUsage ? usageMetadata : undefined,\n }),\n };\n } else if (\n data.type === \"content_block_start\" &&\n [\n \"tool_use\",\n \"document\",\n \"server_tool_use\",\n \"web_search_tool_result\",\n ].includes(data.content_block.type)\n ) {\n const contentBlock = data.content_block;\n let toolCallChunks: ToolCallChunk[];\n if (contentBlock.type === \"tool_use\") {\n toolCallChunks = [\n {\n id: contentBlock.id,\n index: data.index,\n name: contentBlock.name,\n args: \"\",\n },\n ];\n } else {\n toolCallChunks = [];\n }\n return {\n chunk: new AIMessageChunk({\n content: fields.coerceContentToString\n ? \"\"\n : [\n {\n index: data.index,\n ...data.content_block,\n input:\n contentBlock.type === \"server_tool_use\" ||\n contentBlock.type === \"tool_use\"\n ? \"\"\n : undefined,\n },\n ],\n response_metadata,\n additional_kwargs: {},\n tool_call_chunks: toolCallChunks,\n }),\n };\n } else if (\n data.type === \"content_block_delta\" &&\n [\n \"text_delta\",\n \"citations_delta\",\n \"thinking_delta\",\n \"signature_delta\",\n ].includes(data.delta.type)\n ) {\n if (fields.coerceContentToString && \"text\" in data.delta) {\n return {\n chunk: new AIMessageChunk({\n content: data.delta.text,\n }),\n };\n } else {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const contentBlock: Record<string, any> = data.delta;\n if (\"citation\" in contentBlock) {\n contentBlock.citations = [contentBlock.citation];\n delete contentBlock.citation;\n }\n if (\n contentBlock.type === \"thinking_delta\" ||\n contentBlock.type === \"signature_delta\"\n ) {\n return {\n chunk: new AIMessageChunk({\n content: [{ index: data.index, ...contentBlock, type: \"thinking\" }],\n response_metadata,\n }),\n };\n }\n\n return {\n chunk: new AIMessageChunk({\n content: [{ index: data.index, ...contentBlock, type: \"text\" }],\n response_metadata,\n }),\n };\n }\n } else if (\n data.type === \"content_block_delta\" &&\n data.delta.type === \"input_json_delta\"\n ) {\n return {\n chunk: new AIMessageChunk({\n content: fields.coerceContentToString\n ? \"\"\n : [\n {\n index: data.index,\n input: data.delta.partial_json,\n type: data.delta.type,\n },\n ],\n response_metadata,\n additional_kwargs: {},\n tool_call_chunks: [\n {\n index: data.index,\n args: data.delta.partial_json,\n },\n ],\n }),\n };\n } else if (\n data.type === \"content_block_start\" &&\n data.content_block.type === \"text\"\n ) {\n const content = data.content_block?.text;\n if (content !== undefined) {\n return {\n chunk: new AIMessageChunk({\n content: fields.coerceContentToString\n ? content\n : [\n {\n index: data.index,\n ...data.content_block,\n },\n ],\n response_metadata,\n additional_kwargs: {},\n }),\n };\n }\n } else if (\n data.type === \"content_block_start\" &&\n data.content_block.type === \"redacted_thinking\"\n ) {\n return {\n chunk: new AIMessageChunk({\n content: fields.coerceContentToString\n ? \"\"\n : [{ index: data.index, ...data.content_block }],\n response_metadata,\n }),\n };\n } else if (\n data.type === \"content_block_start\" &&\n data.content_block.type === \"thinking\"\n ) {\n const content = data.content_block.thinking;\n return {\n chunk: new AIMessageChunk({\n content: fields.coerceContentToString\n ? content\n : [{ index: data.index, ...data.content_block }],\n response_metadata,\n }),\n };\n }\n return null;\n}\n\nexport function anthropicResponseToChatMessages(\n messages: AnthropicMessageResponse[],\n additionalKwargs: Record<string, unknown>\n): ChatGeneration[] {\n const response_metadata = {\n ...additionalKwargs,\n model_provider: \"anthropic\",\n };\n const usage: Record<string, number> | null | undefined =\n additionalKwargs.usage as Record<string, number> | null | undefined;\n const usageMetadata =\n usage != null\n ? {\n input_tokens: usage.input_tokens ?? 0,\n output_tokens: usage.output_tokens ?? 0,\n total_tokens: (usage.input_tokens ?? 0) + (usage.output_tokens ?? 0),\n input_token_details: {\n cache_creation: usage.cache_creation_input_tokens,\n cache_read: usage.cache_read_input_tokens,\n },\n }\n : undefined;\n if (messages.length === 1 && messages[0].type === \"text\") {\n return [\n {\n text: messages[0].text,\n message: new AIMessage({\n content: messages[0].text,\n additional_kwargs: additionalKwargs,\n usage_metadata: usageMetadata,\n response_metadata,\n id: additionalKwargs.id as string,\n }),\n },\n ];\n } else {\n const toolCalls = extractToolCalls(messages);\n const generations: ChatGeneration[] = [\n {\n text: \"\",\n message: new AIMessage({\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n content: messages as any,\n additional_kwargs: additionalKwargs,\n tool_calls: toolCalls,\n usage_metadata: usageMetadata,\n response_metadata,\n id: additionalKwargs.id as string,\n }),\n },\n ];\n return generations;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"message_outputs.cjs","names":["data: Anthropic.Messages.RawMessageStreamEvent","fields: {\n streamUsage: boolean;\n coerceContentToString: boolean;\n }","filteredAdditionalKwargs: Record<string, any>","AIMessageChunk","usageMetadata: UsageMetadata","toolCallChunks: ToolCallChunk[]","contentBlock: Record<string, any>","messages: AnthropicMessageResponse[]","additionalKwargs: Record<string, unknown>","usage: Record<string, number> | null | undefined","AIMessage","extractToolCalls","generations: ChatGeneration[]","usage: Anthropic.Messages.Usage | Record<string, number>"],"sources":["../../src/utils/message_outputs.ts"],"sourcesContent":["/**\n * This util file contains functions for converting Anthropic messages to LangChain messages.\n */\nimport Anthropic from \"@anthropic-ai/sdk\";\nimport {\n AIMessage,\n AIMessageChunk,\n UsageMetadata,\n} from \"@langchain/core/messages\";\nimport type { ToolCallChunk } from \"@langchain/core/messages/tool\";\nimport { ChatGeneration } from \"@langchain/core/outputs\";\nimport { AnthropicMessageResponse } from \"../types.js\";\nimport { extractToolCalls } from \"../output_parsers.js\";\n\nexport function _makeMessageChunkFromAnthropicEvent(\n data: Anthropic.Messages.RawMessageStreamEvent,\n fields: {\n streamUsage: boolean;\n coerceContentToString: boolean;\n }\n): {\n chunk: AIMessageChunk;\n} | null {\n const response_metadata = { model_provider: \"anthropic\" };\n if (data.type === \"message_start\") {\n const { content, usage, ...additionalKwargs } = data.message;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const filteredAdditionalKwargs: Record<string, any> = {};\n for (const [key, value] of Object.entries(additionalKwargs)) {\n if (value !== undefined && value !== null) {\n filteredAdditionalKwargs[key] = value;\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const { input_tokens, output_tokens, ...rest }: Record<string, any> =\n usage ?? {};\n const usageMetadata = buildUsageMetadata(usage);\n return {\n chunk: new AIMessageChunk({\n content: fields.coerceContentToString ? \"\" : [],\n additional_kwargs: filteredAdditionalKwargs,\n usage_metadata: fields.streamUsage ? usageMetadata : undefined,\n response_metadata: {\n ...response_metadata,\n usage: {\n ...rest,\n },\n },\n id: data.message.id,\n }),\n };\n } else if (data.type === \"message_delta\") {\n const usageMetadata: UsageMetadata = {\n input_tokens: 0,\n output_tokens: data.usage.output_tokens,\n total_tokens: data.usage.output_tokens,\n input_token_details: {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n cache_creation: (data.usage as any).cache_creation_input_tokens,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n cache_read: (data.usage as any).cache_read_input_tokens,\n },\n };\n const responseMetadata =\n \"context_management\" in data.delta\n ? { context_management: data.delta.context_management }\n : undefined;\n return {\n chunk: new AIMessageChunk({\n content: fields.coerceContentToString ? \"\" : [],\n response_metadata: responseMetadata,\n additional_kwargs: { ...data.delta },\n usage_metadata: fields.streamUsage ? usageMetadata : undefined,\n }),\n };\n } else if (\n data.type === \"content_block_start\" &&\n [\n \"tool_use\",\n \"document\",\n \"server_tool_use\",\n \"web_search_tool_result\",\n ].includes(data.content_block.type)\n ) {\n const contentBlock = data.content_block;\n let toolCallChunks: ToolCallChunk[];\n if (contentBlock.type === \"tool_use\") {\n toolCallChunks = [\n {\n id: contentBlock.id,\n index: data.index,\n name: contentBlock.name,\n args: \"\",\n },\n ];\n } else {\n toolCallChunks = [];\n }\n return {\n chunk: new AIMessageChunk({\n content: fields.coerceContentToString\n ? \"\"\n : [\n {\n index: data.index,\n ...data.content_block,\n input:\n contentBlock.type === \"server_tool_use\" ||\n contentBlock.type === \"tool_use\"\n ? \"\"\n : undefined,\n },\n ],\n response_metadata,\n additional_kwargs: {},\n tool_call_chunks: toolCallChunks,\n }),\n };\n } else if (\n data.type === \"content_block_delta\" &&\n [\n \"text_delta\",\n \"citations_delta\",\n \"thinking_delta\",\n \"signature_delta\",\n ].includes(data.delta.type)\n ) {\n if (fields.coerceContentToString && \"text\" in data.delta) {\n return {\n chunk: new AIMessageChunk({\n content: data.delta.text,\n }),\n };\n } else {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const contentBlock: Record<string, any> = data.delta;\n if (\"citation\" in contentBlock) {\n contentBlock.citations = [contentBlock.citation];\n delete contentBlock.citation;\n }\n if (\n contentBlock.type === \"thinking_delta\" ||\n contentBlock.type === \"signature_delta\"\n ) {\n return {\n chunk: new AIMessageChunk({\n content: [{ index: data.index, ...contentBlock, type: \"thinking\" }],\n response_metadata,\n }),\n };\n }\n\n return {\n chunk: new AIMessageChunk({\n content: [{ index: data.index, ...contentBlock, type: \"text\" }],\n response_metadata,\n }),\n };\n }\n } else if (\n data.type === \"content_block_delta\" &&\n data.delta.type === \"input_json_delta\"\n ) {\n return {\n chunk: new AIMessageChunk({\n content: fields.coerceContentToString\n ? \"\"\n : [\n {\n index: data.index,\n input: data.delta.partial_json,\n type: data.delta.type,\n },\n ],\n response_metadata,\n additional_kwargs: {},\n tool_call_chunks: [\n {\n index: data.index,\n args: data.delta.partial_json,\n },\n ],\n }),\n };\n } else if (\n data.type === \"content_block_start\" &&\n data.content_block.type === \"text\"\n ) {\n const content = data.content_block?.text;\n if (content !== undefined) {\n return {\n chunk: new AIMessageChunk({\n content: fields.coerceContentToString\n ? content\n : [\n {\n index: data.index,\n ...data.content_block,\n },\n ],\n response_metadata,\n additional_kwargs: {},\n }),\n };\n }\n } else if (\n data.type === \"content_block_start\" &&\n data.content_block.type === \"redacted_thinking\"\n ) {\n return {\n chunk: new AIMessageChunk({\n content: fields.coerceContentToString\n ? \"\"\n : [{ index: data.index, ...data.content_block }],\n response_metadata,\n }),\n };\n } else if (\n data.type === \"content_block_start\" &&\n data.content_block.type === \"thinking\"\n ) {\n const content = data.content_block.thinking;\n return {\n chunk: new AIMessageChunk({\n content: fields.coerceContentToString\n ? content\n : [{ index: data.index, ...data.content_block }],\n response_metadata,\n }),\n };\n }\n return null;\n}\n\nexport function anthropicResponseToChatMessages(\n messages: AnthropicMessageResponse[],\n additionalKwargs: Record<string, unknown>\n): ChatGeneration[] {\n const response_metadata = {\n ...additionalKwargs,\n model_provider: \"anthropic\",\n };\n const usage: Record<string, number> | null | undefined =\n additionalKwargs.usage as Record<string, number> | null | undefined;\n const usageMetadata = usage != null ? buildUsageMetadata(usage) : undefined;\n if (messages.length === 1 && messages[0].type === \"text\") {\n return [\n {\n text: messages[0].text,\n message: new AIMessage({\n content: messages[0].text,\n additional_kwargs: additionalKwargs,\n usage_metadata: usageMetadata,\n response_metadata,\n id: additionalKwargs.id as string,\n }),\n },\n ];\n } else {\n const toolCalls = extractToolCalls(messages);\n const generations: ChatGeneration[] = [\n {\n text: \"\",\n message: new AIMessage({\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n content: messages as any,\n additional_kwargs: additionalKwargs,\n tool_calls: toolCalls,\n usage_metadata: usageMetadata,\n response_metadata,\n id: additionalKwargs.id as string,\n }),\n },\n ];\n return generations;\n }\n}\n\nfunction buildUsageMetadata(\n usage: Anthropic.Messages.Usage | Record<string, number>\n): UsageMetadata {\n const cacheCreationInputTokens = usage.cache_creation_input_tokens ?? 0;\n const cacheReadInputTokens = usage.cache_read_input_tokens ?? 0;\n // Total input tokens in a Claude API request is the summation of `input_tokens`, `cache_creation_input_tokens`, and `cache_read_input_tokens`.\n // ref: https://platform.claude.com/docs/en/api/messages\n const totalInputTokens =\n usage.input_tokens + cacheCreationInputTokens + cacheReadInputTokens;\n return {\n input_tokens: totalInputTokens,\n output_tokens: usage.output_tokens,\n total_tokens: totalInputTokens + usage.output_tokens,\n input_token_details: {\n cache_creation: cacheCreationInputTokens,\n cache_read: cacheReadInputTokens,\n },\n };\n}\n"],"mappings":"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"}
@@ -9,16 +9,7 @@ function _makeMessageChunkFromAnthropicEvent(data, fields) {
9
9
  const filteredAdditionalKwargs = {};
10
10
  for (const [key, value] of Object.entries(additionalKwargs)) if (value !== void 0 && value !== null) filteredAdditionalKwargs[key] = value;
11
11
  const { input_tokens, output_tokens,...rest } = usage ?? {};
12
- const totalInputTokens = input_tokens + rest.cache_creation_input_tokens + rest.cache_read_input_tokens;
13
- const usageMetadata = {
14
- input_tokens: totalInputTokens,
15
- output_tokens,
16
- total_tokens: totalInputTokens + output_tokens,
17
- input_token_details: {
18
- cache_creation: rest.cache_creation_input_tokens,
19
- cache_read: rest.cache_read_input_tokens
20
- }
21
- };
12
+ const usageMetadata = buildUsageMetadata(usage);
22
13
  return { chunk: new AIMessageChunk({
23
14
  content: fields.coerceContentToString ? "" : [],
24
15
  additional_kwargs: filteredAdditionalKwargs,
@@ -148,15 +139,7 @@ function anthropicResponseToChatMessages(messages, additionalKwargs) {
148
139
  model_provider: "anthropic"
149
140
  };
150
141
  const usage = additionalKwargs.usage;
151
- const usageMetadata = usage != null ? {
152
- input_tokens: usage.input_tokens ?? 0,
153
- output_tokens: usage.output_tokens ?? 0,
154
- total_tokens: (usage.input_tokens ?? 0) + (usage.output_tokens ?? 0),
155
- input_token_details: {
156
- cache_creation: usage.cache_creation_input_tokens,
157
- cache_read: usage.cache_read_input_tokens
158
- }
159
- } : void 0;
142
+ const usageMetadata = usage != null ? buildUsageMetadata(usage) : void 0;
160
143
  if (messages.length === 1 && messages[0].type === "text") return [{
161
144
  text: messages[0].text,
162
145
  message: new AIMessage({
@@ -183,6 +166,20 @@ function anthropicResponseToChatMessages(messages, additionalKwargs) {
183
166
  return generations;
184
167
  }
185
168
  }
169
+ function buildUsageMetadata(usage) {
170
+ const cacheCreationInputTokens = usage.cache_creation_input_tokens ?? 0;
171
+ const cacheReadInputTokens = usage.cache_read_input_tokens ?? 0;
172
+ const totalInputTokens = usage.input_tokens + cacheCreationInputTokens + cacheReadInputTokens;
173
+ return {
174
+ input_tokens: totalInputTokens,
175
+ output_tokens: usage.output_tokens,
176
+ total_tokens: totalInputTokens + usage.output_tokens,
177
+ input_token_details: {
178
+ cache_creation: cacheCreationInputTokens,
179
+ cache_read: cacheReadInputTokens
180
+ }
181
+ };
182
+ }
186
183
 
187
184
  //#endregion
188
185
  export { _makeMessageChunkFromAnthropicEvent, anthropicResponseToChatMessages };