diff --git a/src/crewai/utilities/converter.py b/src/crewai/utilities/converter.py index e9f8c6b8e..5a797d8a9 100644 --- a/src/crewai/utilities/converter.py +++ b/src/crewai/utilities/converter.py @@ -241,9 +241,13 @@ def generate_model_description(model: Type[BaseModel]) -> str: origin = get_origin(field_type) args = get_args(field_type) - if origin is Union and type(None) in args: + if origin is Union or (origin is None and len(args) > 0): + # Handle both Union and the new '|' syntax non_none_args = [arg for arg in args if arg is not type(None)] - return f"Optional[{describe_field(non_none_args[0])}]" + if len(non_none_args) == 1: + return f"Optional[{describe_field(non_none_args[0])}]" + else: + return f"Optional[Union[{', '.join(describe_field(arg) for arg in non_none_args)}]]" elif origin is list: return f"List[{describe_field(args[0])}]" elif origin is dict: @@ -252,8 +256,10 @@ def generate_model_description(model: Type[BaseModel]) -> str: return f"Dict[{key_type}, {value_type}]" elif isinstance(field_type, type) and issubclass(field_type, BaseModel): return generate_model_description(field_type) - else: + elif hasattr(field_type, "__name__"): return field_type.__name__ + else: + return str(field_type) fields = model.__annotations__ field_descriptions = [ diff --git a/tests/utilities/test_converter.py b/tests/utilities/test_converter.py index df906acd7..f661af9cd 100644 --- a/tests/utilities/test_converter.py +++ b/tests/utilities/test_converter.py @@ -588,3 +588,12 @@ def test_converter_with_function_calling(): assert output.name == "Eve" assert output.age == 35 instructor.to_pydantic.assert_called_once() + + +def test_generate_model_description_union_field(): + class UnionModel(BaseModel): + field: int | str | None + + description = generate_model_description(UnionModel) + expected_description = '{\n "field": int | str | None\n}' + assert description == expected_description