RUNLOCALAIv38
->Will it run?Best GPUCompareTroubleshootStartLearnPulseModelsHardwareToolsBench
Run check
RUNLOCALAI

Independently operated catalog for local-AI hardware and software. Hand-written verdicts. Source-cited claims. Reproducible commands when we have them.

OP·Fredoline Eruo
DIR
  • Models
  • Hardware
  • Tools
  • Benchmarks
TOOLS
  • Will it run?
  • Compare hardware
  • Cost vs cloud
  • Choose my GPU
  • Prompting kits
  • Quick answers
REF
  • All buyer guides
  • Learn local AI
  • Methodology
  • Glossary
  • Errors KB
  • Trust
EDITOR
  • About
  • Author
  • How we make money
  • Editorial policy
  • Contact
LEGAL
  • Privacy
  • Terms
  • Sitemap
MAIL · MONTHLY DIGEST
Get monthly local AI changes
Monthly recap. No spam.
DISCLOSURE

Some links on this site are affiliate links (Amazon Associates and other first-class retailers). When you buy through them, we earn a small commission at no extra cost to you. Affiliate links do not influence our verdicts — there are cards we rate highly that we don't have affiliate relationships with, and cards that sell well that we refuse to recommend. Read more →

© 2026 runlocalai.coIndependently operated
RUNLOCALAI · v38
  1. >
  2. Home
  3. /Learn
  4. /Courses
  5. /Custom Agent Frameworks
  6. /Ch. 4
Custom Agent Frameworks

04. Tool Registry

Chapter 4 of 24 · 15 min
KEY INSIGHT

The registry is a simple mapping with added schema generation. Its power is in standardization: every tool goes through the same interface, making debugging and testing consistent.

The tool registry is a mapping layer. It connects the string names the LLM uses to actual Python callables, along with the schemas that tell the LLM what each tool expects.

A well-designed registry supports three operations: registration, retrieval by name, and schema generation for LLM input.

from dataclasses import dataclass
from typing import Any, Callable, Awaitable

@dataclass
class Tool:
    name: str
    description: str
    parameters: dict[str, Any]  # JSON Schema compatible
    handler: Callable[..., Awaitable[Any]]

class ToolRegistry:
    def __init__(self):
        self._tools: dict[str, Tool] = {}
    
    def register(
        self,
        name: str,
        description: str,
        parameters: dict[str, Any],
        handler: Callable[..., Awaitable[Any]]
    ) -> None:
        if name in self._tools:
            raise ValueError(f"Tool '{name}' already registered")
        self._tools[name] = Tool(name, description, parameters, handler)
    
    def get(self, name: str) -> Tool:
        if name not in self._tools:
            raise KeyError(f"Tool '{name}' not found. Registered: {list(self._tools.keys())}")
        return self._tools[name]
    
    def schemas(self) -> list[dict[str, Any]]:
        """Generate tool schemas for LLM function calling."""
        return [
            {
                "type": "function",
                "function": {
                    "name": tool.name,
                    "description": tool.description,
                    "parameters": tool.parameters
                }
            }
            for tool in self._tools.values()
        ]

Decorator pattern for registration:

def tool(registry: ToolRegistry, name: str, description: str, parameters: dict[str, Any]):
    def decorator(func: Callable[..., Awaitable[Any]]):
        registry.register(name, description, parameters, func)
        return func
    return decorator

# Usage
registry = ToolRegistry()

@tool(registry, name="get_weather", description="Get current weather for a location", parameters={
    "type": "object",
    "properties": {
        "location": {"type": "string", "description": "City name"}
    },
    "required": ["location"]
})
async def get_weather(location: str) -> str:
    # Implementation
    return f"Sunny, 72°F in {location}"

Failure mode: schema mismatch. If your schema says a parameter is required but the handler has a default, the LLM may pass null and your handler crashes. Keep schemas and function signatures in sync—ideally derive schemas from type hints.

EXERCISE

Define five tools your target agent needs. Write their schemas (name, description, parameters) and the handler signatures. Check for schema-signature mismatches.

← Chapter 3
Agent Loop
Chapter 5 →
Function Calling Integration