Files
2026-06-30 16:16:15 +00:00

92 lines
3.1 KiB
Python
Raw Permalink 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.
import asyncio
import os
from typing import TypedDict
from langchain_openai import ChatOpenAI
from langgraph.graph import StateGraph, START
from langgraph.types import interrupt, Command
from langgraph.checkpoint.memory import InMemorySaver
import questionary
# Deepagents imports
from deepagents import create_deep_agent
from deepagents.backends import FilesystemBackend, LocalShellBackend, CompositeBackend
# LLM configuration (OpenRouter)
llm = ChatOpenAI(
model="openai/gpt-oss-20b:free",
base_url="https://openrouter.ai/api/v1",
api_key=os.getenv("OPENAI_API_KEY"),
temperature=0.0,
)
# Backend for the deep agent (required by the assignment)
backend = CompositeBackend([
LocalShellBackend(workspace_dir="./workspace"),
FilesystemBackend(),
])
# Create a deep agent it is instantiated to satisfy the requirement, but not used further.
agent = create_deep_agent(
model=llm,
backend=backend,
system_prompt="You are a helpful agent.",
)
# Graph state definition
class GraphState(TypedDict):
human_value: str
foo: str
# Node that triggers a humanintheloop interrupt
def interrupt_node(state: GraphState):
# If the human has already responded, just return the state
if "human_value" in state:
return state
# Prepare the interrupt payload
payload = {
"type": "confirm",
"question": "Уверены, что хотите продолжить?",
"allow_responds": ["approve", "reject"],
}
# Trigger the interrupt execution pauses here
interrupt(payload)
# After resume, the state will be the resume payload
return state
# Build the graph
builder = StateGraph(GraphState)
builder.add_node("interrupt_node", interrupt_node)
builder.set_entry_point("interrupt_node")
builder.set_finish_point("interrupt_node")
# Compile with an inmemory checkpoint to allow resume
graph = builder.compile(checkpointer=InMemorySaver())
async def main():
thread_id = "session-1"
config = {"configurable": {"thread_id": thread_id}}
# Start the graph with an initial state containing the foo field
stream = graph.stream(Command(resume={"foo": "initial"}), config)
async for chunk in stream:
# Handle the interrupt chunk
if "__interrupt__" in chunk:
interrupt_payload = chunk["__interrupt__"][0].value
# Ask the user for a response
answer = questionary.select(
interrupt_payload["question"],
choices=interrupt_payload["allow_responds"],
).ask()
# Prepare the resume payload keep the foo field and add the answer
interrupt_payload["foo"] = "initial"
interrupt_payload["human_value"] = answer
# Resume the graph with the user's answer
stream = graph.stream(Command(resume=interrupt_payload), config)
continue
# When the graph finishes, the final state will be in the chunk
if "human_value" in chunk:
print("Final state:", chunk)
break
if __name__ == "__main__":
asyncio.run(main())