Skip to content

Commit 888224c

Browse files
authored
fix(agents): propagate store and configurable to ToolNode middleware runtime (#10446)
1 parent 82d56cb commit 888224c

File tree

3 files changed

+81
-0
lines changed

3 files changed

+81
-0
lines changed

.changeset/config-propagation.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(agents): propagate store and configurable to ToolNode middleware runtime

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,8 @@ export class ToolNode<
298298
const lgConfig = config as LangGraphRunnableConfig;
299299
const runtime = {
300300
context: lgConfig?.context,
301+
store: lgConfig?.store,
302+
configurable: lgConfig?.configurable,
301303
writer: lgConfig?.writer,
302304
interrupt: lgConfig?.interrupt,
303305
signal: lgConfig?.signal,

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

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2975,4 +2975,78 @@ describe("middleware", () => {
29752975
expect(val).toBeDefined();
29762976
}
29772977
});
2978+
2979+
it("should propagate store to wrapToolCall middleware runtime", async () => {
2980+
const store = new InMemoryStore();
2981+
let capturedStore: unknown;
2982+
let capturedConfigurable: unknown;
2983+
2984+
const testTool = tool(async () => "tool result", {
2985+
name: "test_tool",
2986+
description: "A test tool",
2987+
schema: z.object({}),
2988+
});
2989+
2990+
const middleware = createMiddleware({
2991+
name: "storeCheck",
2992+
wrapToolCall: async (request, handler) => {
2993+
capturedStore = request.runtime.store;
2994+
capturedConfigurable = request.runtime.configurable;
2995+
return handler(request);
2996+
},
2997+
});
2998+
2999+
const model = new FakeToolCallingModel({
3000+
toolCalls: [[{ name: "test_tool", args: {}, id: "1" }]],
3001+
});
3002+
3003+
const agent = createAgent({
3004+
model,
3005+
tools: [testTool],
3006+
store,
3007+
middleware: [middleware],
3008+
});
3009+
3010+
await agent.invoke({
3011+
messages: [new HumanMessage("call the tool")],
3012+
});
3013+
3014+
// Verify store is propagated to wrapToolCall (wrapped in AsyncBatchedStore)
3015+
expect(capturedStore).toBeDefined();
3016+
expect(capturedStore).not.toBeNull();
3017+
// Verify configurable is also propagated
3018+
expect(capturedConfigurable).toBeDefined();
3019+
});
3020+
3021+
it("should propagate store to wrapModelCall middleware runtime", async () => {
3022+
const store = new InMemoryStore();
3023+
let capturedStore: unknown;
3024+
3025+
const middleware = createMiddleware({
3026+
name: "storeCheck",
3027+
wrapModelCall: async (request, handler) => {
3028+
capturedStore = request.runtime.store;
3029+
return handler(request);
3030+
},
3031+
});
3032+
3033+
const model = new FakeToolCallingChatModel({
3034+
responses: [new AIMessage("hello")],
3035+
});
3036+
3037+
const agent = createAgent({
3038+
model,
3039+
tools: [],
3040+
store,
3041+
middleware: [middleware],
3042+
});
3043+
3044+
await agent.invoke({
3045+
messages: [new HumanMessage("hi")],
3046+
});
3047+
3048+
// Verify store is propagated to wrapModelCall (wrapped in AsyncBatchedStore)
3049+
expect(capturedStore).toBeDefined();
3050+
expect(capturedStore).not.toBeNull();
3051+
});
29783052
});

0 commit comments

Comments
 (0)