From e31be05f8278b038cdf698b368d6da9f7f3c0c2e Mon Sep 17 00:00:00 2001 From: Razvan Radulescu <43811028+h3xxit@users.noreply.github.com> Date: Wed, 24 Jun 2026 21:47:50 +0200 Subject: [PATCH] feat(core): add explicit examples field to JsonSchema JsonSchema previously accepted `examples` only via `extra="allow"`, leaving it untyped, undocumented, and invisible to type checkers. Declare it as Optional[List[JsonType]] so the JSON Schema `examples` keyword is a first-class, validated field. Supports PR #88 (OpenAPI converter examples parsing), which currently relies on the extra-field fallback. Co-Authored-By: Claude Opus 4.8 (1M context) --- core/src/utcp/data/tool.py | 2 ++ core/tests/data/__init__.py | 0 core/tests/data/test_tool_schema.py | 38 +++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 core/tests/data/__init__.py create mode 100644 core/tests/data/test_tool_schema.py diff --git a/core/src/utcp/data/tool.py b/core/src/utcp/data/tool.py index effdd5c..73ab5b4 100644 --- a/core/src/utcp/data/tool.py +++ b/core/src/utcp/data/tool.py @@ -38,6 +38,7 @@ class JsonSchema(BaseModel): default: Optional schema default value. format: Optional schema format. additionalProperties: Optional schema additional properties. + examples: Optional list of example values for the schema. """ schema_: Optional[str] = Field(None, alias="$schema") id_: Optional[str] = Field(None, alias="$id") @@ -50,6 +51,7 @@ class JsonSchema(BaseModel): enum: Optional[List[JsonType]] = None const: Optional[JsonType] = None default: Optional[JsonType] = None + examples: Optional[List[JsonType]] = None format: Optional[str] = None additionalProperties: Optional[Union[bool, "JsonSchema"]] = None pattern: Optional[str] = None diff --git a/core/tests/data/__init__.py b/core/tests/data/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/tests/data/test_tool_schema.py b/core/tests/data/test_tool_schema.py new file mode 100644 index 0000000..ab9e5fe --- /dev/null +++ b/core/tests/data/test_tool_schema.py @@ -0,0 +1,38 @@ +"""Tests for the JsonSchema model, including the `examples` field.""" + +from utcp.data.tool import JsonSchema, JsonSchemaSerializer + + +def test_jsonschema_examples_field_is_typed(): + """`examples` is a declared field, not just an extra attribute.""" + assert "examples" in JsonSchema.model_fields + + schema = JsonSchema(type="string", examples=["user123", "user456"]) + assert schema.examples == ["user123", "user456"] + + +def test_jsonschema_examples_default_none(): + """`examples` defaults to None when absent.""" + schema = JsonSchema(type="string") + assert schema.examples is None + + +def test_jsonschema_examples_roundtrip(): + """`examples` survives serialize -> validate roundtrip.""" + serializer = JsonSchemaSerializer() + schema = JsonSchema( + type="object", + examples=[{"id": "user123", "name": "John Doe"}], + ) + + as_dict = serializer.to_dict(schema) + assert as_dict["examples"] == [{"id": "user123", "name": "John Doe"}] + + restored = serializer.validate_dict(as_dict) + assert restored.examples == schema.examples + + +def test_jsonschema_examples_allows_mixed_json_types(): + """`examples` accepts any JSON value (string, bool, number, object).""" + schema = JsonSchema(examples=["a", True, 1, 1.5, None, {"k": "v"}, [1, 2]]) + assert schema.examples == ["a", True, 1, 1.5, None, {"k": "v"}, [1, 2]]