Fix Pydantic field alias consistency in structured output (#1099)

This commit is contained in:
Seongjun Kim 2025-07-07 23:16:23 +09:00 • committed by GitHub
commit 5c9cf290d8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 46 additions and 1 deletions

View file

@ -111,7 +111,7 @@ class FuncMetadata(BaseModel):
assert self.output_model is not None, "Output model must be set if output schema is defined"
validated = self.output_model.model_validate(result)
structured_content = validated.model_dump(mode="json")
structured_content = validated.model_dump(mode="json", by_alias=True)
return (unstructured_content, structured_content)

View file

@ -839,3 +839,48 @@ def test_structured_output_unserializable_type_error():
func_metadata(func_returning_namedtuple, structured_output=True)
assert "is not serializable for structured output" in str(exc_info.value)
assert "Point" in str(exc_info.value)
def test_structured_output_aliases():
"""Test that field aliases are consistent between schema and output"""
class ModelWithAliases(BaseModel):
field_first: str | None = Field(default=None, alias="first", description="The first field.")
field_second: str | None = Field(default=None, alias="second", description="The second field.")
def func_with_aliases() -> ModelWithAliases:
# When aliases are defined, we must use the aliased names to set values
return ModelWithAliases(**{"first": "hello", "second": "world"})
meta = func_metadata(func_with_aliases)
# Check that schema uses aliases
assert meta.output_schema is not None
assert "first" in meta.output_schema["properties"]
assert "second" in meta.output_schema["properties"]
assert "field_first" not in meta.output_schema["properties"]
assert "field_second" not in meta.output_schema["properties"]
# Check that the actual output uses aliases too
result = ModelWithAliases(**{"first": "hello", "second": "world"})
unstructured_content, structured_content = meta.convert_result(result)
# The structured content should use aliases to match the schema
assert "first" in structured_content
assert "second" in structured_content
assert "field_first" not in structured_content
assert "field_second" not in structured_content
assert structured_content["first"] == "hello"
assert structured_content["second"] == "world"
# Also test the case where we have a model with defaults to ensure aliases work in all cases
result_with_defaults = ModelWithAliases() # Uses default None values
unstructured_content_defaults, structured_content_defaults = meta.convert_result(result_with_defaults)
# Even with defaults, should use aliases in output
assert "first" in structured_content_defaults
assert "second" in structured_content_defaults
assert "field_first" not in structured_content_defaults
assert "field_second" not in structured_content_defaults
assert structured_content_defaults["first"] is None
assert structured_content_defaults["second"] is None