Discussion about why LangGraph JS ToolNode doesn’t inject ToolRuntime.state like Python does, and what the correct workaround or intended design pattern is.

Hi team :waving_hand:,

I’m seeing a difference in how ToolRuntime / state is handled between Python and JS in LangGraph and wanted clarification.

:magnifying_glass_tilted_left: Observation

  • In Python, ToolNode explicitly supports state injection:

    “ToolNode … handles … state injection for tools” (LangChain Reference)
    and tools can directly access:

    runtime.state
    
    
  • In JS, ToolRuntime docs say it includes state:

    state: The current graph state” (LangChain Reference)

    But when using:

    new ToolNode(tools)
    
    

    runtime.state is not populated, and we need to pass state manually via config.configurable.


:red_question_mark: Questions

  1. Is this difference intentional (Python ToolNode = injection, JS ToolNode = execution only)?

  2. Is ToolRuntime injection planned for JS ToolNode?

  3. What’s the recommended pattern in JS LangGraph?

    • Pass state manually via config.configurable?

    • Or avoid ToolNode and use createAgent for runtime injection?


:hammer_and_wrench: Current workaround

tool.invoke(toolCall, {
  configurable: { state }
});

But this feels less ergonomic vs Python.


Would appreciate guidance on the intended design + best practice here. Thanks! :folded_hands:

hi @Idrees

what module are you imorting ToolNode from?

using ToolNode from @langchain/langgraph/prebuilt