From b859eab9f5d4dcaf412141e904358e6abebc1214 Mon Sep 17 00:00:00 2001 From: bracesproul Date: Fri, 20 Sep 2024 15:55:57 -0700 Subject: [PATCH 1/4] fix: Update code to reflect config being a required arg --- libs/langgraph/src/graph/graph.ts | 2 +- libs/langgraph/src/prebuilt/agent_executor.ts | 4 +- .../src/prebuilt/chat_agent_executor.ts | 4 +- .../src/prebuilt/react_agent_executor.ts | 2 +- libs/langgraph/src/prebuilt/tool_executor.ts | 4 +- libs/langgraph/src/pregel/write.ts | 4 +- libs/langgraph/src/tests/pregel.test.ts | 55 ++++--------------- 7 files changed, 20 insertions(+), 55 deletions(-) diff --git a/libs/langgraph/src/graph/graph.ts b/libs/langgraph/src/graph/graph.ts index 55ac5ca7..7fb67d6d 100644 --- a/libs/langgraph/src/graph/graph.ts +++ b/libs/langgraph/src/graph/graph.ts @@ -40,7 +40,7 @@ export interface BranchOptions { export class Branch { condition: ( input: IO, - config?: RunnableConfig + config: RunnableConfig ) => | string | Send diff --git a/libs/langgraph/src/prebuilt/agent_executor.ts b/libs/langgraph/src/prebuilt/agent_executor.ts index 21611833..5a889d57 100644 --- a/libs/langgraph/src/prebuilt/agent_executor.ts +++ b/libs/langgraph/src/prebuilt/agent_executor.ts @@ -46,7 +46,7 @@ export function createAgentExecutor({ const runAgent = async ( data: AgentExecutorState, - config?: RunnableConfig + config: RunnableConfig ) => { const agentOutcome = await agentRunnable.invoke(data, config); return { @@ -56,7 +56,7 @@ export function createAgentExecutor({ const executeTools = async ( data: AgentExecutorState, - config?: RunnableConfig + config: RunnableConfig ): Promise> => { const agentAction = data.agentOutcome; if (!agentAction || "returnValues" in agentAction) { diff --git a/libs/langgraph/src/prebuilt/chat_agent_executor.ts b/libs/langgraph/src/prebuilt/chat_agent_executor.ts index 861d7f68..6cdd0715 100644 --- a/libs/langgraph/src/prebuilt/chat_agent_executor.ts +++ b/libs/langgraph/src/prebuilt/chat_agent_executor.ts @@ -70,7 +70,7 @@ export function createFunctionCallingExecutor({ // Define the function that calls the model const callModel = async ( state: FunctionCallingExecutorState, - config?: RunnableConfig + config: RunnableConfig ) => { const { messages } = state; const response = await newModel.invoke(messages, config); @@ -104,7 +104,7 @@ export function createFunctionCallingExecutor({ const callTool = async ( state: FunctionCallingExecutorState, - config?: RunnableConfig + config: RunnableConfig ) => { const action = _getAction(state); // We call the tool_executor and get back a response diff --git a/libs/langgraph/src/prebuilt/react_agent_executor.ts b/libs/langgraph/src/prebuilt/react_agent_executor.ts index bba625aa..4463c090 100644 --- a/libs/langgraph/src/prebuilt/react_agent_executor.ts +++ b/libs/langgraph/src/prebuilt/react_agent_executor.ts @@ -154,7 +154,7 @@ export function createReactAgent( } }; - const callModel = async (state: AgentState, config?: RunnableConfig) => { + const callModel = async (state: AgentState, config: RunnableConfig) => { const { messages } = state; // TODO: Auto-promote streaming. return { messages: [await modelRunnable.invoke(messages, config)] }; diff --git a/libs/langgraph/src/prebuilt/tool_executor.ts b/libs/langgraph/src/prebuilt/tool_executor.ts index a0366082..bbe03a98 100644 --- a/libs/langgraph/src/prebuilt/tool_executor.ts +++ b/libs/langgraph/src/prebuilt/tool_executor.ts @@ -50,7 +50,7 @@ export class ToolExecutor extends RunnableBinding< ...fields, }; const bound = RunnableLambda.from( - async (input: ToolInvocationInterface, config?: RunnableConfig) => + async (input: ToolInvocationInterface, config: RunnableConfig) => this._execute(input, config) ); super({ @@ -74,7 +74,7 @@ export class ToolExecutor extends RunnableBinding< */ async _execute( toolInvocation: ToolInvocationInterface, - config?: RunnableConfig + config: RunnableConfig ): Promise { if (!(toolInvocation.tool in this.toolMap)) { return this.invalidToolMsgTemplate diff --git a/libs/langgraph/src/pregel/write.ts b/libs/langgraph/src/pregel/write.ts index 9c276443..0d306834 100644 --- a/libs/langgraph/src/pregel/write.ts +++ b/libs/langgraph/src/pregel/write.ts @@ -53,8 +53,8 @@ export class ChannelWrite< .join(",")}>`; super({ ...{ writes, name, tags }, - func: async (input: RunInput, config?: RunnableConfig) => { - return this._write(input, config ?? {}); + func: async (input: RunInput, config: RunnableConfig) => { + return this._write(input, config); }, }); diff --git a/libs/langgraph/src/tests/pregel.test.ts b/libs/langgraph/src/tests/pregel.test.ts index d06fa39c..5b4fa897 100644 --- a/libs/langgraph/src/tests/pregel.test.ts +++ b/libs/langgraph/src/tests/pregel.test.ts @@ -3642,18 +3642,18 @@ describe("StateGraph", () => { const nodeA = ( _: typeof StateAnnotation.State, - config?: RunnableConfig + config: RunnableConfig ) => { // Unfortunately can't infer input types at runtime :( - expect(config?.configurable?.foo).toEqual("bar"); + expect(config.configurable?.foo).toEqual("bar"); return {}; }; const nodeB = ( _: typeof StateAnnotation.State, - config?: RunnableConfig + config: RunnableConfig ) => { - expect(config?.configurable?.foo).toEqual("bar"); + expect(config.configurable?.foo).toEqual("bar"); return { hello: "again", now: 123, @@ -5020,11 +5020,8 @@ describe("Managed Values (context) can be passed through state", () => { it("should be passed through state but not stored in checkpointer", async () => { const nodeOne = async ( data: typeof AgentAnnotation.State, - config?: RunnableConfig + config: RunnableConfig ): Promise> => { - if (!config) { - throw new Error("config is undefined"); - } expect(config.configurable?.thread_id).toEqual(threadId); expect(data.sharedStateKey).toEqual({}); @@ -5041,12 +5038,7 @@ describe("Managed Values (context) can be passed through state", () => { const nodeTwo = async ( data: typeof AgentAnnotation.State, - config?: RunnableConfig ): Promise> => { - if (!config) { - throw new Error("config is undefined"); - } - expect(data.sharedStateKey).toEqual({ sharedStateValue: { value: "shared", @@ -5083,12 +5075,7 @@ describe("Managed Values (context) can be passed through state", () => { const nodeThree = async ( data: typeof AgentAnnotation.State, - config?: RunnableConfig ): Promise> => { - if (!config) { - throw new Error("config is undefined"); - } - expect(data.sharedStateKey).toEqual({ sharedStateValue: { value: "updated", @@ -5157,11 +5144,8 @@ describe("Managed Values (context) can be passed through state", () => { it("can not access shared values from other 'on' keys", async () => { const nodeOne = async ( data: typeof AgentAnnotation.State, - config?: RunnableConfig + config: RunnableConfig ): Promise> => { - if (!config) { - throw new Error("config is undefined"); - } expect(config.configurable?.thread_id).toBe(threadId); expect(config.configurable?.assistant_id).toBe("a"); @@ -5178,11 +5162,8 @@ describe("Managed Values (context) can be passed through state", () => { const nodeTwo = async ( data: typeof AgentAnnotation.State, - config?: RunnableConfig + config: RunnableConfig ): Promise> => { - if (!config) { - throw new Error("config is undefined"); - } expect(config.configurable?.thread_id).toBe(threadId); expect(config.configurable?.assistant_id).toBe("b"); @@ -5199,12 +5180,8 @@ describe("Managed Values (context) can be passed through state", () => { const nodeThree = async ( data: typeof AgentAnnotation.State, - config?: RunnableConfig + config: RunnableConfig ): Promise> => { - if (!config) { - throw new Error("config is undefined"); - } - expect(config.configurable?.thread_id).toBe(threadId); expect(config.configurable?.assistant_id).toBe("a"); @@ -5219,12 +5196,8 @@ describe("Managed Values (context) can be passed through state", () => { const nodeFour = async ( data: typeof AgentAnnotation.State, - config?: RunnableConfig + config: RunnableConfig ): Promise> => { - if (!config) { - throw new Error("config is undefined"); - } - expect(config.configurable?.thread_id).toBe(threadId); expect(config.configurable?.assistant_id).toBe("b"); @@ -5379,11 +5352,8 @@ describe("Managed Values (context) can be passed through state", () => { // Define nodeOne that sets sharedStateKey and adds a message const nodeOne = async ( data: typeof AgentAnnotation.State, - config?: RunnableConfig + config: RunnableConfig ): Promise> => { - if (!config) { - throw new Error("config is undefined"); - } expect(config.configurable?.thread_id).toEqual(threadId); expect(data.sharedStateKey).toEqual({}); @@ -5401,12 +5371,7 @@ describe("Managed Values (context) can be passed through state", () => { // Define nodeTwo that updates sharedStateKey const nodeTwo = async ( data: typeof AgentAnnotation.State, - config?: RunnableConfig ): Promise> => { - if (!config) { - throw new Error("config is undefined"); - } - expect(data.sharedStateKey).toEqual({ data: { value: "shared", From 4386bdcedd1b98a4bafb1a33207428e80184c1a9 Mon Sep 17 00:00:00 2001 From: bracesproul Date: Fri, 20 Sep 2024 15:56:14 -0700 Subject: [PATCH 2/4] chore: lint files --- libs/langgraph/src/prebuilt/agent_executor.ts | 5 +---- libs/langgraph/src/tests/pregel.test.ts | 16 +++++----------- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/libs/langgraph/src/prebuilt/agent_executor.ts b/libs/langgraph/src/prebuilt/agent_executor.ts index 5a889d57..d6a6e462 100644 --- a/libs/langgraph/src/prebuilt/agent_executor.ts +++ b/libs/langgraph/src/prebuilt/agent_executor.ts @@ -44,10 +44,7 @@ export function createAgentExecutor({ return "continue"; }; - const runAgent = async ( - data: AgentExecutorState, - config: RunnableConfig - ) => { + const runAgent = async (data: AgentExecutorState, config: RunnableConfig) => { const agentOutcome = await agentRunnable.invoke(data, config); return { agentOutcome, diff --git a/libs/langgraph/src/tests/pregel.test.ts b/libs/langgraph/src/tests/pregel.test.ts index 5b4fa897..85814984 100644 --- a/libs/langgraph/src/tests/pregel.test.ts +++ b/libs/langgraph/src/tests/pregel.test.ts @@ -3640,19 +3640,13 @@ describe("StateGraph", () => { hello: Annotation, }); - const nodeA = ( - _: typeof StateAnnotation.State, - config: RunnableConfig - ) => { + const nodeA = (_: typeof StateAnnotation.State, config: RunnableConfig) => { // Unfortunately can't infer input types at runtime :( expect(config.configurable?.foo).toEqual("bar"); return {}; }; - const nodeB = ( - _: typeof StateAnnotation.State, - config: RunnableConfig - ) => { + const nodeB = (_: typeof StateAnnotation.State, config: RunnableConfig) => { expect(config.configurable?.foo).toEqual("bar"); return { hello: "again", @@ -5037,7 +5031,7 @@ describe("Managed Values (context) can be passed through state", () => { }; const nodeTwo = async ( - data: typeof AgentAnnotation.State, + data: typeof AgentAnnotation.State ): Promise> => { expect(data.sharedStateKey).toEqual({ sharedStateValue: { @@ -5074,7 +5068,7 @@ describe("Managed Values (context) can be passed through state", () => { }; const nodeThree = async ( - data: typeof AgentAnnotation.State, + data: typeof AgentAnnotation.State ): Promise> => { expect(data.sharedStateKey).toEqual({ sharedStateValue: { @@ -5370,7 +5364,7 @@ describe("Managed Values (context) can be passed through state", () => { // Define nodeTwo that updates sharedStateKey const nodeTwo = async ( - data: typeof AgentAnnotation.State, + data: typeof AgentAnnotation.State ): Promise> => { expect(data.sharedStateKey).toEqual({ data: { From 0dc7eeb4fcd01763ded8ed94f5b10ded012308df Mon Sep 17 00:00:00 2001 From: bracesproul Date: Fri, 20 Sep 2024 16:03:15 -0700 Subject: [PATCH 3/4] add test --- libs/langgraph/src/tests/pregel.test.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libs/langgraph/src/tests/pregel.test.ts b/libs/langgraph/src/tests/pregel.test.ts index 85814984..c467a075 100644 --- a/libs/langgraph/src/tests/pregel.test.ts +++ b/libs/langgraph/src/tests/pregel.test.ts @@ -3744,6 +3744,20 @@ describe("StateGraph", () => { hello: "again", }); }); + + it("can be passed a conditional edge with required config arg", async () => { + const workflow = new StateGraph(MessagesAnnotation) + .addNode("nodeOne", (): Partial => ({})) + .addConditionalEdges("nodeOne", (_, config) => { + expect(config).toBeDefined(); + if (!config) { + throw new Error("config must be defined."); + } + return END; + }); + const app = workflow.compile(); + await app.invoke({ messages: [] }); + }); }); describe("PreBuilt", () => { From b9c2d9aeebc0bfc9618c0a1c4a80b5f145241fd2 Mon Sep 17 00:00:00 2001 From: bracesproul Date: Fri, 20 Sep 2024 16:03:31 -0700 Subject: [PATCH 4/4] cr --- libs/langgraph/src/tests/pregel.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/langgraph/src/tests/pregel.test.ts b/libs/langgraph/src/tests/pregel.test.ts index c467a075..d24807c6 100644 --- a/libs/langgraph/src/tests/pregel.test.ts +++ b/libs/langgraph/src/tests/pregel.test.ts @@ -3747,7 +3747,7 @@ describe("StateGraph", () => { it("can be passed a conditional edge with required config arg", async () => { const workflow = new StateGraph(MessagesAnnotation) - .addNode("nodeOne", (): Partial => ({})) + .addNode("nodeOne", () => ({})) .addConditionalEdges("nodeOne", (_, config) => { expect(config).toBeDefined(); if (!config) {