refactor: simplify parameter validation logic

This commit is contained in:
Re-bin 2026-02-04 03:50:39 +00:00
parent 579cbfc8fe
commit 9a0f8fcc73

View File

@ -53,62 +53,41 @@ class Tool(ABC):
pass pass
def validate_params(self, params: dict[str, Any]) -> list[str]: def validate_params(self, params: dict[str, Any]) -> list[str]:
""" """Validate tool parameters against JSON schema. Returns error list (empty if valid)."""
Lightweight JSON schema validation for tool parameters.
Returns a list of error strings (empty if valid).
Unknown params are ignored.
"""
schema = self.parameters or {} schema = self.parameters or {}
if schema.get("type", "object") != "object":
raise ValueError(f"Schema must be object type, got {schema.get('type')!r}")
return self._validate(params, {**schema, "type": "object"}, "")
# Default to an object schema if type is missing, and fail fast on unsupported top-level types. def _validate(self, val: Any, schema: dict[str, Any], path: str) -> list[str]:
if "type" not in schema: t, label = schema.get("type"), path or "parameter"
schema = {"type": "object", **schema} if t in self._TYPE_MAP and not isinstance(val, self._TYPE_MAP[t]):
elif schema.get("type") != "object": return [f"{label} should be {t}"]
raise ValueError(
f"Tool parameter schemas must have top-level type 'object'; got {schema.get('type')!r}" errors = []
) if "enum" in schema and val not in schema["enum"]:
return self._validate_schema(params, schema, path="")
def _validate_schema(self, value: Any, schema: dict[str, Any], path: str) -> list[str]:
errors: list[str] = []
expected_type = schema.get("type")
label = path or "parameter"
if expected_type in self._TYPE_MAP and not isinstance(value, self._TYPE_MAP[expected_type]):
return [f"{label} should be {expected_type}"]
if "enum" in schema and value not in schema["enum"]:
errors.append(f"{label} must be one of {schema['enum']}") errors.append(f"{label} must be one of {schema['enum']}")
if t in ("integer", "number"):
if expected_type in ("integer", "number"): if "minimum" in schema and val < schema["minimum"]:
if "minimum" in schema and value < schema["minimum"]:
errors.append(f"{label} must be >= {schema['minimum']}") errors.append(f"{label} must be >= {schema['minimum']}")
if "maximum" in schema and value > schema["maximum"]: if "maximum" in schema and val > schema["maximum"]:
errors.append(f"{label} must be <= {schema['maximum']}") errors.append(f"{label} must be <= {schema['maximum']}")
if t == "string":
if expected_type == "string": if "minLength" in schema and len(val) < schema["minLength"]:
if "minLength" in schema and len(value) < schema["minLength"]:
errors.append(f"{label} must be at least {schema['minLength']} chars") errors.append(f"{label} must be at least {schema['minLength']} chars")
if "maxLength" in schema and len(value) > schema["maxLength"]: if "maxLength" in schema and len(val) > schema["maxLength"]:
errors.append(f"{label} must be at most {schema['maxLength']} chars") errors.append(f"{label} must be at most {schema['maxLength']} chars")
if t == "object":
if expected_type == "object": props = schema.get("properties", {})
properties = schema.get("properties", {}) for k in schema.get("required", []):
for key in schema.get("required", []): if k not in val:
if key not in value: errors.append(f"missing required {path + '.' + k if path else k}")
errors.append(f"missing required {path}.{key}" if path else f"missing required {key}") for k, v in val.items():
for key, item in value.items(): if k in props:
if key in properties: errors.extend(self._validate(v, props[k], path + '.' + k if path else k))
errors.extend(self._validate_schema(item, properties[key], f"{path}.{key}" if path else key)) if t == "array" and "items" in schema:
for i, item in enumerate(val):
if expected_type == "array": errors.extend(self._validate(item, schema["items"], f"{path}[{i}]" if path else f"[{i}]"))
items_schema = schema.get("items")
if items_schema:
for idx, item in enumerate(value):
errors.extend(self._validate_schema(item, items_schema, f"{path}[{idx}]" if path else f"[{idx}]"))
return errors return errors
def to_schema(self) -> dict[str, Any]: def to_schema(self) -> dict[str, Any]: