Skip to content

Conversation

@chitralputhran
Copy link

Summary

PR implements full Pydantic BaseModel support for smolagents tools, allowing developers to use Pydantic models as tool parameters with automatic validation, schema generation, and dict-to-model conversion.
Fixes #699

Features

  • Automatic Pydantic detection: Tools can now accept Pydantic BaseModel classes as parameter types
  • Dict-to-model conversion: Automatically converts dictionary arguments to Pydantic model instances during tool execution
  • Schema integration: Pydantic JSON schemas are properly processed and integrated with smolagents validation system
  • Updated validation: Supports complex Pydantic features including nested models, enum constraints, optional fields, and custom validators
  • Backward compatibility: All existing tools continue to work without changes

Changes Made

Implementation

src/smolagents/_function_type_hints_utils.py

  • Added _is_pydantic_model() to detect Pydantic BaseModel classes
  • Added _get_pydantic_json_schema() to extract JSON schemas from Pydantic models
  • Added _process_pydantic_schema() to handle schema processing including $refs resolution

src/smolagents/tools.py

  • Updated Tool.__call__() with argument parsing for both single-parameter and multi-parameter scenarios
  • Added _convert_dict_args_to_pydantic_models() method for automatic dict-to-Pydantic conversion
  • Improved _validate_value_against_schema() with additional validation for complex schemas

Testing

tests/test_tools.py

  • Added TestPydanticToolIntegration class with additional test cases
  • Tests cover basic model usage, validation success/failure scenarios, optional fields, enum constraints, and nested models

tests/test_function_type_hints_utils.py

  • Added TestPydanticIntegration class with additional test cases
  • Tests cover model detection, schema extraction, processing, and error handling

Usage Examples

Before (Limited Support)

# Complex schema definition was difficult and error-prone
inputs = {
    "report_config": {
        "type": "object",
        "description": "Configuration for report",
        "properties": {
            "sheet_name": {"type": "string", "description": "Name of sheet"},
            "start_date": {"type": "string", "description": "Start date"},
            # Manual schema definition...
        }
    }
}

After (Full Pydantic Support)

from pydantic import BaseModel, Field
from enum import Enum

class ReportType(str, Enum):
    REPORT_1 = "report_1"
    REPORT_2 = "report_2"

class ReportConfig(BaseModel):
    sheet_name: str = Field(description="Name of the sheet")
    start_date: str = Field(description="Start date")
    report_type: ReportType = Field(description="Type of report")

@tool
def create_report(config: ReportConfig) -> str:
    """Create a report with the given configuration.
    
    Args:
        config: Report configuration
    """
    return f"Creating {config.report_type} report for {config.sheet_name}"

# Tool automatically handles dict-to-Pydantic conversion
result = create_report({
    "config": {
        "sheet_name": "Sales Data",
        "start_date": "2024-01-01", 
        "report_type": "report_1"
    }
})

Backward Compatibility

This implementation maintains full backward compatibility:

  • All existing tools continue to work unchanged
  • Traditional input definitions using dict schemas remain supported

This implementation resolves the core issues outlined in #699 by providing Pydantic integration.

@chitralputhran chitralputhran changed the title Add comprehensive Pydantic schema support for smolagents tools Add Pydantic schema support for smolagents tools Aug 4, 2025
"object",
"any",
"null",
# Additional types that can appear in Pydantic schemas
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Additional types that can appear in Pydantic schemas

"any",
"null",
# Additional types that can appear in Pydantic schemas
"enum", # For enum constraints
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the comment (remnants of vibe coding?)

potential_kwargs = args[0]

# If the dictionary keys match our input parameters, convert it to kwargs
# This handles the case where the dict keys are the parameter names
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unclear comment IMO

Suggested change
# This handles the case where the dict keys are the parameter names

if all(key in self.inputs for key in potential_kwargs):
args = ()
kwargs = potential_kwargs
# If we have exactly one input parameter and the dict doesn't match parameter names,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the dict does not match the single parameter name, maybe it should be considered an error, i.e. the agent is trying to call a tool with wrong parameters?

Checks that all provided arguments match the tool's expected input types and that
all required arguments are present. Supports both dictionary arguments and single
value arguments for tools with one input parameter.
value arguments for tools with one input parameter. Now includes updated support
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remnants of vibe coding?

# Use updated validation for complex schemas
_validate_value_against_schema(value, input_schema, key)
else:
# Fall back to original simple validation for backward compatibility
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of having a split validation: just make a full new validation and test it to make sure it does not break anything

@aymeric-roucher
Copy link
Collaborator

Thank you @chitralputhran, I think supporting pydantic BaseModel would be great! Noting that this would require adding pydantic to dependancies, @albertvillanova is that not an issue?

@chitralputhran chitralputhran deleted the feature/pydantic-schema-support branch August 6, 2025 12:12
@aymeric-roucher
Copy link
Collaborator

@chitralputhran FYI I've opened #1660 to finish this great work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature request] Enable Tool arguments to process pydantic schemas properly

2 participants