import os import json from langchain_openai import ChatOpenAI from langchain.agents import create_agent from langchain.agents.middleware import HumanInTheLoopMiddleware from langgraph.checkpoint.memory import MemorySaver from langgraph.types import Command # LLM setup 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, ) # Simple tool: get_weather from langchain.tools import tool @tool def get_weather(city: str, date: str = "сегодня") -> str: """Return a mock weather description for the given city and date.""" # In a real scenario, call an API. Here we return a deterministic string. return f"Погода в {city} на {date}: солнечно, 25°C." # Agent with HumanInTheLoopMiddleware memory = MemorySaver() agent = create_agent( model=llm, tools=[get_weather], system_prompt="Ты полезный ассистент.", middleware=[ HumanInTheLoopMiddleware( interrupt_on={"get_weather": True}, description_prefix="Подтвердите вызов инструмента", ), ], checkpointer=memory, ) # Helper to process interrupt and collect decisions def handle_interrupt(interrupt_value): action_requests = interrupt_value["action_requests"] decisions = [] for idx, action in enumerate(action_requests, 1): name = action.get("name") args = action.get("args", {}) description = action.get("description", "") print(f"\n--- Подтверждение {idx} ---") print(f"Инструмент: {name}") print(f"Аргументы: {args}") if description: print(f"Описание: {description}") while True: choice = input("a = approve, r = reject: ").strip().lower() if choice == "a": decisions.append({"type": "approve"}) break elif choice == "r": msg = input("Сообщение для агента (причина отказа): ") decisions.append({"type": "reject", "message": msg}) break else: print("Неверный ввод. Попробуйте снова.") return decisions # Main interaction loop if __name__ == "__main__": config = {"configurable": {"thread_id": "сессия-1"}} while True: user_input = input("\nВы: ") if user_input.lower() in {"exit", "quit"}: print("Завершение.") break # Initial invoke result = agent.invoke({"messages": [{"role": "human", "content": user_input}]}, config=config) # Process interrupts while "__interrupt__" in result: interrupt = result["__interrupt__"][0].value decisions = handle_interrupt(interrupt) result = agent.invoke(Command(resume={"decisions": decisions}), config=config) # Final answer if result.get("messages"): final_msg = result["messages"][-1].content print(f"\nАгент: {final_msg}") else: print("\nАгент не вернул ответа.")