Files
dz/solutions/69b19fbf67bbf488a1177d94_Human-in-the-loop__interrupt___resume_/interrupt_graph.py
T

88 lines
3.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<|channel|>final code<|message|>import sys
from typing import TypedDict, List
import questionary
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.constants import START
from langgraph.graph import StateGraph
from langgraph.types import interrupt, Command
# ---------- 1. Состояние графа ----------
class GraphState(TypedDict):
human_value: str | None
foo: str | None
# ---------- 2. Узел с прерыванием ----------
def node_with_interrupt(state: GraphState) -> GraphState:
# Если пользователь уже ответил, просто возвращаем состояние
if state.get("human_value") is not None:
return state
# Создаём объект прерывания
interrupt_payload = {
"type": "confirm",
"question": "Уверены, что хотите продолжить?",
"allow_responds": ["approve", "reject"],
}
# Вызываем прерывание – выполнение остановится до возобновления
return interrupt(interrupt_payload)
# ---------- 3. Сборка графа ----------
builder = StateGraph(GraphState)
builder.add_node("interrupt_node", node_with_interrupt)
builder.set_entry_point("interrupt_node")
graph = builder.compile(checkpointer=InMemorySaver())
# ---------- 4. Цикл запуска с обработкой прерывания ----------
def run_graph() -> None:
# Инициализируем состояние
init_state: GraphState = {"human_value": None, "foo": None}
thread_id = "demo_thread"
# Первый запуск – поток до первого прерывания
stream = graph.stream(
init_state,
configurable={"thread_id": thread_id},
)
for chunk in stream:
if "__interrupt__" in chunk:
# Получаем объект прерывания
interrupt_obj = chunk["__interrupt__"][0].value # type: ignore[index]
print("\n=== Появилось прерывание ===")
print(f"Тип: {interrupt_obj['type']}")
print(f"Вопрос: {interrupt_obj['question']}")
print(f"Варианты: {', '.join(interrupt_obj['allow_responds'])}")
# Запрашиваем ответ пользователя
answer = questionary.select(
interrupt_obj["question"],
choices=interrupt_obj["allow_responds"],
).ask()
if answer is None:
sys.exit("Отмена пользователем")
# Добавляем ответ в объект прерывания и возобновляем граф
interrupt_obj["answer"] = answer
resume_cmd = Command(resume=interrupt_obj)
stream = graph.stream(
resume_cmd,
configurable={"thread_id": thread_id},
)
else:
# Выводим обычный результат (можно логировать)
print(chunk)
# После завершения выводим финальное состояние
final_state: GraphState = stream.final_state()
print("\n=== Финальное состояние ===")
print(final_state)
if __name__ == "__main__":
run_graph()