From 64b4942971f3e246ce27cfc0dbba8c44ed33242d Mon Sep 17 00:00:00 2001 From: cstolting-collab Date: Thu, 17 Sep 2026 13:11:28 -0400 Subject: [PATCH] fix: preserve Pydantic field descriptions in schemas --- .../schema/kernel_json_schema_builder.py | 7 ++----- python/tests/unit/schema/test_schema_builder.py | 12 ++++++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/python/semantic_kernel/schema/kernel_json_schema_builder.py b/python/semantic_kernel/schema/kernel_json_schema_builder.py index 5ec519b5b377..d2291f52ac1a 100644 --- a/python/semantic_kernel/schema/kernel_json_schema_builder.py +++ b/python/semantic_kernel/schema/kernel_json_schema_builder.py @@ -89,12 +89,9 @@ def build_model_schema( field_description = None if hasattr(model, "model_fields") and field_name in model.model_fields: field_info = model.model_fields[field_name] - if isinstance(field_info.metadata, dict): + field_description = getattr(field_info, "description", None) + if field_description is None and isinstance(getattr(field_info, "metadata", None), dict): field_description = field_info.metadata.get("description") - elif isinstance(field_info.metadata, list) and field_info.metadata: - field_description = field_info.metadata[0] - elif hasattr(field_info, "description"): - field_description = field_info.description if not cls._is_optional(field_type): required.append(field_name) properties[field_name] = cls.build(field_type, field_description, structured_output) diff --git a/python/tests/unit/schema/test_schema_builder.py b/python/tests/unit/schema/test_schema_builder.py index 5d24a599c96c..c20db5b70cb2 100644 --- a/python/tests/unit/schema/test_schema_builder.py +++ b/python/tests/unit/schema/test_schema_builder.py @@ -6,6 +6,7 @@ from unittest.mock import Mock import pytest +from pydantic import Field from semantic_kernel.connectors.utils.structured_output_schema import generate_structured_output_response_format_schema from semantic_kernel.kernel_pydantic import KernelBaseModel @@ -76,6 +77,10 @@ class PydanticReasoning(KernelBaseModel): final_answer: str +class PydanticModelWithConstrainedField(KernelBaseModel): + top_p: float = Field(default=0.9, ge=0.0, le=1.0, description="nucleus sampling") + + class NonPydanticStep: explanation: str output: str @@ -156,6 +161,13 @@ def test_build_model_schema(): assert result == expected_schema +def test_build_model_schema_uses_pydantic_description_with_constraints(): + schema = KernelJsonSchemaBuilder.build_model_schema(PydanticModelWithConstrainedField) + + assert schema["properties"]["top_p"] == {"type": "number", "description": "nucleus sampling"} + json.dumps(schema) + + def test_build_from_type_name(): expected_schema = {"type": "string", "description": "A simple string"} result = KernelJsonSchemaBuilder.build_from_type_name("str", description="A simple string")