Schema validation

The starter registry hands each tool a free-form string. That works for two tools, but it falls apart the moment a tool needs structured arguments: a city, a date range, a threshold. The fix is to require every tool to declare a Pydantic schema. The tools layer parses arguments into the schema before dispatching, and any parse error becomes a clean tool-not-callable response.

layers/tools.py (extended)
python
from pydantic import BaseModel, ValidationError
from typing import Type


class CalculatorArgs(BaseModel):
    expression: str


class GetTimeArgs(BaseModel):
    pass  # no arguments


TOOL_SCHEMAS: Dict[str, Type[BaseModel]] = {
    "calculator": CalculatorArgs,
    "get_time": GetTimeArgs,
}


class ToolsLayer:
    def run_validated(self, tool_name: str, raw_args: dict) -> str:
        schema = TOOL_SCHEMAS.get(tool_name)
        if schema is None:
            raise ValueError(f"unknown tool: {tool_name}")
        try:
            args = schema(**raw_args)
        except ValidationError as e:
            raise ValueError(f"invalid args for {tool_name}: {e.errors()[0]['msg']}")

        fn = self._registry[tool_name]
        return fn(**args.model_dump())

Every tool has a schema. run_validated parses raw args through the schema first, raises a clean error on bad input, and only then dispatches to the handler. The handler can trust its arguments.

Fill in the blanks: Add a weather tool schema

Loading practice…

Quiz: Quiz

Loading practice…