Architecture 4 Tools - djvolz/coda-code-assistant GitHub Wiki

Tools Module Architecture

Code References

Overview

The Tools module provides a comprehensive framework for AI-assisted tool execution with safety controls, permissions, and extensibility. It supports both built-in tools and external tools via the Model Context Protocol (MCP). The main interface is defined in coda/tools/base.py with the BaseTool abstract class.

Module Structure

coda/tools/
├── __init__.py           # Module exports and initialization (verified)
├── base.py              # Core interfaces and registry (verified)
├── executor.py          # Tool execution engine (verified)
├── file_tools.py        # File system operations (verified)
├── git_tools.py         # Git repository operations (verified)
├── web_tools.py         # Web fetching and search (verified)
├── shell_tools.py       # Shell command execution (verified)
├── permissions.py       # Permission system (verified)
├── mcp_manager.py       # MCP server management (verified)
├── mcp_server.py        # MCP protocol server (verified)
├── mcp_stdio_client.py  # MCP stdio client (verified)
└── session_storage.py   # Tool invocation tracking (verified)

Key Components

Component 1: Tool Base Classes

Location: coda/tools/base.py

Purpose: Defines the abstract interface for all tools

Key Classes:

  • BaseTool: Abstract base class for tools
  • ToolSchema: Tool metadata and parameters
  • ToolParameter: Parameter definitions with validation
  • ToolRegistry: Centralized tool management

Component 2: Tool Executor

Location: coda/tools/executor.py

Purpose: Orchestrates tool execution with safety checks

Key Methods:

  • execute_tool_call(): Main execution pipeline
  • get_available_tools(): Returns tool schemas
  • format_tool_result(): Formats results for display

Component 3: Permission System

Location: coda/tools/permissions.py

Purpose: Fine-grained access control for tool execution

Key Components:

  • PermissionLevel enum: Permission tiers
  • PermissionRule: Rule definitions
  • PermissionManager: Rule evaluation engine

Component 4: MCP Integration

Location: coda/tools/mcp_manager.py

Purpose: Integrates external tools via Model Context Protocol

Key Classes:

  • MCPManager: Server lifecycle management
  • ExternalMCPTool: Wrapper for MCP tools

Implementation Details

Design Patterns Used

Abstract Factory Pattern

Implementation: coda/tools/base.py

class BaseTool(ABC):
    """Abstract base class for all tools."""
    
    @abstractmethod
    def get_schema(self) -> ToolSchema:
        """Return the tool's schema."""
        pass
    
    @abstractmethod
    async def execute(self, arguments: dict[str, Any]) -> ToolResult:
        """Execute the tool with given arguments."""
        pass

Registry Pattern

Implementation: coda/tools/base.py

class ToolRegistry:
    """Centralized registry for all available tools."""
    
    def __init__(self):
        self._tools: dict[str, BaseTool] = {}
        self._categories: dict[ToolCategory, list[str]] = {}
    
    def register(self, tool: Type[BaseTool], category: Optional[ToolCategory] = None):
        """Register a tool class."""
        tool_instance = tool()
        self._tools[tool_name] = tool_instance

Strategy Pattern

Implementation: Different tool implementations with common interface

Each tool type implements the BaseTool interface differently:

  • File tools for file operations
  • Git tools for version control
  • Web tools for internet access
  • Shell tools for command execution

Tool Execution Flow

sequenceDiagram
    participant AI
    participant Executor as ToolExecutor
    participant Permissions as PermissionManager
    participant Registry as ToolRegistry
    participant Tool as BaseTool
    participant Storage as SessionStorage
    
    AI->>Executor: execute_tool_call(ToolCall)
    Executor->>Registry: get_tool(tool_name)
    Registry->>Executor: Return tool instance
    
    alt Dangerous tool
        Executor->>Permissions: check_permission(tool, user)
        Permissions->>Permissions: Evaluate rules
        alt Permission denied
            Permissions->>Executor: Denied
            Executor->>AI: Return error
        else Permission granted
            Permissions->>Executor: Allowed
        end
    end
    
    Executor->>Tool: validate_arguments(args)
    Tool->>Executor: Validation result
    
    alt Valid arguments
        Executor->>Tool: execute(arguments)
        Tool->>Tool: Perform operation
        Tool->>Executor: Return ToolResult
        Executor->>Storage: log_invocation()
        Executor->>AI: Return formatted result
    else Invalid arguments
        Executor->>AI: Return validation error
    end
Loading

Built-in Tools

File Tools (file_tools.py)

  • ReadFileTool: Read file contents with encoding support
  • WriteFileTool: Write files with backup creation
  • EditFileTool: Advanced file editing operations
  • ListDirectoryTool: Directory listing with patterns

Git Tools (git_tools.py)

  • GitStatusTool: Repository status information
  • GitLogTool: Commit history with filtering
  • GitDiffTool: View diffs between commits/branches
  • GitBranchTool: Branch management operations

Web Tools (web_tools.py)

  • FetchUrlTool: Fetch and convert web content
  • SearchWebTool: Web search via DuckDuckGo

Shell Tools (shell_tools.py)

  • ShellExecuteTool: Execute shell commands with safety controls
    • Dangerous patterns blocklist
    • Completely blocked patterns
    • Safe command allowlist

Permission System

Permission Levels (permissions.py):

class PermissionLevel(str, Enum):
    DENIED = "denied"          # No access
    READ_ONLY = "read_only"    # Read operations only
    LIMITED = "limited"        # Limited write operations
    STANDARD = "standard"      # Standard operations
    ELEVATED = "elevated"      # Elevated privileges
    ADMIN = "admin"           # Full access

Permission Rules support:

  • Tool-specific permissions
  • Category-based permissions
  • Time-based restrictions
  • Usage rate limiting
  • Parameter value restrictions
  • User approval requirements

MCP Integration

MCP Manager (mcp_manager.py):

class MCPManager:
    """Manages MCP server lifecycle and tool discovery."""
    
    async def start_server(self, server_config: dict):
        """Start an MCP server subprocess."""
        # Launches external MCP server
        
    async def discover_tools(self):
        """Discover tools from all active servers."""
        # Queries servers for available tools

External Tool Wrapper (mcp_manager.py):

class ExternalMCPTool(BaseTool):
    """Wrapper for external MCP tools."""
    
    async def execute(self, arguments: dict[str, Any]):
        """Execute tool via MCP protocol."""
        # Sends request to external server

API Reference

Public Classes

BaseTool

Location: coda/tools/base.py

Purpose: Abstract base class for all tools

Methods:

  • get_schema() -> ToolSchema: Return tool metadata
  • execute(arguments: dict) -> ToolResult: Execute tool
  • validate_arguments(arguments: dict) -> str | None: Validate inputs

ToolExecutor

Location: coda/tools/executor.py

Purpose: Manages tool execution with safety controls

Methods:

  • execute_tool_call(tool_call: ToolCall) -> ToolResult: Execute tool
  • get_available_tools() -> list[ToolSchema]: List tools

PermissionManager

Location: coda/tools/permissions.py

Purpose: Evaluates permission rules for tool access

Methods:

  • check_tool_permission(tool_name, user_context) -> PermissionResult
  • add_rule(rule: PermissionRule) -> None
  • evaluate_rules(tool_name, context) -> PermissionLevel

Configuration

Config Files:

  • Tool permissions: ~/.config/coda/permissions.yaml
  • MCP servers: ~/.config/coda/mcp.json

MCP Server Configuration Example:

{
  "servers": [
    {
      "name": "example-server",
      "command": "node",
      "args": ["path/to/server.js"],
      "env": {"API_KEY": "..."}
    }
  ]
}

Dependencies

Internal Dependencies

  • coda.configuration: Config management
  • coda.agents: Tool integration with agents
  • coda.session: Session tracking integration

External Dependencies

  • httpx>=0.24.0: HTTP client for web tools
  • beautifulsoup4>=4.12.0: HTML parsing
  • html2text>=2020.1.16: HTML to markdown conversion
  • GitPython>=3.1.0: Git operations

Testing

Test Coverage

  • Unit tests: tests/test_tools.py
  • Tool-specific tests: tests/tools/test_*.py
  • Integration tests: tests/tools/test_tools_with_mock_provider.py

Key Test Cases

  1. Tool Registry: Registration and discovery
  2. Permission System: Rule evaluation
  3. MCP Integration: Server communication

Error Handling

Tool Execution Errors

try:
    result = await tool.execute(tool_call.arguments)
except Exception as e:
    logger.error(f"Tool execution failed: {e}")
    return ToolResult(
        tool_call_id=tool_call.id,
        content=f"Error: {str(e)}"
    )

Validation Errors

Tools validate arguments before execution and return descriptive errors for invalid inputs.

Performance Considerations

  1. Async Execution: All tools use async/await for non-blocking operations
  2. Connection Pooling: HTTP clients reused for web tools
  3. Subprocess Management: MCP servers managed with process pools
  4. Result Caching: Some tools cache results (e.g., git status)

Security Considerations

  1. Command Injection Prevention: Shell tools use shlex for safe parsing
  2. Path Traversal Protection: File tools validate paths
  3. Rate Limiting: Permission system supports usage limits
  4. Approval Workflows: Dangerous operations require user consent
  5. Audit Trail: All invocations logged to session storage

Examples

Basic Tool Usage

from coda.tools import tool_registry

# Get a tool
read_tool = tool_registry.get_tool("read_file")

# Execute it
result = await read_tool.execute({
    "path": "/path/to/file.txt"
})

Creating a Custom Tool

# Example custom tool
from coda.tools.base import BaseTool, ToolSchema, ToolParameter

class CustomTool(BaseTool):
    def get_schema(self) -> ToolSchema:
        return ToolSchema(
            name="custom_tool",
            description="My custom tool",
            parameters={
                "input": ToolParameter(
                    type="string",
                    description="Input value"
                )
            }
        )
    
    async def execute(self, arguments: dict) -> ToolResult:
        # Tool implementation
        return ToolResult(success=True, output="Done!")

Integration Points

With Other Modules

  1. Agent Module: Tools exposed via MCPToolAdapter
  2. CLI Module: Tool chat integration in tool_chat.py
  3. Session Module: Tool invocations tracked in database

Extension Points

  1. New Tools: Extend BaseTool and register
  2. Custom Permissions: Add rules to permission manager
  3. MCP Servers: Add external tool servers

Known Limitations

  1. Shell Safety: Some commands always blocked for safety
  2. Web Scraping: Limited by site structure and anti-bot measures
  3. File Size: Large file operations may timeout

References

Related Documentation

Source Files

All files referenced in this document:

⚠️ **GitHub.com Fallback** ⚠️