[loop-cycle-46] refactor: break up oversized functions in tools.py (#151) (#154)
All checks were successful
Tests / lint (push) Successful in 3s
Tests / test (push) Successful in 1m20s

This commit was merged in pull request #154.
This commit is contained in:
2026-03-15 10:56:33 -04:00
parent 466db7aed2
commit 717dba9816

View File

@@ -472,26 +472,8 @@ def consult_grok(query: str) -> str:
return response return response
def create_full_toolkit(base_dir: str | Path | None = None): def _register_core_tools(toolkit: Toolkit, base_path: Path) -> None:
"""Create a full toolkit with all available tools (for the orchestrator). """Register core execution and file tools."""
Includes: web search, file read/write, shell commands, python execution,
memory search for contextual recall, and Grok consultation.
"""
if not _AGNO_TOOLS_AVAILABLE:
# Return None when tools aren't available (tests)
return None
from timmy.tool_safety import DANGEROUS_TOOLS
toolkit = Toolkit(
name="full",
)
# Set requires_confirmation_tools AFTER construction (avoids agno WARNING
# about tools not yet registered) but BEFORE register() calls (so each
# Function gets requires_confirmation=True). Fixes #79.
toolkit.requires_confirmation_tools = list(DANGEROUS_TOOLS)
# Python execution # Python execution
python_tools = PythonTools() python_tools = PythonTools()
toolkit.register(python_tools.run_python_code, name="python") toolkit.register(python_tools.run_python_code, name="python")
@@ -500,10 +482,7 @@ def create_full_toolkit(base_dir: str | Path | None = None):
shell_tools = ShellTools() shell_tools = ShellTools()
toolkit.register(shell_tools.run_shell_command, name="shell") toolkit.register(shell_tools.run_shell_command, name="shell")
# File operations - use repo_root from settings # File operations
from config import settings
base_path = Path(base_dir) if base_dir else Path(settings.repo_root)
file_tools = FileTools(base_dir=base_path) file_tools = FileTools(base_dir=base_path)
toolkit.register(_make_smart_read_file(file_tools), name="read_file") toolkit.register(_make_smart_read_file(file_tools), name="read_file")
toolkit.register(file_tools.save_file, name="write_file") toolkit.register(file_tools.save_file, name="write_file")
@@ -512,7 +491,9 @@ def create_full_toolkit(base_dir: str | Path | None = None):
# Calculator — exact arithmetic (never let the LLM guess) # Calculator — exact arithmetic (never let the LLM guess)
toolkit.register(calculator, name="calculator") toolkit.register(calculator, name="calculator")
# Grok consultation — premium frontier reasoning (opt-in)
def _register_grok_tool(toolkit: Toolkit) -> None:
"""Register Grok consultation tool if available."""
try: try:
from timmy.backends import grok_available from timmy.backends import grok_available
@@ -523,7 +504,9 @@ def create_full_toolkit(base_dir: str | Path | None = None):
logger.warning("Tool execution failed (Grok registration): %s", exc) logger.warning("Tool execution failed (Grok registration): %s", exc)
logger.debug("Grok tool not available") logger.debug("Grok tool not available")
# Memory search, write, and forget — persistent recall across all channels
def _register_memory_tools(toolkit: Toolkit) -> None:
"""Register memory search, write, and forget tools."""
try: try:
from timmy.semantic_memory import memory_forget, memory_read, memory_search, memory_write from timmy.semantic_memory import memory_forget, memory_read, memory_search, memory_write
@@ -535,7 +518,9 @@ def create_full_toolkit(base_dir: str | Path | None = None):
logger.warning("Tool execution failed (Memory tools registration): %s", exc) logger.warning("Tool execution failed (Memory tools registration): %s", exc)
logger.debug("Memory tools not available") logger.debug("Memory tools not available")
# Agentic loop — background multi-step task execution
def _register_agentic_loop_tool(toolkit: Toolkit) -> None:
"""Register agentic loop tool for background multi-step task execution."""
try: try:
from timmy.agentic_loop import run_agentic_loop from timmy.agentic_loop import run_agentic_loop
@@ -582,7 +567,9 @@ def create_full_toolkit(base_dir: str | Path | None = None):
logger.warning("Tool execution failed (plan_and_execute registration): %s", exc) logger.warning("Tool execution failed (plan_and_execute registration): %s", exc)
logger.debug("plan_and_execute tool not available") logger.debug("plan_and_execute tool not available")
# System introspection - query runtime environment (sovereign self-knowledge)
def _register_introspection_tools(toolkit: Toolkit) -> None:
"""Register system introspection tools for runtime environment queries."""
try: try:
from timmy.tools_intro import ( from timmy.tools_intro import (
check_ollama_health, check_ollama_health,
@@ -599,7 +586,9 @@ def create_full_toolkit(base_dir: str | Path | None = None):
logger.warning("Tool execution failed (Introspection tools registration): %s", exc) logger.warning("Tool execution failed (Introspection tools registration): %s", exc)
logger.debug("Introspection tools not available") logger.debug("Introspection tools not available")
# Inter-agent delegation - dispatch tasks to swarm agents
def _register_delegation_tools(toolkit: Toolkit) -> None:
"""Register inter-agent delegation tools."""
try: try:
from timmy.tools_delegation import delegate_task, delegate_to_kimi, list_swarm_agents from timmy.tools_delegation import delegate_task, delegate_to_kimi, list_swarm_agents
@@ -610,6 +599,34 @@ def create_full_toolkit(base_dir: str | Path | None = None):
logger.warning("Tool execution failed (Delegation tools registration): %s", exc) logger.warning("Tool execution failed (Delegation tools registration): %s", exc)
logger.debug("Delegation tools not available") logger.debug("Delegation tools not available")
def create_full_toolkit(base_dir: str | Path | None = None):
"""Create a full toolkit with all available tools (for the orchestrator).
Includes: web search, file read/write, shell commands, python execution,
memory search for contextual recall, and Grok consultation.
"""
if not _AGNO_TOOLS_AVAILABLE:
# Return None when tools aren't available (tests)
return None
from timmy.tool_safety import DANGEROUS_TOOLS
toolkit = Toolkit(name="full")
# Set requires_confirmation_tools AFTER construction (avoids agno WARNING
# about tools not yet registered) but BEFORE register() calls (so each
# Function gets requires_confirmation=True). Fixes #79.
toolkit.requires_confirmation_tools = list(DANGEROUS_TOOLS)
base_path = Path(base_dir) if base_dir else Path(settings.repo_root)
_register_core_tools(toolkit, base_path)
_register_grok_tool(toolkit)
_register_memory_tools(toolkit)
_register_agentic_loop_tool(toolkit)
_register_introspection_tools(toolkit)
_register_delegation_tools(toolkit)
# Gitea issue management is now provided by the gitea-mcp server # Gitea issue management is now provided by the gitea-mcp server
# (wired in as MCPTools in agent.py, not registered here) # (wired in as MCPTools in agent.py, not registered here)
@@ -719,13 +736,9 @@ get_tools_for_persona = get_tools_for_agent
PERSONA_TOOLKITS = AGENT_TOOLKITS PERSONA_TOOLKITS = AGENT_TOOLKITS
def get_all_available_tools() -> dict[str, dict]: def _core_tool_catalog() -> dict:
"""Get a catalog of all available tools and their descriptions. """Return core file and execution tools catalog entries."""
return {
Returns:
Dict mapping tool categories to their tools and descriptions.
"""
catalog = {
"shell": { "shell": {
"name": "Shell Commands", "name": "Shell Commands",
"description": "Execute shell commands (sandboxed)", "description": "Execute shell commands (sandboxed)",
@@ -751,16 +764,39 @@ def get_all_available_tools() -> dict[str, dict]:
"description": "List files in a directory", "description": "List files in a directory",
"available_in": ["echo", "seer", "forge", "quill", "mace", "helm", "orchestrator"], "available_in": ["echo", "seer", "forge", "quill", "mace", "helm", "orchestrator"],
}, },
}
def _analysis_tool_catalog() -> dict:
"""Return analysis and calculation tools catalog entries."""
return {
"calculator": { "calculator": {
"name": "Calculator", "name": "Calculator",
"description": "Evaluate mathematical expressions with exact results", "description": "Evaluate mathematical expressions with exact results",
"available_in": ["orchestrator"], "available_in": ["orchestrator"],
}, },
}
def _ai_tool_catalog() -> dict:
"""Return AI assistant and frontier reasoning tools catalog entries."""
return {
"consult_grok": { "consult_grok": {
"name": "Consult Grok", "name": "Consult Grok",
"description": "Premium frontier reasoning via xAI Grok (opt-in, Lightning-payable)", "description": "Premium frontier reasoning via xAI Grok (opt-in, Lightning-payable)",
"available_in": ["orchestrator"], "available_in": ["orchestrator"],
}, },
"aider": {
"name": "Aider AI Assistant",
"description": "Local AI coding assistant using Ollama (qwen3.5:latest or deepseek-coder)",
"available_in": ["forge", "orchestrator"],
},
}
def _introspection_tool_catalog() -> dict:
"""Return system introspection tools catalog entries."""
return {
"get_system_info": { "get_system_info": {
"name": "System Info", "name": "System Info",
"description": "Introspect runtime environment - discover model, Python version, config", "description": "Introspect runtime environment - discover model, Python version, config",
@@ -776,11 +812,12 @@ def get_all_available_tools() -> dict[str, dict]:
"description": "Check status of memory tiers (hot memory, vault)", "description": "Check status of memory tiers (hot memory, vault)",
"available_in": ["orchestrator"], "available_in": ["orchestrator"],
}, },
"aider": { }
"name": "Aider AI Assistant",
"description": "Local AI coding assistant using Ollama (qwen3.5:latest or deepseek-coder)",
"available_in": ["forge", "orchestrator"], def _experiment_tool_catalog() -> dict:
}, """Return ML experiment tools catalog entries."""
return {
"prepare_experiment": { "prepare_experiment": {
"name": "Prepare Experiment", "name": "Prepare Experiment",
"description": "Clone autoresearch repo and run data preparation for ML experiments", "description": "Clone autoresearch repo and run data preparation for ML experiments",
@@ -798,6 +835,9 @@ def get_all_available_tools() -> dict[str, dict]:
}, },
} }
def _import_creative_catalogs(catalog: dict) -> None:
"""Import and merge creative tool catalogs from creative module."""
# ── Git tools ───────────────────────────────────────────────────────────── # ── Git tools ─────────────────────────────────────────────────────────────
try: try:
from creative.tools.git_tools import GIT_TOOL_CATALOG from creative.tools.git_tools import GIT_TOOL_CATALOG
@@ -876,4 +916,18 @@ def get_all_available_tools() -> dict[str, dict]:
except ImportError: except ImportError:
pass pass
def get_all_available_tools() -> dict[str, dict]:
"""Get a catalog of all available tools and their descriptions.
Returns:
Dict mapping tool categories to their tools and descriptions.
"""
catalog = {}
catalog.update(_core_tool_catalog())
catalog.update(_analysis_tool_catalog())
catalog.update(_ai_tool_catalog())
catalog.update(_introspection_tool_catalog())
catalog.update(_experiment_tool_catalog())
_import_creative_catalogs(catalog)
return catalog return catalog