Fix Pydantic field alias consistency in structured output (#1099)
This commit is contained in:
parent
906ceea388
commit
5c9cf290d8
2 changed files with 46 additions and 1 deletions
|
|
@ -111,7 +111,7 @@ class FuncMetadata(BaseModel):
|
||||||
|
|
||||||
assert self.output_model is not None, "Output model must be set if output schema is defined"
|
assert self.output_model is not None, "Output model must be set if output schema is defined"
|
||||||
validated = self.output_model.model_validate(result)
|
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)
|
return (unstructured_content, structured_content)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -839,3 +839,48 @@ def test_structured_output_unserializable_type_error():
|
||||||
func_metadata(func_returning_namedtuple, structured_output=True)
|
func_metadata(func_returning_namedtuple, structured_output=True)
|
||||||
assert "is not serializable for structured output" in str(exc_info.value)
|
assert "is not serializable for structured output" in str(exc_info.value)
|
||||||
assert "Point" 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
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue