Skip to content

Commit 66fc10c

Browse files
fix(langchain): don't allow default or optional context schemas (langchain-ai#9287)
1 parent 42930b5 commit 66fc10c

File tree

3 files changed

+27
-63
lines changed

3 files changed

+27
-63
lines changed

.changeset/fresh-dingos-repair.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"langchain": patch
3+
---
4+
5+
fix(langchain): don't allow default or optional context schemas

libs/langchain/src/agents/middleware.ts

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
/* eslint-disable @typescript-eslint/no-explicit-any */
22
import type {
33
InteropZodObject,
4-
InteropZodDefault,
5-
InteropZodOptional,
64
InferInteropZodOutput,
75
} from "@langchain/core/utils/types";
86

@@ -52,11 +50,7 @@ import type {
5250
*/
5351
export function createMiddleware<
5452
TSchema extends InteropZodObject | undefined = undefined,
55-
TContextSchema extends
56-
| InteropZodObject
57-
| InteropZodOptional<InteropZodObject>
58-
| InteropZodDefault<InteropZodObject>
59-
| undefined = undefined
53+
TContextSchema extends InteropZodObject | undefined = undefined
6054
>(config: {
6155
/**
6256
* The name of the middleware
@@ -232,15 +226,7 @@ export function createMiddleware<
232226
}
233227

234228
type NormalizeContextSchema<
235-
TContextSchema extends
236-
| InteropZodObject
237-
| InteropZodOptional<InteropZodObject>
238-
| InteropZodDefault<InteropZodObject>
239-
| undefined = undefined
229+
TContextSchema extends InteropZodObject | undefined = undefined
240230
> = TContextSchema extends InteropZodObject
241231
? InferInteropZodOutput<TContextSchema>
242-
: TContextSchema extends InteropZodDefault<any>
243-
? InferInteropZodOutput<TContextSchema>
244-
: TContextSchema extends InteropZodOptional<any>
245-
? Partial<InferInteropZodOutput<TContextSchema>>
246232
: never;

libs/langchain/src/agents/tests/middleware.test-d.ts

Lines changed: 20 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,9 @@ describe("middleware types", () => {
133133
it("doesn't require users to pass in a context if a middleware has optional context schema", async () => {
134134
const middleware = createMiddleware({
135135
name: "Middleware",
136-
contextSchema: z
137-
.object({
138-
customOptionalContextProp: z.string().default("default value"),
139-
})
140-
.optional(),
136+
contextSchema: z.object({
137+
customOptionalContextProp: z.string().optional(),
138+
}),
141139
});
142140

143141
const agent = createAgent({
@@ -158,18 +156,13 @@ describe("middleware types", () => {
158156
);
159157
});
160158

161-
it("doesn't require users to pass in a context if a middleware has context schema with defaults", async () => {
159+
it("doesn't require users to pass in a context if a middleware has context schema with defaults or optional", async () => {
162160
const middleware = createMiddleware({
163161
name: "Middleware",
164-
contextSchema: z
165-
.object({
166-
customDefaultContextProp: z.string().default("default value"),
167-
customOptionalContextProp: z.string().optional(),
168-
customRequiredContextProp: z.string(),
169-
})
170-
.default({
171-
customRequiredContextProp: "default value",
172-
}),
162+
contextSchema: z.object({
163+
customDefaultContextProp: z.string().default("default value"),
164+
customOptionalContextProp: z.string().optional(),
165+
}),
173166
stateSchema: z.object({
174167
customDefaultStateProp: z.string().default("default value"),
175168
customOptionalStateProp: z.string().optional(),
@@ -186,7 +179,6 @@ describe("middleware types", () => {
186179
expectTypeOf(runtime.context).toEqualTypeOf<{
187180
customDefaultContextProp: string;
188181
customOptionalContextProp?: string;
189-
customRequiredContextProp: string;
190182
}>();
191183
},
192184
afterModel: async (state, runtime) => {
@@ -200,7 +192,6 @@ describe("middleware types", () => {
200192
expectTypeOf(runtime.context).toEqualTypeOf<{
201193
customDefaultContextProp: string;
202194
customOptionalContextProp?: string;
203-
customRequiredContextProp: string;
204195
}>();
205196
},
206197
wrapModelCall: async (request, handler) => {
@@ -210,7 +201,6 @@ describe("middleware types", () => {
210201
expectTypeOf(request.runtime.context).toEqualTypeOf<{
211202
customDefaultContextProp: string;
212203
customOptionalContextProp?: string;
213-
customRequiredContextProp: string;
214204
}>();
215205

216206
return handler({
@@ -242,40 +232,23 @@ describe("middleware types", () => {
242232
it("doesn't require users to pass in a context if a middleware has context schema as optional", async () => {
243233
const middleware = createMiddleware({
244234
name: "Middleware",
245-
contextSchema: z
246-
.object({
247-
customOptionalContextProp: z.string().default("default value"),
248-
})
249-
.optional(),
235+
contextSchema: z.object({
236+
customOptionalContextProp: z.string().default("default value"),
237+
}),
250238
beforeModel: async (_state, runtime) => {
251-
expectTypeOf(runtime.context).toEqualTypeOf<
252-
Partial<
253-
| {
254-
customOptionalContextProp: string;
255-
}
256-
| undefined
257-
>
258-
>();
239+
expectTypeOf(runtime.context).toEqualTypeOf<{
240+
customOptionalContextProp: string;
241+
}>();
259242
},
260243
afterModel: async (_state, runtime) => {
261-
expectTypeOf(runtime.context).toEqualTypeOf<
262-
Partial<
263-
| {
264-
customOptionalContextProp: string;
265-
}
266-
| undefined
267-
>
268-
>();
244+
expectTypeOf(runtime.context).toEqualTypeOf<{
245+
customOptionalContextProp: string;
246+
}>();
269247
},
270248
wrapModelCall: async (request) => {
271-
expectTypeOf(request.runtime.context).toEqualTypeOf<
272-
Partial<
273-
| {
274-
customOptionalContextProp: string;
275-
}
276-
| undefined
277-
>
278-
>();
249+
expectTypeOf(request.runtime.context).toEqualTypeOf<{
250+
customOptionalContextProp: string;
251+
}>();
279252

280253
return new AIMessage("foobar");
281254
},

0 commit comments

Comments
 (0)