From 60b2ad6e71edf6bf3815eefa74303e9540772094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D1=80=D0=B0=D1=82=20=D0=A4=D0=B0=D0=B7=D1=8B?= =?UTF-8?q?=D0=BB=D0=BE=D0=B2?= Date: Tue, 12 May 2026 21:37:10 +0000 Subject: [PATCH] add file --- main.py | 95 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 43 deletions(-) diff --git a/main.py b/main.py index 6eeec28..f60098d 100644 --- a/main.py +++ b/main.py @@ -1,57 +1,66 @@ -import questionary -from langgraph.graph import StateGraph, START -from langgraph.types import interrupt, Command -from langgraph.checkpoint.memory import InMemorySaver -from typing import TypedDict, List +import sys +from typing import TypedDict, List, Dict, Any -class GraphState(TypedDict): +from langgraph.graph import StateGraph, START +from langgraph.constants import interrupt +from langgraph.types import Command +from langgraph.checkpoint.memory import InMemorySaver +import questionary + +# Define state +class State(TypedDict): human_value: str | None foo: str | None # Node that triggers interrupt - -def interrupt_node(state: GraphState) -> GraphState: - # Trigger interrupt with payload - payload = { +def interrupt_node(state: State) -> State: + # Trigger interrupt with question and options + interrupt_payload = { "type": "confirm", "question": "Уверены, что хотите продолжить?", "allow_responds": ["approve", "reject"], } - # interrupt returns None; graph pauses until resumed - interrupt(payload) - # After resume, state will contain the answer in payload['answer'] - answer = state.get("answer") - state["human_value"] = answer + # Raise interrupt; graph will pause until resumed + interrupt(interrupt_payload) + # After resume, the payload will be merged into state via resume + # We expect state to contain 'human_value' set by resume return state -builder = StateGraph(GraphState) -builder.add_node("interrupt", interrupt_node) -builder.set_entry_point("interrupt") -builder.add_edge(START, "interrupt") -builder.add_edge("interrupt", "interrupt") # loop to finish -graph = builder.compile(checkpointer=InMemorySaver()) +# Build graph +graph = StateGraph(State) +graph.add_node("interrupt", interrupt_node) +graph.set_entry_point(START) +graph.add_edge(START, "interrupt") +# No further nodes; graph ends after interrupt node +graph.set_finish_point("interrupt") + +# Compile with checkpoint +checkpoint = InMemorySaver() +compiled = graph.compile(checkpointer=checkpoint) # Run graph with interrupt handling -config = {"configurable": {"thread_id": "demo"}} - -# Initial state -state: GraphState = {"human_value": None, "foo": None} - -# Stream execution -for chunk in graph.stream(state, config): - if "__interrupt__" in chunk: - # Extract payload - payload = chunk["__interrupt__"][0].value - # Show question - answer = questionary.select( - payload["question"], - choices=payload["allow_responds"], - ).ask() - # Resume with answer - payload["answer"] = answer - resume = Command(resume=payload) - for _ in graph.stream(resume, config): +if __name__ == "__main__": + thread_id = "demo_thread" + config = {"configurable": {"thread_id": thread_id}} + # Start stream + stream = compiled.stream({}, config) + for chunk in stream: + if "__interrupt__" in chunk: + # Extract interrupt payload + interrupt_obj = chunk["__interrupt__"][0] + payload = interrupt_obj.value + # Show question to user + answer = questionary.select( + payload["question"], + choices=payload["allow_responds"], + ).ask() + # Resume with answer + resume_payload = {"human_value": answer} + stream = compiled.stream(Command(resume=resume_payload), config) + for subchunk in stream: + if "human_value" in subchunk: + print("\nFinal state:", subchunk) + sys.exit(0) + else: + # Normal output (none expected here) pass - else: - # Final state output - print("Final state:", chunk)