diff --git a/src/crewai/utilities/string_utils.py b/src/crewai/utilities/string_utils.py index 630512b04..f4527a6dc 100644 --- a/src/crewai/utilities/string_utils.py +++ b/src/crewai/utilities/string_utils.py @@ -1,10 +1,38 @@ import re -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, Optional + +SUPPORTED_PRIMITIVE_TYPES = (str, int, float, bool) +SUPPORTED_CONTAINER_TYPES = (dict, list) +SUPPORTED_TYPES = SUPPORTED_PRIMITIVE_TYPES + SUPPORTED_CONTAINER_TYPES + + +def _validate_input_type(val: Any) -> None: + """Validates input types recursively (str, int, float, bool, dict, list). + + Args: + val: The value to validate + + Raises: + ValueError: If the value contains unsupported types + """ + if val is None: + return + if isinstance(val, SUPPORTED_PRIMITIVE_TYPES): + return + if isinstance(val, SUPPORTED_CONTAINER_TYPES): + for item in val.values() if isinstance(val, dict) else val: + _validate_input_type(item) + return + raise ValueError( + f"Unsupported type {type(val).__name__} in inputs. " + "Only str, int, float, bool, dict, and list are allowed." + ) def interpolate_only( input_string: Optional[str], - inputs: Dict[str, Union[str, int, float, Dict[str, Any], List[Any]]], + inputs: Dict[str, Any], + raise_on_missing: bool = True, ) -> str: """Interpolate placeholders (e.g., {key}) in a string while leaving JSON untouched. Only interpolates placeholders that follow the pattern {variable_name} where @@ -28,26 +56,11 @@ def interpolate_only( from crewai.utilities.serialization import to_serializable processed_inputs = {} - supported_types = (str, int, float, bool, dict, list) for key, value in inputs.items(): - if value is None or isinstance(value, supported_types): - def validate_type(val: Any) -> None: - if val is None: - return - if isinstance(val, (str, int, float, bool)): - return - if isinstance(val, (dict, list)): - for item in val.values() if isinstance(val, dict) else val: - validate_type(item) - return - raise ValueError( - f"Unsupported type {type(val).__name__} in inputs. " - "Only str, int, float, bool, dict, and list are allowed." - ) - + if value is None or isinstance(value, SUPPORTED_TYPES): try: - validate_type(value) + _validate_input_type(value) processed_inputs[key] = value except ValueError as e: raise ValueError(f"Invalid value for key '{key}': {str(e)}") from e diff --git a/tests/utilities/test_string_utils.py b/tests/utilities/test_string_utils.py index 27ba2125c..c5e96c679 100644 --- a/tests/utilities/test_string_utils.py +++ b/tests/utilities/test_string_utils.py @@ -182,7 +182,7 @@ class TestInterpolateOnly: template = "Hello, {name}!" inputs: Dict[str, Any] = {} - with pytest.raises(ValueError) as excinfo: + with pytest.raises(ValueError): interpolate_only(template, inputs)