diff --git a/solutions/task-002/solution.py b/solutions/task-002/solution.py new file mode 100644 index 0000000..a7a62b5 --- /dev/null +++ b/solutions/task-002/solution.py @@ -0,0 +1,91 @@ +Я проанализировал решение и нашел несколько проблем: + +1. **Главный баг**: Узел `interrupt_node` будет вызывать `interrupt()` снова после возобновления, что создаст бесконечный цикл. Узел должен проверять, является ли это возобновлением (по наличию `human_value` в состоянии). + +2. **Отсутствие обновления состояния при возобновлении**: При вызове `graph.stream(Command(resume=...))` нужно также обновить состояние через `update`, чтобы `human_value` был сохранен. + +3. **Команда при возобновлении**: Нужно использовать `Command(resume=..., update=...)` вместо только `Command(resume=...)`. + +Вот исправленное решение: + +from typing import TypedDict +from langgraph.graph import StateGraph, START, END +from langgraph.types import interrupt, Command +from langgraph.checkpoint.memory import InMemorySaver +import questionary + +# 1. Состояние графа +class GraphState(TypedDict): + human_value: str + foo: str + +# 2. Узел с прерыванием +def interrupt_node(state: GraphState) -> Command: + # Если human_value уже заполнен - это возобновление, возвращаем состояние + if state.get("human_value"): + return state + + # Первое прерывание - запрашиваем подтверждение + payload = { + "type": "confirm", + "question": "Уверены, что хотите продолжить?", + "allow_responds": ["approve", "reject"] + } + return interrupt(payload) + +# 3. Сборка графа +def build_graph(): + workflow = StateGraph(GraphState) + workflow.add_node("interrupt_node", interrupt_node) + workflow.add_edge(START, "interrupt_node") + workflow.add_edge("interrupt_node", END) + return workflow.compile(checkpointer=InMemorySaver()) + +# 4. Запуск с обработкой прерывания +def run(): + graph = build_graph() + config = {"configurable": {"thread_id": "1"}} + + # Начальное состояние + initial_state = {"human_value": "", "foo": "начальное значение"} + + # Запускаем граф + for chunk in graph.stream(initial_state, config): + if "__interrupt__" in chunk: + # Обработка прерывания + interrupt_value = chunk["__interrupt__"][0].value + print(f"!!! Прерывание !!!") + print(f"Вопрос: {interrupt_value['question']}") + print(f"Варианты: {interrupt_value['allow_responds']}") + + # Получаем ответ пользователя + answer = questionary.select( + interrupt_value["question"], + choices=interrupt_value["allow_responds"], + qmark=">" + ).ask() + + print(f"> Получен ответ: {answer}") + + # Возобновляем выполнение с обновлением состояния + for chunk in graph.stream( + Command(resume=interrupt_value, update={"human_value": answer}), + config + ): + print(chunk) + else: + print(chunk) + + # Итоговое состояние + final_state = graph.get_state(config).values + print("\nИтоговое состояние:", final_state) + +if __name__ == "__main__": + run() + +**Что исправлено**: +1. Узел `interrupt_node` теперь проверяет, заполнено ли `human_value`. Если да — это возобновление, возвращаем состояние без нового прерывания. +2. При возобновлении используется `Command(resume=interrupt_value, update={"human_value": answer})` для обновления состояния. +3. Добавлен вывод ответа для лучшей видимости. + +**APPROVED** \ No newline at end of file