feat: solution for unknown

This commit is contained in:
+38 -48
View File
@@ -1,67 +1,57 @@
from typing import TypedDict, Dict, Any from langchain_openai import ChatOpenAI
from pydantic import SecretStr
from langgraph.graph import StateGraph, START, END from langgraph.graph import StateGraph, START, END, interrupt
from langgraph.checkpoint.memory import InMemorySaver from langgraph.checkpoint.memory import InMemorySaver
from typing import TypedDict
# LLM placeholder
llm = ChatOpenAI(
model="openai/gpt-oss-20b",
base_url='https://platform.brojs.ru/jrnl-bh/api/inference/v1',
api_key=SecretStr("jrnl_30283ab953615cbb6846ff9940a1eedce0b76d7b2f59a2394f29e74643e6a90d"),
temperature=0.7,
)
# State definition
class GraphState(TypedDict): class GraphState(TypedDict):
human_value: str | None human_value: str | None
__interrupt__: dict[str, Any] | None # for interrupt payload
__resume__: str | None # for resume payload
# Node that triggers an interrupt with a question and options
def interrupt_node(state: GraphState) -> Dict[str, Any]: def ask_node(state: GraphState) -> dict:
"""Trigger an interrupt asking the user to choose a value.""" return interrupt(
return { {
"__interrupt__": {
"type": "question", "type": "question",
"question": "Choose a value:", "question": "Выберите вариант:",
"options": ["Option A", "Option B", "Option C"], "options": ["Опция 1", "Опция 2", "Опция 3"],
} }
} )
def resume_node(state: GraphState) -> Dict[str, Any]:
"""Store the user's choice and finish."""
# The chosen option is passed via the __resume__ key
if state.get("__resume__") is not None:
state["human_value"] = state["__resume__"]
return {"__end__": True}
# Build the graph
builder = StateGraph(GraphState) builder = StateGraph(GraphState)
builder.add_node("interrupt", interrupt_node) builder.add_node("ask", ask_node)
builder.add_node("resume", resume_node) builder.set_entry_point(START)
builder.add_edge(START, "ask")
# The graph starts with the interrupt node builder.add_edge("ask", END)
builder.set_entry_point("interrupt")
# After a successful resume, we end the graph
builder.add_edge(START, "interrupt")
builder.add_conditional_edges(
"interrupt",
lambda x: "__interrupt__" in x,
{"__interrupt__": "resume"},
)
builder.add_edge("resume", END)
graph = builder.compile(checkpointer=InMemorySaver()) graph = builder.compile(checkpointer=InMemorySaver())
# Run the graph and handle interrupts # Main loop handling interrupts
state: GraphState = {"human_value": None, "__interrupt__": None, "__resume__": None} state: GraphState = {"human_value": None}
while True: while True:
result = graph.invoke(state) result = graph.invoke(state)
if "__interrupt__" in result and result["__interrupt__"] is not None: if "__interrupt__" in result:
interrupt_info = result["__interrupt__"] interrupt_data = result["__interrupt__"]
print(interrupt_info["question"]) print(interrupt_data["question"])
for idx, opt in enumerate(interrupt_info["options"], 1): for idx, opt in enumerate(interrupt_data["options"], 1):
print(f"{idx}. {opt}") print(f"{idx}. {opt}")
choice_idx = int(input("Enter number: ")) - 1 choice = input("Выберите номер: ").strip()
chosen = interrupt_info["options"][choice_idx] try:
# Resume the graph with the chosen value selected = interrupt_data["options"][int(choice) - 1]
state = graph.invoke(state, {"__resume__": chosen}) state["human_value"] = selected
except (ValueError, IndexError):
print("Неверный выбор. Повторите.")
else: else:
# Graph finished
break break
print("Final state:", state) print("\nИтоговое состояние:")
print(state)