diff --git a/main.py b/main.py index 273d069..ca7f860 100644 --- a/main.py +++ b/main.py @@ -1,104 +1,58 @@ -import os import asyncio from langchain_openai import ChatOpenAI +from langchain_core.messages import HumanMessage from langchain.tools import tool -from langchain.agents.middleware import HumanInTheLoopMiddleware -from deepagents import create_deep_agent -from deepagents.backends import CompositeBackend, LocalShellBackend, FilesystemBackend +from langgraph.checkpoint.memory import MemorySaver +from langgraph.graph import StateGraph from langgraph.types import Command -# ---------- LLM ---------- -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, -) +# LLM +llm = ChatOpenAI(model="gpt-4o-mini", base_url="https://openrouter.ai/api/v1", api_key=os.getenv("OPENAI_API_KEY"), temperature=0.0) -# ---------- Backend ---------- -backend = CompositeBackend([ - LocalShellBackend(workspace_dir="./workspace"), - FilesystemBackend(), -]) - -# ---------- Tool ---------- +# Simple tool @tool -def get_weather(city: str, date: str = "today") -> str: - """Return a mock weather report for the given city and date.""" - return f"The weather in {city} on {date} is sunny with a high of 25°C." +def get_weather(city: str, date: str) -> str: + return f"Погода в {city} на {date}: солнечно, 25°C" -# ---------- Agent ---------- -agent = create_deep_agent( +# Agent with middleware +memory = MemorySaver() + +agent = create_agent( model=llm, tools=[get_weather], - backend=backend, - system_prompt="You are a helpful assistant.", + system_prompt='Ты полезный ассистент', middleware=[ HumanInTheLoopMiddleware( interrupt_on={"get_weather": True}, description_prefix="Подтвердите вызов инструмента", ), ], + checkpointer=memory, ) -# ---------- Helper to process interrupt ---------- -async def handle_interrupt(result, config): - interrupt = result["__interrupt__"][0].value - action_requests = interrupt["action_requests"] - review_configs = interrupt["review_configs"] - decisions = [] - for idx, action in enumerate(action_requests): - name = action["name"] - args = action["args"] - description = action.get("description", "") - print(f"\n--- Подтверждение ---") - print(f"Инструмент: {name}") - print(f"Аргументы: {args}") - if description: - print(f"Описание: {description}") - # Determine allowed decisions - allowed = review_configs[idx].get("allowed_decisions", ["approve", "reject", "edit"]) - while True: - choice = input(f"a = approve, r = reject{', e = edit' if 'edit' in allowed else ''}: ").strip().lower() - if choice == "a" and "approve" in allowed: - decisions.append({"type": "approve"}) - break - if choice == "r" and "reject" in allowed: - msg = input("Сообщение для агента (причина отказа): ") - decisions.append({"type": "reject", "message": msg}) - break - if choice == "e" and "edit" in allowed: - # Simple edit: ask for new args as JSON - import json - new_args = input("Введите отредактированные аргументы в формате JSON: ") - try: - new_args_dict = json.loads(new_args) - decisions.append({"type": "edit", "edited_action": {"name": name, "args": new_args_dict}}) - break - except json.JSONDecodeError: - print("Неверный JSON, попробуйте снова.") - print("Неверный выбор, попробуйте снова.") - # Resume agent - return await agent.ainvoke(Command(resume={"decisions": decisions}), config) - -# ---------- Main loop ---------- async def main(): - config = {"configurable": {"thread_id": "session-1"}} - while True: - user_input = input("Вы: ") - if user_input.lower() in {"exit", "quit"}: - break - # Initial invoke - result = await agent.ainvoke( - {"messages": [{"role": "human", "content": user_input}]}, - config, - ) - # Process interrupts - while "__interrupt__" in result: - result = await handle_interrupt(result, config) - # Final answer - final_msg = result["messages"][-1].content - print(f"\nАгент: {final_msg}\n") + config = {"configurable": {"thread_id": "сессия-1"}} + result = await agent.ainvoke( + {"messages": [{"role": "human", "content": "Какая погода в Казани сегодня?"}]}, + config=config, + ) + # loop for interrupts + while "__interrupt__" in result: + interrupt = result["__interrupt__"][0].value + decisions = [] + for req in interrupt["action_requests"]: + print(f"Инструмент: {req['name']}") + print(f"Аргументы: {req['args']}") + if "description" in req: + print(req["description"]) + choice = input("a=approve, r=reject: ") + if choice.lower() == "a": + decisions.append({"type": "approve"}) + else: + msg = input("Причина отказа: ") + decisions.append({"type": "reject", "message": msg}) + result = await agent.ainvoke(Command(resume={"decisions": decisions}), config=config) + print("\nОтвет: ", result["messages"][-1]["content"]) if __name__ == "__main__": asyncio.run(main())