v9.1.1
Menu

Validate a Tool Call Against Its Schema

easyFREETool Use & Function CallingAI AgentsAI Agents 1

Problem Statement

The model does not call your tool - it emits a JSON object claiming to call your tool. Everything between that claim and your code is your responsibility. A validator sitting on the boundary turns a malformed call into a precise, machine-readable error the agent can actually recover from, instead of a stack trace inside your business logic.

Background

A tool schema is a JSON-Schema-shaped object:

{
  "parameters": {
    "type": "object",
    "properties": {
      "city":  {"type": "string"},
      "days":  {"type": "integer"},
      "units": {"type": "string", "enum": ["c", "f"]}
    },
    "required": ["city"]
  }
}

Validation checks four things, in this order per argument: the tool exists, every required parameter is present, no undeclared parameters were passed, and every declared parameter has the right type (and, if an enum is declared, an allowed value).

The subtle one: in Python bool is a subclass of int, so a naive isinstance(True, int) accepts True for an integer parameter. It is not one. A boolean value is valid only for "type": "boolean".

Your Task

Implement:

def validate_tool_call(schemas, call):
  • schemas: dict mapping tool name -> schema dict as above.
  • call: dict {"name": str, "arguments": dict}.

Return {"ok": bool, "errors": list[str]} where errors use these exact formats:

| Situation | Error string | |---|---| | tool name not in schemas | unknown_tool:<name> | | required parameter absent | missing:<param> | | argument not declared in properties | unexpected:<param> | | declared parameter, wrong type | type:<param> | | right type, value not in enum | enum:<param> |

Rules: an unknown tool short-circuits - return that single error and nothing else. Otherwise collect every error, and report at most one error per argument (a type error suppresses the enum check for that argument). Sort the final error list ascending before returning. ok is True only when the list is empty.

Type names map to Python as: string->str, integer->int, number->int or float, boolean->bool, array->list, object->dict. A parameter spec with no "type" accepts anything.

Input/Output Format

Returns a dict with keys ok (bool) and errors (sorted list of strings).

Sample

schemas = {"get_weather": {"parameters": {
    "type": "object",
    "properties": {"city": {"type": "string"}, "days": {"type": "integer"}},
    "required": ["city"]}}}
print(validate_tool_call(schemas, {"name": "get_weather",
                                   "arguments": {"days": True, "tz": "UTC"}}))
# {'ok': False, 'errors': ['missing:city', 'type:days', 'unexpected:tz']}

Example

Input
schemas = {'get_weather': {'parameters': {'type':'object','properties': {'city': {'type':'string'}, 'days': {'type':'integer'}}, 'required': ['city']}}}
print(validate_tool_call(schemas, {'name': 'get_weather', 'arguments': {'days': True, 'tz': 'UTC'}}))
Output
{'ok': False, 'errors': ['missing:city', 'type:days', 'unexpected:tz']}
Reasoning
  • Inputs: schemas declares one tool, get_weather, with two parameters: city (a string, required) and days (an integer, optional). The call names that tool and passes two arguments: days set to True and tz set to 'UTC'.
  • Tool check: get_weather exists, so there is no short circuit and every argument problem gets reported.
  • Required: the required set is {city}\{\text{city}\} and the supplied set is {days,tz}\{\text{days}, \text{tz}\}. Their difference is {city}\{\text{city}\}, giving missing:city.
  • Declared: tz is not among the declared properties, so it earns unexpected:tz and nothing else is judged about it (one error per argument).
  • Type: days is declared as an integer, but True is a boolean. Python counts a boolean as an integer, but here booleans are valid only for a boolean parameter, so this is type:days.
  • Output: the three strings in ascending order compare on their first letters, m < t < u, and since the list is non-empty the result is {'ok': False, 'errors': ['missing:city', 'type:days', 'unexpected:tz']}.
  • Notice that with city present and days equal to 3, only unexpected:tz would remain.

Constraints

  • 1 <= len(schemas) <= 50; each schema has at most 20 properties
  • An unknown tool returns exactly ["unknown_tool:<name>"] and stops
  • At most one error per argument: type: suppresses the enum: check
  • True/False are valid only for "type": "boolean" - never for integer or number
  • int is an acceptable number; float is not an acceptable integer
  • The errors list must be sorted ascending

Learn this in

More from AI Agents 1

solution.py

Test results

Sign in to run your code against the test cases.