Skip to content

Commit e75b30b

Browse files
fix(langchain): enable Anthropic native structured output with create agent (#9562)
1 parent 668d7aa commit e75b30b

File tree

4 files changed

+51
-7
lines changed

4 files changed

+51
-7
lines changed

libs/langchain/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,4 +207,4 @@
207207
"./package.json": "./package.json"
208208
},
209209
"module": "./dist/index.js"
210-
}
210+
}

libs/langchain/src/agents/nodes/AgentNode.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,13 @@ export class AgentNode<
849849
type: "json_schema",
850850
json_schema: jsonSchemaParams,
851851
},
852+
output_format: {
853+
type: "json_schema",
854+
schema: structuredResponseFormat.strategy.schema,
855+
},
856+
headers: {
857+
"anthropic-beta": "structured-outputs-2025-11-13",
858+
},
852859
ls_structured_output_format: {
853860
kwargs: { method: "json_schema" },
854861
schema: structuredResponseFormat.strategy.schema,

libs/langchain/src/agents/tests/responses.int.test.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { tool } from "@langchain/core/tools";
55
import { HumanMessage, AIMessage } from "@langchain/core/messages";
66
import z from "zod/v3";
77

8-
import { createAgent, toolStrategy } from "../index.js";
8+
import { createAgent, toolStrategy, providerStrategy } from "../index.js";
99
import type { JsonSchemaFormat } from "../responses.js";
1010

1111
import responsesSpec from "./specifications/responses.json";
@@ -180,6 +180,43 @@ describe("structured output handling", () => {
180180
);
181181
});
182182
});
183+
184+
describe("providerStrategy", () => {
185+
it("should support native structured output for newer Anthropic models", async () => {
186+
const model = new ChatAnthropic({
187+
model: "claude-sonnet-4-5-20250929",
188+
temperature: 0, // Make it deterministic
189+
});
190+
const captialCatalogTool = tool(
191+
() => {
192+
return "Paris";
193+
},
194+
{
195+
name: "capital_catalog",
196+
description: "Get the capital of a country",
197+
schema: z.object({
198+
location: z.string(),
199+
}),
200+
}
201+
);
202+
const agent = createAgent({
203+
model,
204+
tools: [captialCatalogTool],
205+
responseFormat: providerStrategy(
206+
z.object({
207+
answer: z.string().describe("The capital of the country in 1 word"),
208+
})
209+
),
210+
});
211+
const result = await agent.invoke({
212+
messages: [new HumanMessage("What is the capital of France?")],
213+
});
214+
expect(result.structuredResponse.answer).toBe("Paris");
215+
expect(result.messages.length).toBe(4);
216+
expect(result.messages.at(-1)?.content).toContain('{"answer": "Paris"}');
217+
expect((result.messages.at(-1) as AIMessage).tool_calls?.length).toBe(0);
218+
});
219+
});
183220
});
184221

185222
describe("Strategy Selection", () => {
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
/** Auto-generated by import-constants plugin. Do not edit manually */
22

33
export const optionalImportEntrypoints: string[] = [
4-
"langchain_langchain/chat_models/universal",
5-
"langchain_langchain/cache/file_system",
6-
"langchain_langchain/storage/file_system",
7-
"langchain_langchain/hub/index",
8-
"langchain_langchain/hub/node",
4+
"langchain/chat_models/universal",
5+
"langchain/cache/file_system",
6+
"langchain/storage/file_system",
7+
"langchain/hub/index",
8+
"langchain/hub/node",
99
];

0 commit comments

Comments
 (0)