Skip to content

Architecture 2 Agents

Danny Volz edited this page Jul 8, 2025 · 3 revisions

Agents Module Architecture

Code References

  • Primary implementation: coda/agents/agent.py
  • Tool decorator: coda/agents/decorators.py
  • Function tools: coda/agents/function_tool.py
  • MCP adapter: coda/agents/tool_adapter.py
  • Built-in tools: coda/agents/builtin_tools.py
  • Type definitions: coda/agents/types.py
  • Tests: tests/test_agent.py, tests/test_tool_calling.py

Overview

The Agents module provides an autonomous AI agent framework with tool-calling capabilities. It allows AI models to execute functions and interact with external systems through a unified interface. The main entry point is the Agent class in coda/agents/agent.py:21-728.

Module Structure

coda/agents/
├── __init__.py          # Module exports (verified)
├── agent.py             # Core Agent implementation (verified)
├── decorators.py        # @tool decorator (verified)
├── function_tool.py     # FunctionTool wrapper class (verified)
├── tool_adapter.py      # MCP tool integration (verified)
├── builtin_tools.py     # Pre-built tool functions (verified)
└── types.py            # Type definitions (verified)

Key Components

Component 1: Agent Core

Location: coda/agents/agent.py:21-728

Purpose: Main agent class that orchestrates AI conversations with tool execution

Key Methods:

  • __init__() (lines 29-88): Initializes agent with provider, model, and tools
  • run_async() (lines 104-305): Executes agent with tool calling support
  • run_async_streaming() (lines 307-538): Streaming execution with real-time output
  • _handle_tool_calls() (lines 595-665): Orchestrates tool execution

Component 2: Tool Decorator

Location: coda/agents/decorators.py:7-48

Purpose: Decorator that marks functions as agent-callable tools

Implementation:

def tool(func=None, *, name=None, description=None):  # line 7
    """Decorator to mark a function as a tool."""  # line 8
    def decorator(f):  # line 17
        f._is_tool = True  # line 24
        f._tool_name = name or f.__name__  # line 25
        f._tool_description = description or f.__doc__ or ""  # line 26

Component 3: FunctionTool

Location: coda/agents/function_tool.py:11-143

Purpose: Wrapper that converts Python functions into tool specifications

Key Methods:

  • from_callable() (lines 26-53): Factory method to create from decorated functions
  • execute() (lines 55-74): Executes the wrapped function with arguments
  • _build_parameters() (lines 89-132): Generates JSON Schema from function signature

Component 4: MCP Tool Adapter

Location: coda/agents/tool_adapter.py:15-95

Purpose: Adapts MCP (Model Context Protocol) tools for use with agents

Key Methods:

  • convert_mcp_tool() (lines 15-51): Converts MCP tool to FunctionTool
  • get_all_tools() (lines 83-94): Retrieves all registered MCP tools

Implementation Details

Design Patterns Used

Decorator Pattern

Implementation: coda/agents/decorators.py:7-48

The @tool decorator adds metadata to functions:

@tool(description="Read contents of a file")  # line example from builtin_tools.py:18
def read_file(path: str) -> str:
    """Read and return the contents of a file."""
    with open(path, 'r') as f:
        return f.read()

Adapter Pattern

Implementation: coda/agents/tool_adapter.py:15-95

Adapts MCP tools to the agent's FunctionTool interface:

def convert_mcp_tool(self, mcp_tool: Type[BaseTool]) -> FunctionTool:  # line 15
    """Convert an MCP tool to a FunctionTool."""
    # Creates wrapper function that calls MCP tool
    async def tool_wrapper(**kwargs):  # line 29
        return await tool_instance.execute(**kwargs)  # line 34

Factory Pattern

Implementation: coda/agents/function_tool.py:26-53

@classmethod
def from_callable(cls, func: Callable) -> "FunctionTool":  # line 26
    """Create a FunctionTool from a callable."""
    if not hasattr(func, "_is_tool"):  # line 31
        raise ValueError(f"Function {func.__name__} is not decorated with @tool")

Data Flow

sequenceDiagram
    participant User
    participant Agent
    participant Provider
    participant FunctionTool
    participant Tool Function
    
    User->>Agent: run_async(messages)
    Agent->>Provider: Send messages with tools
    Provider->>Provider: Generate response
    
    alt Tool calls requested
        Provider->>Agent: Response with tool_calls
        loop For each tool call
            Agent->>Agent: Create RequiredAction
            Agent->>FunctionTool: execute(arguments)
            FunctionTool->>Tool Function: Call with args
            Tool Function->>FunctionTool: Return result
            FunctionTool->>Agent: Return PerformedAction
        end
        Agent->>Agent: Add tool results to messages
        Agent->>Provider: Continue with results
    end
    
    Provider->>Agent: Final response
    Agent->>User: Return RunResponse
Loading

Class Hierarchy

classDiagram
    BaseModel <|-- FunctionTool
    BaseModel <|-- RequiredAction
    BaseModel <|-- PerformedAction
    BaseModel <|-- RunResponse
    
    class Agent {
        -provider: BaseProvider
        -model: str
        -tools: List[FunctionTool]
        +run_async(messages)
        +run_async_streaming(messages)
        -_handle_tool_calls(tool_calls)
    }
    
    class FunctionTool {
        +name: str
        +description: str
        +parameters: dict
        +callable: Callable
        +from_callable(func)
        +execute(arguments)
    }
    
    class MCPToolAdapter {
        +convert_mcp_tool(mcp_tool)
        +get_all_tools()
    }
    
    note for Agent "Defined in agent.py:21-728"
    note for FunctionTool "Defined in function_tool.py:11-143"
Loading

API Reference

Public Functions

@tool decorator

Location: coda/agents/decorators.py:7

Purpose: Marks a function as an agent-callable tool

Usage:

@tool  # Simple usage
def my_tool(): ...

@tool(name="custom", description="Custom tool")  # With metadata
def another_tool(): ...

Public Classes

Agent

Location: coda/agents/agent.py:21-728

Purpose: Autonomous AI agent with tool-calling capabilities

Constructor:

def __init__(
    self,
    provider: BaseProvider,
    model: str,
    instructions: str = "",
    tools: List[Union[Callable, FunctionTool]] = None,
    name: str = None
)  # lines 29-44

Key Methods:

  • run_async(messages, instructions): Async execution (line 104)
  • run_async_streaming(messages, instructions): Streaming execution (line 307)
  • run(messages, instructions): Sync wrapper (line 582)
  • as_tool(): Convert agent to tool (line 702)

FunctionTool

Location: coda/agents/function_tool.py:11-143

Purpose: Wrapper for Python functions with tool metadata

Fields:

  • name (str): Tool name (line 13)
  • description (str): Tool description (line 14)
  • parameters (dict): JSON Schema parameters (line 15)
  • callable (Callable): Wrapped function (line 16)

Configuration

Tools are configured through:

  1. Decorator parameters: @tool(name="...", description="...")
  2. Function docstrings: Used as default descriptions
  3. Type hints: Used to generate parameter schemas

Dependencies

Internal Dependencies

  • coda.providers.base: Provider interface (agent.py:9)
  • coda.tools.base: Tool registry for MCP tools (tool_adapter.py:8)
  • coda.tools.executor: Tool execution permissions (agent.py:638)

External Dependencies

  • pydantic>=2.0: Data validation and models
  • rich>=13.7.0: Console output formatting
  • typing_extensions: Enhanced typing support

Testing

Test Coverage

  • Unit tests: tests/test_agent.py
  • Tool calling tests: tests/test_tool_calling.py
  • Integration tests: Various provider-specific tests

Key Test Cases

  1. Basic Agent Execution (test_agent.py:23-45): Tests agent without tools
  2. Tool Calling (test_tool_calling.py:34-89): Tests tool execution flow
  3. Streaming Support (test_agent.py:156-203): Tests streaming responses

Error Handling

Exception Handling

Tool execution errors are captured and returned to the model:

# From agent.py:649-656
try:
    result = tool.execute(filtered_args)
except Exception as e:
    logger.error(f"Tool execution error: {e}")
    result = f"Error: {str(e)}"

Loop Detection

Implementation: agent.py:540-580

Prevents infinite tool-calling loops by tracking call patterns and breaking after repeated sequences.

Performance Considerations

  1. Async Execution: All operations are async-first (agent.py:104)
  2. Streaming Support: Reduces time-to-first-token (agent.py:307)
  3. Tool Map Caching: O(1) tool lookup (agent.py:85-87)
  4. Lazy Tool Processing: Tools converted only when needed

Security Considerations

  1. Tool Permissions: Integrated with permission system (agent.py:638)
  2. Argument Filtering: Only declared parameters passed to tools (agent.py:635-640)
  3. Error Isolation: Tool errors don't crash agent (agent.py:649-656)

Examples

Basic Usage

# From tests/test_agent.py:35
from coda.agents import Agent, tool

@tool
def get_weather(location: str) -> str:
    """Get weather for a location."""
    return f"Sunny in {location}"

agent = Agent(
    provider=provider,
    model="gpt-4",
    tools=[get_weather]
)

response = await agent.run_async([
    {"role": "user", "content": "What's the weather in Paris?"}
])

Advanced Usage

# From builtin_tools.py:144-166
@tool(description="Fetch data from a URL asynchronously")
async def fetch_data(url: str) -> str:
    """Fetch and return data from a URL."""
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

Integration Points

With Other Modules

  1. Provider Module: Uses provider for AI completions (agent.py:125)
  2. Tools Module: Integrates MCP tools via adapter (tool_adapter.py:83)
  3. CLI Module: Used in agent_chat.py for interactive sessions

Extension Points

  1. Custom Tools: Create with @tool decorator
  2. Tool Adapters: Implement adapters for other tool protocols
  3. Agent Subclassing: Extend Agent for specialized behavior

Known Limitations

  1. Tool Discovery: Tools must be explicitly passed to agent (see agent.py:73)
  2. Parameter Types: Complex types may not serialize correctly (see function_tool.py:127)

Verification Checklist

  • All file paths verified to exist
  • All line numbers checked for accuracy
  • All class/function names validated
  • Code snippets copied from source
  • Diagrams match actual code flow
  • Examples tested from test files
  • Cross-references verified
  • Type definitions accurate

References

Related Documentation

Source Files

All files referenced in this document:

  • coda/agents/agent.py
  • coda/agents/decorators.py
  • coda/agents/function_tool.py
  • coda/agents/tool_adapter.py
  • coda/agents/builtin_tools.py
  • coda/agents/types.py
  • tests/test_agent.py
  • tests/test_tool_calling.py

Clone this wiki locally