[PR #4374] [breaking]: Improve interrupt behavior when stream_mode='values' #3792

Closed
opened 2026-02-20 17:49:10 -05:00 by yindo · 0 comments
Owner

Original Pull Request: https://github.com/langchain-ai/langgraph/pull/4374

State: closed
Merged: Yes


This PR does a few things:

  1. Surfaces interrupts when stream_mode='values' (particularly relevant for invoke, where this is the default behavior)
  2. Adds an interrupt_id property to the Interrupt dataclass so that interrupts can effectively be mapped to resumes
  3. Minor docs updates to reflect the new pattern (no need for a special section on interrupts with invoke and ainvoke)
  • In a different PR (the one with the multiple resume values), as it's more relevant there: add an interrupts property to StateSnapshot so that interrupts can easily be iterated over if users are attempting to map interrupts to resumes.

I don't recommend we release this until we have multi-resumes working.

Example

We have the following setup where we're sending multiple prompts to the child graph, which uses interrupt:

def child_graph(state):
    human_input = interrupt(state["prompt"])

    return {
        "human_inputs": [human_input],
    }
Screenshot 2025-04-23 at 10 01 12 AM

Old behavior:

initial_input = {"prompts": ["a", "b"]}

print(parent_graph.invoke(input=initial_input,config=thread_config,stream_mode="values"))
#> {'prompts': ['a', 'b'], 'human_inputs': []}

print(parent_graph.invoke(Command(resume="hello 1"),config=thread_config,stream_mode="values"))
#> {'prompts': ['a', 'b'], 'human_inputs': ['hello 1']}

print(parent_graph.invoke(Command(resume="hello 2"),config=thread_config,stream_mode="values"))
#> {'prompts': ['a', 'b'], 'human_inputs': ['hello 1', 'hello 2']}

New behavior:

initial_input = {"prompts": ["a", "b"]}

print(parent_graph.invoke(input=initial_input,config=thread_config,stream_mode="values"))
"""
{
  "prompts": ["a", "b"],
  "human_inputs": [],
  "__interrupt__": [
    Interrupt(
      value="a",
      resumable=True,
      ns=["child_graph:38d43a18-a5e7-8ab2-ca83-9d80f6e9ca83"]
    ),
    Interrupt(
      value="b",
      resumable=True,
      ns=["child_graph:dad810e8-738e-9f90-41cd-30c0091eb79b"]
    )
  ]
}
"""

print(parent_graph.invoke(Command(resume="hello 1"),config=thread_config,stream_mode="values"))
"""
{
  "prompts": ["a", "b"],
  "human_inputs": ["hello 1"],
  "__interrupt__": [
    Interrupt(
      value="b",
      resumable=True,
      ns=["child_graph:dad810e8-738e-9f90-41cd-30c0091eb79b"]
    )
  ]
}
"""

print(parent_graph.invoke(Command(resume="hello 2"),config=thread_config,stream_mode="values"))
#> {'prompts': ['a', 'b'], 'human_inputs': ['hello 1', 'hello 2']}
**Original Pull Request:** https://github.com/langchain-ai/langgraph/pull/4374 **State:** closed **Merged:** Yes --- This PR does a few things: 1. Surfaces interrupts when `stream_mode='values'` (particularly relevant for `invoke`, where this is the default behavior) 2. Adds an `interrupt_id` property to the `Interrupt` dataclass so that interrupts can effectively be mapped to resumes 3. Minor docs updates to reflect the new pattern (no need for a special section on interrupts with `invoke` and `ainvoke`) * In a different PR (the one with the multiple resume values), as it's more relevant there: add an `interrupts` property to `StateSnapshot` so that `interrupts` can easily be iterated over if users are attempting to map interrupts to resumes. I **don't** recommend we release this until we have multi-resumes working. ## Example We have the following setup where we're sending multiple prompts to the child graph, which uses `interrupt`: ```py def child_graph(state): human_input = interrupt(state["prompt"]) return { "human_inputs": [human_input], } ``` <img width="142" alt="Screenshot 2025-04-23 at 10 01 12 AM" src="https://github.com/user-attachments/assets/c6238bf1-54ad-4e48-ab0b-60a0bfc18485" /> Old behavior: ```py initial_input = {"prompts": ["a", "b"]} print(parent_graph.invoke(input=initial_input,config=thread_config,stream_mode="values")) #> {'prompts': ['a', 'b'], 'human_inputs': []} print(parent_graph.invoke(Command(resume="hello 1"),config=thread_config,stream_mode="values")) #> {'prompts': ['a', 'b'], 'human_inputs': ['hello 1']} print(parent_graph.invoke(Command(resume="hello 2"),config=thread_config,stream_mode="values")) #> {'prompts': ['a', 'b'], 'human_inputs': ['hello 1', 'hello 2']} ``` New behavior: ```py initial_input = {"prompts": ["a", "b"]} print(parent_graph.invoke(input=initial_input,config=thread_config,stream_mode="values")) """ { "prompts": ["a", "b"], "human_inputs": [], "__interrupt__": [ Interrupt( value="a", resumable=True, ns=["child_graph:38d43a18-a5e7-8ab2-ca83-9d80f6e9ca83"] ), Interrupt( value="b", resumable=True, ns=["child_graph:dad810e8-738e-9f90-41cd-30c0091eb79b"] ) ] } """ print(parent_graph.invoke(Command(resume="hello 1"),config=thread_config,stream_mode="values")) """ { "prompts": ["a", "b"], "human_inputs": ["hello 1"], "__interrupt__": [ Interrupt( value="b", resumable=True, ns=["child_graph:dad810e8-738e-9f90-41cd-30c0091eb79b"] ) ] } """ print(parent_graph.invoke(Command(resume="hello 2"),config=thread_config,stream_mode="values")) #> {'prompts': ['a', 'b'], 'human_inputs': ['hello 1', 'hello 2']} ```
yindo added the pull-request label 2026-02-20 17:49:10 -05:00
yindo closed this issue 2026-02-20 17:49:10 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langchain-ai/langgraph#3792