| | from __future__ import annotations |
| |
|
| | import os |
| | import sys |
| | import ast |
| | from io import StringIO |
| | from typing import Annotated |
| | import importlib.metadata |
| |
|
| | import gradio as gr |
| | from ._docstrings import autodoc |
| | from .File_System import ROOT_DIR, File_System |
| | from .Web_Fetch import Web_Fetch |
| | from .Web_Search import Web_Search |
| | from .Memory_Manager import Memory_Manager |
| | from .Generate_Speech import Generate_Speech, List_Kokoro_Voices |
| | from .Generate_Image import Generate_Image |
| | from .Generate_Video import Generate_Video |
| | from .Deep_Research import Deep_Research |
| | from .Obsidian_Vault import Obsidian_Vault |
| | from .Shell_Command import Shell_Command |
| | from .Code_Interpreter import Code_Interpreter |
| |
|
| | from app import _log_call_end, _log_call_start, _truncate_for_log |
| |
|
| | def search_packages(query: str = "") -> str: |
| | """Search for installed Python packages by name. If query is empty, lists all.""" |
| | packages = [] |
| | query = query.lower() |
| | for dist in importlib.metadata.distributions(): |
| | name = dist.metadata['Name'] |
| | if query in name.lower(): |
| | packages.append(f"{name} ({dist.version})") |
| | packages.sort() |
| | if not packages: |
| | return f"No packages found matching '{query}'." |
| | return "\n".join(packages) |
| |
|
| | def _get_tools_map(): |
| | return { |
| | "Web_Fetch": Web_Fetch, |
| | "Web_Search": Web_Search, |
| | "Memory_Manager": Memory_Manager, |
| | "Generate_Speech": Generate_Speech, |
| | "List_Kokoro_Voices": List_Kokoro_Voices, |
| | "Generate_Image": Generate_Image, |
| | "Generate_Video": Generate_Video, |
| | "Deep_Research": Deep_Research, |
| | "File_System": File_System, |
| | "Obsidian_Vault": Obsidian_Vault, |
| | "Shell_Command": Shell_Command, |
| | "Code_Interpreter": Code_Interpreter, |
| | } |
| |
|
| | def list_tools() -> list[str]: |
| | """List all available tools in the Code Interpreter environment.""" |
| | return list(_get_tools_map().keys()) |
| |
|
| | def search_tools(query: str) -> str: |
| | """Search for tools by name or description. Returns usage info for matches.""" |
| | query = query.lower() |
| | matches = [] |
| | tools = _get_tools_map() |
| | for name, func in tools.items(): |
| | doc = (func.__doc__ or "").lower() |
| | if query in name.lower() or query in doc: |
| | matches.append((name, func)) |
| | |
| | if not matches: |
| | return f"No tools found matching '{query}'." |
| | |
| | output = [] |
| | for name, func in matches: |
| | output.append(f"--- {name} ---") |
| | output.append(func.__doc__ or "No documentation available.") |
| | output.append("") |
| | return "\n".join(output) |
| |
|
| | def usage(tool_name: str) -> str: |
| | """Get detailed usage information for a specific tool.""" |
| | tools = _get_tools_map() |
| | if tool_name not in tools: |
| | return f"Tool '{tool_name}' not found. Available tools: {', '.join(tools.keys())}" |
| | func = tools[tool_name] |
| | return f"--- {tool_name} ---\n{func.__doc__ or 'No documentation available.'}" |
| |
|
| | |
| | TOOL_SUMMARY = ( |
| | "Executes Python code as the unified interface for the entire tools ecosystem. " |
| | "All tool interactions must happen through this code-execution gateway. " |
| | "Use Agent Terminal repeatedly whenever you need to chain or combine tool operations. " |
| | "Available tools: `Web_Fetch`, `Web_Search`, `Code_Interpreter`, `Shell_Command`, `File_System`, `Obsidian_Vault`, `Memory_Manager`, `Generate_Speech`, `Generate_Image`, `Generate_Video`, `Deep_Research`." |
| | ) |
| |
|
| |
|
| |
|
| | @autodoc( |
| | summary=TOOL_SUMMARY, |
| | ) |
| | def Agent_Terminal(code: Annotated[str, ( |
| | "Python source code to run; stdout is captured and returned. " |
| | "Execute these commands: " |
| | "`search_tools('query')` to search for tools by name or capability; " |
| | "`list_tools()` to list all available tools; " |
| | "`usage('ToolName')` to inspect a tool’s expected input parameters; " |
| | "`search_packages('query')` to search for installed Python libraries." |
| | )]) -> str: |
| | _log_call_start("Agent_Terminal", code=_truncate_for_log(code or "", 300)) |
| | if code is None: |
| | result = "No code provided." |
| | _log_call_end("Agent_Terminal", result) |
| | return result |
| | old_stdout = sys.stdout |
| | old_cwd = os.getcwd() |
| | redirected_output = sys.stdout = StringIO() |
| | |
| | |
| | tools_env = { |
| | "Web_Fetch": Web_Fetch, |
| | "Web_Search": Web_Search, |
| | "Memory_Manager": Memory_Manager, |
| | "Generate_Speech": Generate_Speech, |
| | "List_Kokoro_Voices": List_Kokoro_Voices, |
| | "Generate_Image": Generate_Image, |
| | "Generate_Video": Generate_Video, |
| | "Deep_Research": Deep_Research, |
| | "File_System": File_System, |
| | "Obsidian_Vault": Obsidian_Vault, |
| | "Shell_Command": Shell_Command, |
| | "Code_Interpreter": Code_Interpreter, |
| | "list_tools": list_tools, |
| | "search_tools": search_tools, |
| | "usage": usage, |
| | "search_packages": search_packages, |
| | "print": print, |
| | "__builtins__": __builtins__, |
| | } |
| | |
| | try: |
| | os.chdir(ROOT_DIR) |
| | |
| | |
| | tree = ast.parse(code) |
| | if tree.body and isinstance(tree.body[-1], ast.Expr): |
| | last_node = tree.body.pop() |
| | |
| | |
| | if tree.body: |
| | exec(compile(tree, filename="<string>", mode="exec"), tools_env) |
| | |
| | |
| | expr = compile(ast.Expression(last_node.value), filename="<string>", mode="eval") |
| | result_val = eval(expr, tools_env) |
| | if result_val is not None: |
| | print(result_val) |
| | else: |
| | exec(code, tools_env) |
| | |
| | result = redirected_output.getvalue() |
| | except Exception as exc: |
| | result = str(exc) |
| | finally: |
| | sys.stdout = old_stdout |
| | try: |
| | os.chdir(old_cwd) |
| | except Exception: |
| | pass |
| | _log_call_end("Agent_Terminal", _truncate_for_log(result)) |
| | return result |
| |
|
| |
|
| | def build_interface() -> gr.Interface: |
| | return gr.Interface( |
| | fn=Agent_Terminal, |
| | inputs=gr.Code(label="Python Code", language="python"), |
| | outputs=gr.Textbox(label="Output", lines=5, max_lines=20), |
| | title="Agent Terminal", |
| | description="<div style=\"text-align:center\">Interact with all other tools via a Python API. Reduces token usage by 90%.</div>", |
| | api_description=TOOL_SUMMARY, |
| | flagging_mode="never", |
| | ) |
| |
|
| |
|
| | __all__ = ["Agent_Terminal", "build_interface"] |
| |
|