This commit is contained in:
2026-05-12 22:08:06 +00:00
parent 293073ccfb
commit 333c1d5881
+22 -30
View File
@@ -1,27 +1,25 @@
import questionary import questionary
from langgraph.graph import StateGraph, START from langgraph.graph import StateGraph, START
from langgraph.constants import interrupt from langgraph.types import interrupt, Command
from langgraph.types import Command
from langgraph.checkpoint.memory import InMemorySaver from langgraph.checkpoint.memory import InMemorySaver
from typing import TypedDict, List, Dict from typing import TypedDict, List, Dict, Any
class GraphState(TypedDict): class GraphState(TypedDict):
human_value: str | None human_value: str | None
foo: str | None foo: str
# Node that triggers interrupt # Node that triggers interrupt
async def interrupt_node(state: GraphState) -> GraphState:
def interrupt_node(state: GraphState) -> GraphState:
# Trigger interrupt with structured payload # Trigger interrupt with structured payload
payload = { payload = {
"type": "confirm", "type": "confirm",
"question": "Уверены, что хотите продолжить?", "question": "Уверены, что хотите продолжить?",
"allow_responds": ["approve", "reject"], "allow_responds": ["approve", "reject"],
} }
# interrupt returns None, execution pauses until resume # interrupt returns None; graph pauses until resumed
interrupt(payload) interrupt(payload)
# After resume, the same payload will be passed back via state # After resume, state will contain the payload with added answer
# We expect the resume payload to contain 'answer' # Extract answer and store in state
answer = state.get("answer") answer = state.get("answer")
state["human_value"] = answer state["human_value"] = answer
return state return state
@@ -30,38 +28,32 @@ def interrupt_node(state: GraphState) -> GraphState:
builder = StateGraph(GraphState) builder = StateGraph(GraphState)
builder.add_node("interrupt_node", interrupt_node) builder.add_node("interrupt_node", interrupt_node)
builder.set_entry_point("interrupt_node") builder.set_entry_point("interrupt_node")
builder.add_edge(START, "interrupt_node")
# No further nodes; graph ends after node
builder.set_finish_point("interrupt_node") builder.set_finish_point("interrupt_node")
# Use InMemorySaver for checkpointing
# Compile with checkpoint
checkpoint = InMemorySaver() checkpoint = InMemorySaver()
graph = builder.compile(checkpointer=checkpoint) graph = builder.compile(checkpointer=checkpoint)
# Run graph with interrupt handling # Run graph with interrupt handling
config = {"configurable": {"thread_id": "thread-1"}} config = {"configurable": {"thread_id": "thread-1"}}
# Initial state stream = graph.stream({}, config)
state: GraphState = {"human_value": None, "foo": None}
# Start streaming
stream = graph.stream(state, config)
for chunk in stream: for chunk in stream:
if "__interrupt__" in chunk: if "__interrupt__" in chunk:
# Extract payload # Get the interrupt payload
payload = chunk["__interrupt__"][0].value interrupt_payload = chunk["__interrupt__"][0].value
# Show question to user # Show question to user
answer = questionary.select( answer = questionary.select(
payload["question"], interrupt_payload["question"],
choices=payload["allow_responds"], choices=interrupt_payload["allow_responds"],
).ask() ).ask()
# Add answer to payload and resume # Add answer to payload and resume
payload["answer"] = answer interrupt_payload["answer"] = answer
# Resume graph stream = graph.stream(Command(resume=interrupt_payload), config)
stream = graph.stream(Command(resume=payload), config)
# Continue processing resumed stream
for subchunk in stream:
if "__interrupt__" in subchunk:
# Should not happen in this simple example
continue continue
print(subchunk) # Print final state when finished
else: if "node" in chunk:
print(chunk) print("Final state:", chunk["node"]["human_value"])
break
print("Final state:", state)