Spaces:
Running
Running
| from __future__ import annotations | |
| import subprocess | |
| import sys | |
| from pathlib import Path | |
| from typing import Any | |
| from config import Settings | |
| from graph.state import AgentState, PlanStep | |
| from models.openrouter_model import OpenRouterModels | |
| from tools.audio_transcriber import transcribe_audio | |
| from tools.image_analyzer import analyze_image | |
| from tools.pdf_reader import read_supported_file | |
| from tools.python_tool import calculate_expression | |
| from tools.web_search import search_web | |
| from tools.webpage_reader import read_webpage | |
| def execute_next_tool( | |
| state: AgentState, | |
| settings: Settings, | |
| models: OpenRouterModels, | |
| ) -> dict[str, Any]: | |
| plan = [ | |
| dict(step) | |
| for step in state.get("plan", []) | |
| ] | |
| index = state.get( | |
| "step_index", | |
| 0, | |
| ) | |
| if index >= len(plan): | |
| return { | |
| "step_index": index, | |
| } | |
| step: PlanStep = plan[index] | |
| action = step.get( | |
| "action", | |
| "", | |
| ) | |
| result: dict[str, Any] | |
| try: | |
| if action == "web_search": | |
| query = ( | |
| step.get("query") | |
| or step.get("instruction") | |
| or state["question"] | |
| ) | |
| result = search_web( | |
| query, | |
| settings, | |
| ) | |
| elif action == "read_webpage": | |
| url = ( | |
| step.get("query") | |
| or _best_url(state) | |
| ) | |
| result = read_webpage( | |
| url, | |
| settings, | |
| ) | |
| elif action == "read_file": | |
| result = read_supported_file( | |
| state.get("file_path"), | |
| state["question"], | |
| ) | |
| elif action == "analyze_image": | |
| result = analyze_image( | |
| state.get("file_path"), | |
| state["question"], | |
| models.vision, | |
| ) | |
| elif action == "transcribe_audio": | |
| file_path = state.get( | |
| "file_path" | |
| ) | |
| if not file_path: | |
| raise ValueError( | |
| "No audio file is available." | |
| ) | |
| result = transcribe_audio( | |
| file_path | |
| ) | |
| elif action == "execute_python_file": | |
| file_path = state.get( | |
| "file_path" | |
| ) | |
| if not file_path: | |
| raise ValueError( | |
| "No Python file is available." | |
| ) | |
| result = _execute_python_file( | |
| file_path | |
| ) | |
| elif action == "calculate": | |
| expression = ( | |
| step.get("expression") | |
| or step.get("query") | |
| or step.get( | |
| "instruction", | |
| "", | |
| ) | |
| ) | |
| result = calculate_expression( | |
| expression | |
| ) | |
| else: | |
| result = { | |
| "ok": False, | |
| "error": ( | |
| f"Unsupported action: {action}" | |
| ), | |
| } | |
| except Exception as exc: | |
| result = { | |
| "ok": False, | |
| "error": ( | |
| f"{type(exc).__name__}: {exc}" | |
| ), | |
| } | |
| step["status"] = ( | |
| "done" | |
| if result.get("ok") | |
| else "failed" | |
| ) | |
| step["result"] = str( | |
| result.get("content") | |
| or result.get("error") | |
| or "" | |
| )[:6000] | |
| plan[index] = step | |
| tool_record = { | |
| "action": action, | |
| "instruction": step.get( | |
| "instruction", | |
| "", | |
| ), | |
| **result, | |
| } | |
| evidence = list( | |
| state.get("evidence", []) | |
| ) | |
| if result.get("ok"): | |
| evidence.append( | |
| { | |
| "source": result.get( | |
| "source", | |
| action, | |
| ), | |
| "content": str( | |
| result.get( | |
| "content", | |
| "", | |
| ) | |
| )[:10000], | |
| "metadata": result.get( | |
| "metadata", | |
| {}, | |
| ), | |
| } | |
| ) | |
| return { | |
| "plan": plan, | |
| "step_index": index + 1, | |
| "iteration": ( | |
| state.get("iteration", 0) | |
| + 1 | |
| ), | |
| "tool_results": [ | |
| *state.get( | |
| "tool_results", | |
| [], | |
| ), | |
| tool_record, | |
| ], | |
| "evidence": evidence, | |
| "error": "", | |
| } | |
| def _execute_python_file( | |
| file_path: str, | |
| timeout: int = 45, | |
| ) -> dict[str, Any]: | |
| path = Path(file_path) | |
| if not path.exists(): | |
| return { | |
| "ok": False, | |
| "error": ( | |
| f"Python file not found: {path}" | |
| ), | |
| } | |
| if path.suffix.lower() != ".py": | |
| return { | |
| "ok": False, | |
| "error": ( | |
| "Attachment is not a Python file." | |
| ), | |
| } | |
| try: | |
| completed = subprocess.run( | |
| [ | |
| sys.executable, | |
| str(path), | |
| ], | |
| capture_output=True, | |
| text=True, | |
| timeout=timeout, | |
| check=False, | |
| ) | |
| except subprocess.TimeoutExpired: | |
| return { | |
| "ok": False, | |
| "error": ( | |
| "Python execution timed out." | |
| ), | |
| } | |
| stdout = completed.stdout.strip() | |
| stderr = completed.stderr.strip() | |
| output_lines = [ | |
| line.strip() | |
| for line in stdout.splitlines() | |
| if line.strip() | |
| ] | |
| final_output = ( | |
| output_lines[-1] | |
| if output_lines | |
| else "" | |
| ) | |
| if completed.returncode != 0: | |
| return { | |
| "ok": False, | |
| "error": ( | |
| stderr | |
| or "Python execution failed." | |
| ), | |
| "metadata": { | |
| "stdout": stdout, | |
| "stderr": stderr, | |
| "returncode": ( | |
| completed.returncode | |
| ), | |
| }, | |
| } | |
| return { | |
| "ok": bool(final_output), | |
| "source": str(path), | |
| "content": final_output, | |
| "metadata": { | |
| "stdout": stdout, | |
| "stderr": stderr, | |
| "returncode": ( | |
| completed.returncode | |
| ), | |
| }, | |
| } | |
| def _best_url( | |
| state: AgentState, | |
| ) -> str: | |
| for record in reversed( | |
| state.get("tool_results", []) | |
| ): | |
| for item in record.get( | |
| "results", | |
| [], | |
| ): | |
| if ( | |
| isinstance(item, dict) | |
| and item.get("url") | |
| ): | |
| return str(item["url"]) | |
| raise ValueError( | |
| "No URL is available. Add a web_search " | |
| "step before read_webpage." | |
| ) |