Skip to content

Commit 4d771a1

Browse files
committed
Lint, add tests for strict and other structured output kwargs
1 parent 86adfb7 commit 4d771a1

File tree

2 files changed

+34
-24
lines changed

2 files changed

+34
-24
lines changed

libs/langgraph/src/prebuilt/react_agent_executor.ts

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,13 @@ export interface AgentState<
5757

5858
export type N = typeof START | "agent" | "tools";
5959

60-
export type StructuredResponseSchemaAndPrompt<StructuredResponseType> = {
61-
prompt: string;
60+
type StructuredResponseSchemaOptions<StructuredResponseType> = {
6261
// eslint-disable-next-line @typescript-eslint/no-explicit-any
6362
schema: InteropZodType<StructuredResponseType> | Record<string, any>;
64-
strict?:true
63+
prompt?: string;
64+
65+
strict?: boolean;
66+
[key: string]: unknown;
6567
};
6668

6769
function _convertMessageModifierToPrompt(
@@ -525,14 +527,15 @@ export type CreateReactAgentParams<
525527
*/
526528
responseFormat?:
527529
| InteropZodType<StructuredResponseType>
528-
| StructuredResponseSchemaAndPrompt<StructuredResponseType>
529-
| { schema: InteropZodType<StructuredResponseType> | Record<string, any>; strict?: boolean }
530+
| StructuredResponseSchemaOptions<StructuredResponseType>
530531
// eslint-disable-next-line @typescript-eslint/no-explicit-any
531532
| Record<string, any>;
533+
532534
/**
533535
* An optional name for the agent.
534536
*/
535537
name?: string;
538+
536539
/**
537540
* Use to specify how to expose the agent name to the underlying supervisor LLM.
538541
@@ -714,23 +717,18 @@ export function createReactAgent<
714717
const messages = [...state.messages];
715718
let modelWithStructuredOutput;
716719

717-
if (
718-
typeof responseFormat === "object" &&
719-
"prompt" in responseFormat &&
720-
"schema" in responseFormat
721-
) {
722-
const { prompt, schema,strict } = responseFormat;
723-
724-
modelWithStructuredOutput = (await _getModel(llm)).withStructuredOutput(
725-
schema,
726-
strict ? {strict:true} : undefined
727-
);
728-
messages.unshift(new SystemMessage({ content: prompt }));
729-
}
730-
else {
731-
modelWithStructuredOutput = (await _getModel(llm)).withStructuredOutput(
732-
responseFormat
733-
);
720+
const model = await _getModel(llm);
721+
722+
if (typeof responseFormat === "object" && "schema" in responseFormat) {
723+
const { prompt, schema, ...options } =
724+
responseFormat as StructuredResponseSchemaOptions<StructuredResponseFormat>;
725+
726+
modelWithStructuredOutput = model.withStructuredOutput(schema, options);
727+
if (prompt != null) {
728+
messages.unshift(new SystemMessage({ content: prompt }));
729+
}
730+
} else {
731+
modelWithStructuredOutput = model.withStructuredOutput(responseFormat);
734732
}
735733

736734
const response = await modelWithStructuredOutput.invoke(messages, config);
@@ -756,7 +754,8 @@ export function createReactAgent<
756754
return { messages: [response] };
757755
};
758756

759-
const schema =stateSchema ?? createReactAgentAnnotation<StructuredResponseFormat>();
757+
const schema =
758+
stateSchema ?? createReactAgentAnnotation<StructuredResponseFormat>();
760759

761760
const workflow = new StateGraph(schema).addNode("tools", toolNode);
762761

libs/langgraph/src/tests/prebuilt.test.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1864,20 +1864,31 @@ describe("createReactAgent with structured responses", () => {
18641864
"The weather is nice"
18651865
);
18661866

1867-
// Test with prompt and schema
1867+
// Test with prompt and schema (and options)
18681868
const agent2 = createReactAgent({
18691869
llm,
18701870
tools: [getWeather],
18711871
responseFormat: {
18721872
prompt: "Meow",
18731873
schema: weatherResponseSchema,
1874+
1875+
name: "generate_structured_response",
1876+
strict: true,
18741877
},
18751878
});
18761879

1880+
const withStructuredOutputSpy = vi.spyOn(llm, "withStructuredOutput");
1881+
18771882
const result2 = await agent2.invoke({
18781883
messages: [new HumanMessage("What's the weather?")],
18791884
});
18801885

1886+
// Check if `strict` is set properly
1887+
expect(withStructuredOutputSpy).toHaveBeenCalledWith(
1888+
weatherResponseSchema,
1889+
{ name: "generate_structured_response", strict: true }
1890+
);
1891+
18811892
expect(result2.structuredResponse).toEqual(expectedStructuredResponse);
18821893
expect(result2.messages.length).toEqual(4);
18831894
expect(result2.messages[2].content).toEqual(

0 commit comments

Comments
 (0)