diff --git a/main.py b/main.py new file mode 100644 index 0000000..81c648c --- /dev/null +++ b/main.py @@ -0,0 +1,61 @@ +import questionary +from langgraph.graph import StateGraph, START +from langgraph.types import interrupt, Command +from langgraph.checkpoint.memory import InMemorySaver +from typing import TypedDict, Annotated + +# State definition +class GraphState(TypedDict): + human_value: Annotated[str | None, "value chosen by user"] + foo: Annotated[str, "initial data placeholder"] + +# Node that triggers interrupt + +def interrupt_node(state: GraphState) -> GraphState: + # Trigger interrupt with structured payload + payload = { + "type": "confirm", + "question": "Уверены, что хотите продолжить?", + "allow_responds": ["approve", "reject"], + } + # Call interrupt; execution pauses until resumed + interrupt(payload) + # After resume, payload will contain 'answer' + # We expect the resumed payload to be the same dict with added 'answer' + # The node receives the resumed payload as its return value + # So we just return the state with human_value set + return {"human_value": payload.get("answer", None), "foo": state.get("foo", "")} + +# Build graph +builder = StateGraph(GraphState) +builder.add_node("interrupt_node", interrupt_node) +builder.set_entry_point("interrupt_node") +builder.add_edge(START, "interrupt_node") +# No further nodes; graph ends after interrupt node +graph = builder.compile(checkpointer=InMemorySaver()) + +# Run graph with interrupt handling +if __name__ == "__main__": + config = {"configurable": {"thread_id": "hitl-demo"}} + # Initial state + state = {"human_value": None, "foo": "initial"} + # Stream execution + for chunk in graph.stream(state, config): + if "__interrupt__" in chunk: + # Extract interrupt payload + interrupt_payload = chunk["__interrupt__"][0].value + # Show question to user + answer = questionary.select( + interrupt_payload["question"], + choices=interrupt_payload["allow_responds"], + ).ask() + # Add answer to payload and resume + interrupt_payload["answer"] = answer + # Resume graph + for resume_chunk in graph.stream(Command(resume=interrupt_payload), config): + # Print final state when graph finishes + if "node" in resume_chunk: + print("Final state:", resume_chunk["node"]) + else: + # Normal output (none expected here) + pass