From 5ce306002e27fd744cf372fb9a07949b94e5da36 Mon Sep 17 00:00:00 2001 From: Christian Bromann Date: Fri, 12 Dec 2025 13:07:09 -0800 Subject: [PATCH 1/2] fix(openai): fix content in AIMessage for tool and function calls --- .../src/converters/completions.ts | 2 - .../src/converters/tests/completions.test.ts | 98 +++++++++++++++++++ 2 files changed, 98 insertions(+), 2 deletions(-) diff --git a/libs/providers/langchain-openai/src/converters/completions.ts b/libs/providers/langchain-openai/src/converters/completions.ts index 4a5304df904d..ea08e95c5408 100644 --- a/libs/providers/langchain-openai/src/converters/completions.ts +++ b/libs/providers/langchain-openai/src/converters/completions.ts @@ -811,13 +811,11 @@ export const convertMessagesToCompletionsMessageParams: Converter< } if (message.additional_kwargs.function_call != null) { completionParam.function_call = message.additional_kwargs.function_call; - completionParam.content = ""; } if (AIMessage.isInstance(message) && !!message.tool_calls?.length) { completionParam.tool_calls = message.tool_calls.map( convertLangChainToolCallToOpenAI ); - completionParam.content = ""; } else { if (message.additional_kwargs.tool_calls != null) { completionParam.tool_calls = message.additional_kwargs.tool_calls; diff --git a/libs/providers/langchain-openai/src/converters/tests/completions.test.ts b/libs/providers/langchain-openai/src/converters/tests/completions.test.ts index 8e52a6a50677..d587b91b789c 100644 --- a/libs/providers/langchain-openai/src/converters/tests/completions.test.ts +++ b/libs/providers/langchain-openai/src/converters/tests/completions.test.ts @@ -1,9 +1,11 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { describe, it, expect } from "vitest"; import { ChatCompletionMessage } from "openai/resources"; +import { AIMessage } from "@langchain/core/messages"; import { completionsApiContentBlockConverter, convertCompletionsMessageToBaseMessage, + convertMessagesToCompletionsMessageParams, convertStandardContentBlockToCompletionsContentPart, } from "../completions.js"; @@ -194,6 +196,102 @@ describe("convertCompletionsMessageToBaseMessage", () => { }); }); + describe("convertMessagesToCompletionsMessageParams", () => { + it("should preserve AIMessage content when tool_calls are present", () => { + const message = new AIMessage({ + content: + "I'll check the status of item 730 for identifier X1110 to find out why it's not active.", + tool_calls: [ + { + id: "call_zGKlzVl2Ee3Lyob4AsyqfGXb", + name: "getStatus", + args: { identifier: "X1110", itemId: "730" }, + }, + ], + }); + + const result = convertMessagesToCompletionsMessageParams({ + messages: [message], + }); + + expect(result).toHaveLength(1); + expect(result[0]).toEqual({ + role: "assistant", + content: + "I'll check the status of item 730 for identifier X1110 to find out why it's not active.", + tool_calls: [ + { + id: "call_zGKlzVl2Ee3Lyob4AsyqfGXb", + type: "function", + function: { + name: "getStatus", + arguments: '{"identifier":"X1110","itemId":"730"}', + }, + }, + ], + }); + }); + + it("should handle AIMessage with empty content and tool_calls", () => { + const message = new AIMessage({ + content: "", + tool_calls: [ + { + id: "call_123", + name: "someFunction", + args: { key: "value" }, + }, + ], + }); + + const result = convertMessagesToCompletionsMessageParams({ + messages: [message], + }); + + expect(result).toHaveLength(1); + expect(result[0]).toEqual({ + role: "assistant", + content: "", + tool_calls: [ + { + id: "call_123", + type: "function", + function: { + name: "someFunction", + arguments: '{"key":"value"}', + }, + }, + ], + }); + }); + + it("should preserve content with function_call in additional_kwargs", () => { + const message = new AIMessage({ + content: "Let me call a function for you.", + additional_kwargs: { + function_call: { + name: "myFunction", + arguments: '{"arg":"value"}', + }, + }, + }); + + const result = convertMessagesToCompletionsMessageParams({ + messages: [message], + }); + + expect(result).toHaveLength(1); + expect(result[0]).toEqual({ + role: "assistant", + content: "Let me call a function for you.", + function_call: { + name: "myFunction", + arguments: '{"arg":"value"}', + }, + }); + }); + }); + describe("completionsApiContentBlockConverter.fromStandardFileBlock", () => { it("throws when base64 file block is missing filename/name/title metadata", () => { const block = { From 0c0a9a76e6f05ddb83b42c713e4013bcdabf6081 Mon Sep 17 00:00:00 2001 From: Hunter Lovell <40191806+hntrl@users.noreply.github.com> Date: Fri, 12 Dec 2025 13:51:02 -0800 Subject: [PATCH 2/2] Create cold-laws-matter.md --- .changeset/cold-laws-matter.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/cold-laws-matter.md diff --git a/.changeset/cold-laws-matter.md b/.changeset/cold-laws-matter.md new file mode 100644 index 000000000000..9c3b82803196 --- /dev/null +++ b/.changeset/cold-laws-matter.md @@ -0,0 +1,5 @@ +--- +"@langchain/openai": patch +--- + +fix content in AIMessage for tool and function calls