"""Deep research agent: веб-поиск, виртуальные файлы, экспорт на диск. Основано на курсе deep agents from scratch: https://github.com/langchain-ai/deep-agents-from-scratch/blob/main/notebooks/4_full_agent.ipynb """ from __future__ import annotations import os import sys from pathlib import Path from dotenv import load_dotenv from deepagents import create_deep_agent from deepagents.backends import LocalShellBackend from langchain_openai import ChatOpenAI from export_tools import DEFAULT_OUTPUT_DIR, WORKSPACE_DIR, export_virtual_files, export_workspace_to_disk from web_tools import get_page_content, web_search load_dotenv() BROJS_INFERENCE_URL = "https://platform.brojs.ru/jrnl-bh/api/inference/v1" DEFAULT_MODEL = "openai/gpt-oss-20b:free" SYSTEM_PROMPT = """\ Ты исследовательский deep-агент (стиль deep agents from scratch). Твоя работа: 1. Искать информацию в интернете через web_search и при необходимости get_page_content. 2. Сохранять результаты во ВИРТУАЛЬНЫЕ файлы через write_file (например /research/query.md, /research/summary.md, /research/sources.txt). Не оставляй всё только в чате. 3. Используй write_todos для плана исследования. 4. В КОНЦЕ обязательно вызови export_virtual_files с target_dir="./output", чтобы выгрузить виртуальные файлы в реальную файловую систему. Правила: - Один инструмент за шаг, если возможно. - В файлах — структурированные заметки: запрос, источники, выводы. - Отвечай на русском. """ def _api_key() -> str: return ( os.getenv("OPENAI_API_KEY") or os.getenv("JOURNAL_MCP_PAT") or os.getenv("JOURNAL_TOKEN") or "" ) def _base_url() -> str: if os.getenv("OPENAI_BASE_URL"): return os.environ["OPENAI_BASE_URL"] if os.getenv("OPENAI_API_KEY"): return os.getenv("OPENROUTER_BASE_URL", "https://openrouter.ai/api/v1") return BROJS_INFERENCE_URL def _model() -> str: return os.getenv("OPENAI_MODEL") or os.getenv("OPENROUTER_MODEL") or DEFAULT_MODEL def build_llm() -> ChatOpenAI: return ChatOpenAI( model=_model(), base_url=_base_url(), api_key=_api_key(), temperature=0.2, ) def build_agent(): WORKSPACE_DIR.mkdir(parents=True, exist_ok=True) backend = LocalShellBackend( root_dir=str(WORKSPACE_DIR.resolve()), virtual_mode=True, inherit_env=True, ) llm = build_llm() return create_deep_agent( model=llm, tools=[web_search, get_page_content, export_virtual_files], system_prompt=SYSTEM_PROMPT, backend=backend, ) def run_research(query: str) -> None: agent = build_agent() print(f"Запрос: {query}\n") print("Агент работает (поиск → виртуальные файлы → экспорт)...\n") result = agent.invoke( { "messages": [ { "role": "human", "content": ( f"Исследуй тему: {query}. " "Сохрани заметки в виртуальные файлы и в конце выгрузи их через export_virtual_files." ), } ] } ) last = result["messages"][-1] print("\n--- Ответ агента ---") print(getattr(last, "content", last)) # Гарантированный экспорт, даже если агент не вызвал инструмент exported = export_workspace_to_disk(output_dir=DEFAULT_OUTPUT_DIR) print(f"\n--- Файлы на диске ({DEFAULT_OUTPUT_DIR}) ---") if exported: for path in exported: print(f" {path}") else: print(" (пусто — агент не создал файлов в agent_workspace)") def main() -> None: query = " ".join(sys.argv[1:]).strip() or "LangGraph deep agents и context engineering" run_research(query) if __name__ == "__main__": main()