diff --git a/libs/langchain/src/agents/nodes/AgentNode.ts b/libs/langchain/src/agents/nodes/AgentNode.ts index 25e2ca35bef0..94b6a955948e 100644 --- a/libs/langchain/src/agents/nodes/AgentNode.ts +++ b/libs/langchain/src/agents/nodes/AgentNode.ts @@ -835,13 +835,18 @@ export class AgentNode< * check if the user requests a native schema output */ if (structuredResponseFormat?.type === "native") { + const resolvedStrict = + preparedOptions?.modelSettings?.strict ?? + structuredResponseFormat?.strategy?.strict ?? + true; + const jsonSchemaParams = { name: structuredResponseFormat.strategy.schema?.name ?? "extract", description: getSchemaDescription( structuredResponseFormat.strategy.schema ), schema: structuredResponseFormat.strategy.schema, - strict: true, + strict: resolvedStrict, }; Object.assign(options, { @@ -860,7 +865,7 @@ export class AgentNode< kwargs: { method: "json_schema" }, schema: structuredResponseFormat.strategy.schema, }, - strict: true, + strict: resolvedStrict, }); } diff --git a/libs/providers/langchain-openai/src/chat_models/responses.ts b/libs/providers/langchain-openai/src/chat_models/responses.ts index 39077a85fc71..35a3dba8c423 100644 --- a/libs/providers/langchain-openai/src/chat_models/responses.ts +++ b/libs/providers/langchain-openai/src/chat_models/responses.ts @@ -73,7 +73,8 @@ export class ChatOpenAIResponses< let strict: boolean | undefined; if (options?.strict !== undefined) { strict = options.strict; - } else if (this.supportsStrictToolCalling !== undefined) { + } + if (strict === undefined && this.supportsStrictToolCalling !== undefined) { strict = this.supportsStrictToolCalling; } diff --git a/libs/providers/langchain-openai/src/chat_models/tests/responses.strict.test.ts b/libs/providers/langchain-openai/src/chat_models/tests/responses.strict.test.ts new file mode 100644 index 000000000000..f638a32be590 --- /dev/null +++ b/libs/providers/langchain-openai/src/chat_models/tests/responses.strict.test.ts @@ -0,0 +1,53 @@ +import { describe, it, expect } from "vitest"; +import { ChatOpenAIResponses } from "../responses.js"; + +describe("strict tool-calling configuration", () => { + it("falls back to supportsStrictToolCalling when strict is undefined", () => { + const model = new ChatOpenAIResponses({ + model: "gpt-4o", + supportsStrictToolCalling: true, + }); + + const params = model.invocationParams({ + tools: [ + { + type: "function", + function: { + name: "test_func", + description: "testing", + parameters: { type: "object", properties: {} }, + }, + }, + ], + }); + + expect("strict" in params).toBe(false); + + expect((params.tools as Array<{ strict?: boolean }>)[0].strict).toBe(true); + }); + + it("respects user-provided strict option", () => { + const model = new ChatOpenAIResponses({ + model: "gpt-4o", + supportsStrictToolCalling: true, + }); + + const params = model.invocationParams({ + strict: false, + tools: [ + { + type: "function", + function: { + name: "test_func", + description: "testing", + parameters: { type: "object", properties: {} }, + }, + }, + ], + }); + + expect("strict" in params).toBe(false); + + expect((params.tools as Array<{ strict?: boolean }>)[0].strict).toBe(false); + }); +});