mirror of
https://github.com/microsoft/autogen.git
synced 2025-07-28 03:13:27 +00:00

AutoGen was passing raw dictionaries to functions instead of constructing Pydantic model or dataclass instances. If a tool function’s parameter was a Pydantic BaseModel or a dataclass, the function would receive a dict and likely throw an error or behave incorrectly (since it expected an object of that type). This PR addresses problem in AutoGen where tool functions expecting structured inputs (Pydantic models or dataclasses) were receiving raw dictionaries. It ensures that structured inputs are automatically validated and instantiated before function calls. Complete details are in Issue #5736 [Reproducible Example Code - Failing Case](https://colab.research.google.com/drive/1hgoP-cGdSZ1-OqQLpwYmlmcExgftDqlO?usp=sharing) <!-- Please give a short summary of the change and the problem this solves. --> ## Changes Made: - Inspect function signatures for Pydantic BaseModel and dataclass annotations. - Convert input dictionaries into properly instantiated objects using BaseModel.model_validate() for Pydantic models or standard instantiation for dataclasses. - Raise descriptive errors when validation or instantiation fails. - Unit tests have been added to cover all scenarios Now structured inputs are automatically validated and instantiated before function calls. - **Updated Conversion Logic:** In the `run()` method, we now inspect the function’s signature and convert input dictionaries to structured objects. For parameters annotated with a Pydantic model, we use `model_validate()` to create an instance; for those annotated with a dataclass, we instantiate the object using the dataclass constructor. For example: ```python # Get the function signature. sig = inspect.signature(self._func) raw_kwargs = args.model_dump() kwargs = {} # Iterate over the parameters expected by the function. for name, param in sig.parameters.items(): if name in raw_kwargs: expected_type = param.annotation value = raw_kwargs[name] # If expected type is a subclass of BaseModel, perform conversion. if inspect.isclass(expected_type) and issubclass(expected_type, BaseModel): try: kwargs[name] = expected_type.model_validate(value) except ValidationError as e: raise ValueError( f"Error validating parameter '{name}' for function '{self._func.__name__}': {e}" ) from e # If it's a dataclass, instantiate it. elif is_dataclass(expected_type): try: cls = expected_type if isinstance(expected_type, type) else type(expected_type) kwargs[name] = cls(**value) except Exception as e: raise ValueError( f"Error instantiating dataclass parameter '{name}' for function '{self._func.__name__}': {e}" ) from e else: kwargs[name] = value ``` - **Error Handling Improvements:** Conversion steps are wrapped in try/except blocks to raise descriptive errors when instantiation fails, aiding in debugging invalid inputs. - **Testing:** Unit tests have been added to simulate tool calls (e.g., an `add` tool) to ensure that with input like: ```json {"input": {"x": 2, "y": 3}} ``` The tool function receives an instance of the expected type and returns the correct result. ## Related issue number Closes #5736 ## Checks - [x] I've included any doc changes needed for <https://microsoft.github.io/autogen/>. See <https://github.com/microsoft/autogen/blob/main/CONTRIBUTING.md> to build and test documentation locally. - [x] I've added tests (if relevant) corresponding to the changes introduced in this PR. - [x] I've made sure all auto checks have passed.