From c1665f3788d31410089138725cc87181604ad1c2 Mon Sep 17 00:00:00 2001 From: dimitrievgs Date: Sat, 6 Jun 2026 01:08:25 +0300 Subject: [PATCH] Add debug info display --- app/api.py | 2 +- app/react_agent.py | 15 ++++++++++----- app/workflows.py | 21 ++++++++++++++++++++- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/app/api.py b/app/api.py index c46b9b8..72cb18f 100644 --- a/app/api.py +++ b/app/api.py @@ -232,7 +232,7 @@ def chat_stream(): cache_folder = data.get("cache_folder") temperature = data.get("temperature", DEFAULT_TEMPERATURE) max_tokens = data.get("max_tokens") - agency_mode = data.get("agency_mode", False) # НОВОЕ: Перехватываем режим тумблера "Агент" + agency_mode = data.get("agency_mode", False) # Необязательный параметр для существующего узла ассистента при регенерации existing_assistant_node_id = data.get("existing_assistant_node_id") diff --git a/app/react_agent.py b/app/react_agent.py index eec1257..ec91bcf 100644 --- a/app/react_agent.py +++ b/app/react_agent.py @@ -19,7 +19,7 @@ from typing import Any, get_type_hints from langchain_core.tools import StructuredTool from pydantic import BaseModel, Field, create_model -def build_react_agent(model_name: str, temperature: float, max_tokens: int, agency_mode: bool, obsidian_settings: dict): +def build_react_agent(model_name: str, temperature: float, max_tokens: int, agency_mode: bool, obsidian_settings: dict, debug_callback=None): """Инициализация ядра на базе LangGraph.""" m_cfg = MODELS.get(model_name) llm = ChatOpenAI( @@ -30,7 +30,7 @@ def build_react_agent(model_name: str, temperature: float, max_tokens: int, agen max_tokens=max_tokens if max_tokens else None, streaming=True ) - tools = get_dynamic_tools(obsidian_settings) if agency_mode else [] + tools = get_dynamic_tools(obsidian_settings, debug_callback) if agency_mode else [] return create_react_agent(llm, tools=tools) # Специфическая Pydantic-модель для инструментов без скрипта @@ -41,7 +41,7 @@ class SystemHelpSchema(BaseModel): dummy: str = Field(default="", description="Необязательный параметр, оставь пустым.") def create_subprocess_tool(script_path: str, method_name: str, - hidden_prompt: str): + hidden_prompt: str, debug_callback=None): """Вид 2: Инструмент со скриптом + пост-процессинг.""" script_dir = os.path.dirname(os.path.abspath(script_path)) @@ -69,6 +69,7 @@ def create_subprocess_tool(script_path: str, method_name: str, @functools.wraps(func) def wrapper(**kwargs: Any) -> str: + input_json = json.dumps(kwargs, indent=2, ensure_ascii=False) runner_code = f""" import json import sys @@ -106,6 +107,10 @@ finally: ) raw_output = process.stdout.strip() + # ВЫЗЫВАЕМ КОЛБЭК, если он передан + if debug_callback: + debug_callback(input_json, raw_output) + raw_stripped = raw_output.strip() if raw_output else "" prompt_stripped = hidden_prompt.strip() if hidden_prompt else "" @@ -158,7 +163,7 @@ finally: args_schema=args_schema, # ← вместо infer_schema=True ) -def get_dynamic_tools(obsidian_settings: dict): +def get_dynamic_tools(obsidian_settings: dict, debug_callback=None): """Собирает инструменты двух видов на основе настроек Obsidian.""" tools = [] custom_tools = obsidian_settings.get("customTools", []) @@ -221,7 +226,7 @@ def get_dynamic_tools(obsidian_settings: dict): # ВИД 2: Скрипт + Прилизывание # ---------------------------------------------------- try: - tool = create_subprocess_tool(script_path, method_name, hidden_prompt) + tool = create_subprocess_tool(script_path, method_name, hidden_prompt, debug_callback) tool.name = name # Приоритет имени из UI Obsidian if desc: tool.description = desc diff --git a/app/workflows.py b/app/workflows.py index 0436011..d161315 100644 --- a/app/workflows.py +++ b/app/workflows.py @@ -87,13 +87,20 @@ def run_agent_streaming(graph_id: str, elif role == "assistant": messages_for_llm.append(AIMessage(content=msg.get("content", ""))) + # Локальное хранилище для отладки текущего запуска + current_run_debug = [] + + def capture_debug(req, res): + current_run_debug.append({"req": req, "res": res}) + # 3. Создаем агента. Если agency_mode == False, он соберет 0 тулов и отработает как обычная LLM. agent_executor = build_react_agent( model_name=model, temperature=temperature, max_tokens=max_tokens, agency_mode=agency_mode, - obsidian_settings=obsidian_settings or {} + obsidian_settings=obsidian_settings or {}, + debug_callback=capture_debug ) # 4. Выполняем цикл с потоковой передачей событий @@ -132,6 +139,18 @@ def run_agent_streaming(graph_id: str, "node_id": assistant_node_id } + # В САМОМ КОНЦЕ, после того как агент закончил работу (вышел из цикла) + if current_run_debug and obsidian_settings.get('showDebugInfo'): + debug_section = "\n\n---\n" + "\n\n---\n".join([ + f"**JSON Request:**\n```json\n{d['req']}\n```\n**Result:**\n```text\n{d['res']}\n```" + for d in current_run_debug + ]) + yield { + "type": "chunk", + "content": debug_section, + "node_id": assistant_node_id + } + except Exception as e: print(f"Ошибка при стриминге: {e}") import traceback