diff --git a/python/semantic_kernel/schema/kernel_json_schema_builder.py b/python/semantic_kernel/schema/kernel_json_schema_builder.py index 5ec519b5b377..fe44bdf97d45 100644 --- a/python/semantic_kernel/schema/kernel_json_schema_builder.py +++ b/python/semantic_kernel/schema/kernel_json_schema_builder.py @@ -91,9 +91,10 @@ def build_model_schema( field_info = model.model_fields[field_name] if isinstance(field_info.metadata, 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"): + # Pydantic v2 keeps constraints (Ge, Le, ...) in field_info.metadata, + # which is a list of constraint objects and not a description, + # so the description must come from field_info.description instead. field_description = field_info.description if not cls._is_optional(field_type): required.append(field_name) diff --git a/python/tests/unit/schema/test_schema_builder.py b/python/tests/unit/schema/test_schema_builder.py index 5d24a599c96c..8a6bc13ec093 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 @@ -455,3 +456,16 @@ def test_build_schema_with_nonpydantic_structured_output(): } assert structured_output_schema == expected_schema + + +class ConstrainedParams(KernelBaseModel): + top_p: float = Field(default=0.9, ge=0.0, le=1.0, description="nucleus sampling") + + +def test_build_model_schema_with_field_constraints_keeps_description(): + # Regression test for https://github.com/microsoft/semantic-kernel/issues/14443: + # pydantic constraint objects (Ge, Le, ...) live in FieldInfo.metadata and + # must not end up in the field description. + schema = KernelJsonSchemaBuilder.build_model_schema(ConstrainedParams) + assert schema["properties"]["top_p"]["description"] == "nucleus sampling" + json.dumps(schema) # the schema must be JSON serializable