ADR-004: Tool System Architecture¶
Metadata¶
- Status: Accepted
- Date: 2025-02-26
- Decision Makers: Vijaykumar Singh
- Related ADRs: ADR-001 (Agent Orchestration)
Context¶
Victor needs a tool system that:
- Provides 33+ built-in tools across 9 categories
- Enables easy tool discovery and selection
- Supports progressive disclosure (cost-based tiers)
- Allows custom tool creation
- Ensures tool safety through validation
The challenge is:
- Organizing tools across multiple categories
- Balancing power with safety
- Enabling extensibility without complexity
- Optimizing for performance
Decision¶
We will implement a Three-Phase Tool System with metadata-driven discovery and progressive disclosure.
Architecture¶
Tool Category Registry
↓
Tool Metadata Registry (Decorator-driven)
↓
Progressive Tools Registry (Cost tiers)
↓
Shared Tool Registry (Singleton instances)
Tool Categories¶
- CORE: Essential tools (read, write, edit)
- FILESYSTEM: File operations (ls, grep, find)
- GIT: Version control (git_status, git_commit)
- SEARCH: Code search (code_search, overview)
- WEB: Web access (web_search, web_fetch)
- DATABASE: Database operations (query, execute)
- DOCKER: Container management (docker_run, docker_exec)
- TESTING: Test execution (pytest, test)
- REFACTORING: Code refactoring (rename, extract)
Cost Tiers (Progressive Disclosure)¶
- LOW: Safe, fast, free tools
- MEDIUM: Moderate cost, some restrictions
- HIGH: Expensive or dangerous tools
- PROHIBITED: Blocked by safety rules
Tool Metadata¶
@dataclass
class ToolMetadata:
name: str
category: ToolCategory
description: str
cost_tier: CostTier
idempotent: bool
keywords: List[str]
use_cases: List[str]
schema: Dict[str, Any]
Rationale¶
Why Three Registries?¶
Tool Category Registry:
- High-level organization
- Category-based tool selection
- Preset configurations (minimal, default, full)
Tool Metadata Registry:
- Decorator-driven registration
- Rich metadata for discovery
- Semantic search capabilities
Progressive Tools Registry:
- Cost-based tool disclosure
- Safety controls
- Resource management
Why Progressive Disclosure?¶
Benefits:
- Safer for new users
- Cost control
- Gradual complexity
- Better UX
Implementation:
- Start with LOW tier tools
- Unlock higher tiers as needed
- Explicit opt-in for dangerous tools
Why Metadata-Driven?¶
Benefits:
- Self-documenting tools
- Searchable by keywords
- Auto-generated documentation
- Type-safe validation
Consequences¶
Positive¶
- Discoverable: Rich metadata enables search and discovery
- Safe: Progressive disclosure prevents accidents
- Extensible: Easy to add custom tools
- Organized: Clear categorization
- Observable: Tool execution tracked
Negative¶
- Metadata Overhead: Need to maintain tool metadata
- Discovery Complexity: Multiple registries can confuse
- Registration: Tools must be explicitly registered
Neutral¶
- Performance: Metadata lookup is fast (O(1))
- API: Tool registration is simple decorator
- Compatibility: Existing tools continue to work
Implementation¶
Phase 1: Core Tool System (Completed)¶
- ✅ Base tool abstract class
- ✅ Tool metadata protocol
- ✅ Category registry
- ✅ 33+ built-in tools
- ✅ Progressive disclosure
Phase 2: Enhanced Features (In Progress)¶
- 🔄 Tool validation
- 🔄 Tool aliases
- 🔄 Tool composition
- 🔄 Tool permissions
Phase 3: Advanced Features (Planned)¶
- ⏳ Tool marketplace
- ⏳ Tool versioning
- ⏳ Tool dependencies
- ⏳ Tool sandboxing
Code Example¶
Creating a Tool¶
from victor.tools.base import BaseTool, ToolMetadata, ToolCategory, CostTier
class MyCustomTool(BaseTool):
"""A custom tool example."""
@property
def metadata(self) -> ToolMetadata:
return ToolMetadata(
name="my_tool",
category=ToolCategory.CUSTOM,
description="Description of my tool",
cost_tier=CostTier.LOW,
idempotent=True,
keywords=["custom", "example"],
use_cases=["Use case 1", "Use case 2"],
schema={
"type": "object",
"properties": {
"input": {"type": "string"}
}
}
)
async def execute(self, **kwargs) -> str:
"""Execute the tool."""
return f"Processed: {kwargs.get('input')}"
Using Tool Presets¶
from victor import Agent
# Minimal tools (safe only)
agent = Agent.create(tools="minimal")
# Default tools (safe filesystem)
agent = Agent.create(tools="default")
# Full tools (all available)
agent = Agent.create(tools="full")
# Custom selection
agent = Agent.create(tools=["read", "write", "grep"])
Progressive Disclosure¶
# Start with LOW tier tools
agent = Agent.create(
tools=["read", "write"],
max_cost_tier=CostTier.LOW
)
# User requests more capabilities
agent.add_tools(["shell", "docker"])
Alternatives Considered¶
1. Flat Tool List¶
Description: Single list of all tools, no organization
Rejected Because:
- Hard to discover relevant tools
- No progressive disclosure
- Safety concerns
2. Plugin System¶
Description: Dynamic tool loading from plugins
Rejected Because:
- More complex
- Security concerns
- Slower discovery
3. No Metadata¶
Description: Tools registered without metadata
Rejected Because:
- Hard to discover
- No searchability
- Poor documentation
References¶
Revision History¶
| Date | Version | Changes | Author |
|---|---|---|---|
| 2025-02-26 | 1.0 | Initial ADR | Vijaykumar Singh |