langgraph icon indicating copy to clipboard operation
langgraph copied to clipboard

Make state access for subgraphs easier from parent graph

Open so2liu opened this issue 7 months ago • 5 comments

Checked other resources

  • [x] This is a bug, not a usage question. For questions, please use GitHub Discussions.
  • [x] I added a clear and detailed title that summarizes the issue.
  • [x] I read what a minimal reproducible example is (https://stackoverflow.com/help/minimal-reproducible-example).
  • [x] I included a self-contained, minimal example that demonstrates the issue INCLUDING all the relevant imports. The code run AS IS to reproduce the issue.

Example Code

from typing import Literal

from langchain_core.runnables import RunnableConfig
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import END, START, MessagesState, StateGraph
from langgraph.types import Command, interrupt
from pydantic import BaseModel
from rich import print



class State(BaseModel):
    messages: list[str] = []


def node_builder(name: str, type: Literal["normal", "interrupt"]):
    def node(state: State):
        print(f"{name} node", state)
        return {"messages": state.messages + [f"{name} node"]}

    def node_interrupt(state: State):
        print(f"{name} interrupt", state)
        value = interrupt("enter interrupt")
        return {"messages": state.messages + [f"{name} interrupt"]}

    if type == "normal":
        return node
    elif type == "interrupt":
        return node_interrupt
    else:
        raise ValueError(f"Invalid type: {type}")


def subgraph_builder(name: str):

    def build():
        graph = StateGraph(State)
        graph.add_node(f"{name}1", node_builder(f"{name}1", "normal"))
        graph.add_node(f"{name}2", node_builder(f"{name}2", "interrupt"))

        graph.add_edge(START, f"{name}1")
        graph.add_edge(f"{name}1", f"{name}2")
        graph.add_edge(f"{name}2", END)
        return graph

    return build


def main():
    memory = MemorySaver()
    thread_id = "123"
    config = RunnableConfig(configurable={"thread_id": thread_id})

    graph = StateGraph(State)
    graph.add_node("node1", node_builder("node1", "normal"))
    subgraph = subgraph_builder("node2")()
    compiled_subgraph = subgraph.compile(checkpointer=memory)
    graph.add_node("node2", compiled_subgraph)

    graph.add_edge(START, "node1")
    graph.add_edge("node1", "node2")
    graph.add_edge("node2", END)
    graph.compile()

    compiled_graph = graph.compile(checkpointer=memory)
    for chunk in compiled_graph.stream({"messages": []}, config=config, subgraphs=True):
        # print(chunk)
        pass

    state = compiled_graph.get_state(config=config, subgraphs=True)
    print("state", state.values)

    compiled_graph.invoke(Command(resume=True), config=config, subgraphs=True)
    print("resume")
    state = compiled_graph.get_state(config=config, subgraphs=True)
    print("after resume state", state.values)


if __name__ == "__main__":
    main()

Error Message and Stack Trace (if applicable)


Description

I am using subgraphs and interrupts. When my interrupt happens inside a subgraph, I can't get latest state by get_state API. Only after interrupt is resumed, I can get full state.

In reproduce code, I get

state {'messages': ['node1 node']}
resume
after resume state {'messages': ['node1 node', 'node21 node', 'node22 interrupt']}

I hope I can get

state {'messages': ['node1 node', 'node21 node']}
resume
after resume state {'messages': ['node1 node', 'node21 node', 'node22 interrupt']}

System Info

System Information

OS: Darwin OS Version: Darwin Kernel Version 23.5.0: Wed May 1 20:19:05 PDT 2024; root:xnu-10063.121.3~5/RELEASE_ARM64_T8112 Python Version: 3.12.4 | packaged by Anaconda, Inc. | (main, Jun 18 2024, 10:07:17) [Clang 14.0.6 ]

Package Information

langchain_core: 0.3.56 langchain: 0.3.9 langsmith: 0.1.147 langchain_mcp_adapters: 0.1.1 langchain_openai: 0.3.9 langchain_text_splitters: 0.3.8 langgraph_sdk: 0.1.63

Optional packages not installed

langserve

Other Dependencies

aiohttp: 3.11.18 async-timeout: Installed. No version info available. httpx: 0.28.1 jsonpatch<2.0,>=1.33: Installed. No version info available. langchain-core<0.4,>=0.3.36: Installed. No version info available. langchain-core<1.0.0,>=0.3.45: Installed. No version info available. langchain-core<1.0.0,>=0.3.51: Installed. No version info available. langsmith-pyo3: Installed. No version info available. langsmith<0.4,>=0.1.125: Installed. No version info available. mcp>=1.7: Installed. No version info available. numpy: 2.2.5 openai<2.0.0,>=1.66.3: Installed. No version info available. orjson: 3.10.16 packaging<25,>=23.2: Installed. No version info available. pydantic: 2.10.6 pydantic<3.0.0,>=2.5.2;: Installed. No version info available. pydantic<3.0.0,>=2.7.4;: Installed. No version info available. PyYAML: 6.0.2 PyYAML>=5.3: Installed. No version info available. requests: 2.32.3 requests-toolbelt: 1.0.0 SQLAlchemy: 2.0.40 tenacity: 9.1.2 tenacity!=8.4.0,<10.0.0,>=8.1.0: Installed. No version info available. tiktoken<1,>=0.7: Installed. No version info available. typing-extensions>=4.7: Installed. No version info available.

so2liu avatar May 29 '25 15:05 so2liu

I encountered the same problem.

leecj avatar Jun 06 '25 02:06 leecj

From the docs

You only need to provide the checkpointer when compiling the parent graph. LangGraph will automatically propagate the checkpointer to the child subgraphs.

Looking into this now!

sydney-runkle avatar Jun 11 '25 20:06 sydney-runkle

Hey folks! This is actually the expected behavior. You're getting the state off of the parent graph, so the state hasn't yet been updated because the subgraph node (your subgraph) hasn't completed execution.

In the short term, you can access the subgraph state via something like:

parent_state = parent_graph.get_state(config=config)
sub_state = top_state.tasks[0].state

sydney-runkle avatar Jun 12 '25 13:06 sydney-runkle

Can I update the state of a subgraph using the update_state method? (The content to be updated has no channel between it and the parent graph.)

Liweiyanm avatar Sep 22 '25 07:09 Liweiyanm

Can I update the state of a subgraph using the update_state method? (The content to be updated has no channel between it and the parent graph.)

same question

seetimee avatar Nov 20 '25 03:11 seetimee