You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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
fromtypingimportLiteralfromlangchain_core.runnablesimportRunnableConfigfromlanggraph.checkpoint.memoryimportMemorySaverfromlanggraph.graphimportEND, START, StateGraphfromlanggraph.graph.stateimportCommandfromlanggraph.typesimportinterruptfromrichimportget_consolefromtyping_extensionsimportTypedDict################ Subgraph###############classSubGraphState(TypedDict, total=False):
parent_counter: intsub_counter: intdefsubgraph_accumulator(state: SubGraphState) ->SubGraphState:
get_console().print("---subgraph counter node---")
get_console().print(f"{state=}")
# ask for human approvalhuman_feedback=interrupt("get human feedback")
print(f"{human_feedback=}")
# continue countingsub_counter=state["sub_counter"] +1if"sub_counter"instateelse1return {"sub_counter": sub_counter}
sub_graph= (
StateGraph(SubGraphState)
.add_node(subgraph_accumulator)
.add_edge(START, subgraph_accumulator.__name__)
.add_edge(subgraph_accumulator.__name__, END)
.compile(
checkpointer=True, # BUG: This causes an issue that subgraph nodes are not executed at all after first interruption
)
)
sub_graph.name="sub"################ Parent Graph###############MAX_ITERATION=3classParentGraphState(TypedDict):
parent_counter: intdefparent_graph_accumulator(
state: ParentGraphState,
) ->Command[Literal["sub", "__end__"]]:
print("---parent counter node---")
get_console().print(f"{state=}")
parent_counter=state["parent_counter"] +1if"parent_counter"instateelse0# goto end when max iteration reachesgoto=sub_graph.get_name() ifparent_counter<MAX_ITERATIONelseENDget_console().print(f"going to node {goto}")
returnCommand(
update={
"parent_counter": parent_counter,
},
goto=goto,
)
parent_agent= (
StateGraph(ParentGraphState)
.add_node(parent_graph_accumulator)
.add_node(sub_graph)
.add_edge(START, parent_graph_accumulator.__name__)
.add_edge(sub_graph.get_name(), parent_graph_accumulator.__name__)
.compile(checkpointer=MemorySaver())
)
# visualize graphmermaid_graph=parent_agent.get_graph(xray=True).draw_mermaid()
print(mermaid_graph)
################ Conversation###############config: RunnableConfig= {"configurable": {"thread_id": "42"}, "recursion_limit": MAX_ITERATION+1}
inputs= [
ParentGraphState(parent_counter=0),
Command(resume="human feedback 1"),
Command(resume="human feedback 2"),
]
forinput_ininputs:
print(f"{input_=}")
foreventinparent_agent.stream(
# resume the conversationinput_,
config,
stream_mode="updates",
subgraphs=True,
):
print("Streaming event ...")
print(event)
Error Message and Stack Trace (if applicable)
input_ = {'parent_counter': 0}
---parent counter node---
state = {'parent_counter': 0}
going to node sub
Streaming event ...
((), {'parent_graph_accumulator': {'parent_counter':1}})---subgraph counter node---state = {'parent_counter': 1}Streaming event ...((), {'__interrupt__': (Interrupt(value='get human feedback', resumable=True, ns=['sub', 'subgraph_accumulator:f187d019-da4b-d432-bcd2-cea142aa7e35'], when='during'),)})input_ = Command(resume='human feedback 1')---subgraph counter node---state = {'parent_counter': 1}human_feedback = 'human feedback 1'Streaming event ...(('sub',), {'subgraph_accumulator': {'sub_counter': 1}})Streaming event ...((), {'sub': {'parent_counter': 1}})---parent counter node---state = {'parent_counter': 1}going to node subStreaming event ...((), {'parent_graph_accumulator': {'parent_counter': 2}})Streaming event ...((), {'sub': {'parent_counter': 1}}) <------- BUG: should be subgraph execution like (('sub',), {'subgraph_accumulator': {...}})---parent counter node---state = {'parent_counter': 1}going to node subStreaming event ...((), {'parent_graph_accumulator': {'parent_counter': 2}})Streaming event ...((), {'sub': {'parent_counter': 1}})---parent counter node---state = {'parent_counter': 1}going to node subStreaming event ...((), {'parent_graph_accumulator': {'parent_counter': 2}})Traceback (most recent call last): File "/home/linux/arcgis-ai-assistants/python/arcgis-assistant/.tmp/subgraph_state_lose/loop_subgraph_with_interrupt.py", line 99, in <module> for event in parent_agent.stream( File "/home/linux/miniconda3/envs/test/lib/python3.11/site-packages/langgraph/pregel/__init__.py", line 1690, in stream raise GraphRecursionError(msg)langgraph.errors.GraphRecursionError: Recursion limit of 4 reached without hitting a stop condition. You can increase the limit by setting the `recursion_limit` config key.For troubleshooting, visit: https://python.langchain.com/docs/troubleshooting/errors/GRAPH_RECURSION_LIMIT
Description
I encountered an issue when building a multi-agent graph for multi-turn conversations, where a subgraph has a human feedback node. It interrupts and takes human feedback.
Here is an example graph to reproduce the issue
A parent graph has a loop, calling a sub graph until the parent counter reaches a pre-defined limit.
Subgraph node interrupts and take human feedback.
The sub graph should remember its state from previous run (checkpointer=True).
Expected Behavior
graph should interrupt twice, and resume with human inputs
subgraph should should persist its state on each run (since checkpointer=True)
Actual Behavior
The first interrupt and resume is as expected
The second interrupt never happens. The parent graph never executes sub graph counter node after resuming the first interrupt. The sub graph nodes output the same parent counter (=1) repeatedly, leading to recursion limit error since parent counter does not increase.
Observation
If removing checkpointer=True, the graph executes as expected, i.e. the parent counter increases correctly. No bug. (In this cause, ff course, the sub graph states from previous run is not persisted )
It seems in subgraph assigning checkpointer=True and calling interrupt conflicts in some way.
Since checkpointer=True is not yet officially documented and supported, not sure if I use it in a wrong way.
Could you please take a look? @vbarda@eyurtsev
Appreciate your efforts
Checked other resources
Example Code
Error Message and Stack Trace (if applicable)
Description
I encountered an issue when building a multi-agent graph for multi-turn conversations, where a subgraph has a human feedback node. It interrupts and takes human feedback.
Here is an example graph to reproduce the issue
checkpointer=True
).Expected Behavior
checkpointer=True
)Actual Behavior
Observation
If removing
checkpointer=True
, the graph executes as expected, i.e. the parent counter increases correctly. No bug. (In this cause, ff course, the sub graph states from previous run is not persisted )It seems in subgraph assigning
checkpointer=True
and callinginterrupt
conflicts in some way.LangGraph Version
0.2.67
System Info
System Information
Package Information
Optional packages not installed
Other Dependencies
The text was updated successfully, but these errors were encountered: