From f0daa2dc247aa0000acffdad1d80b3df3c71791f Mon Sep 17 00:00:00 2001 From: Aegis Dev Date: Sun, 31 May 2026 19:05:50 -0400 Subject: [PATCH] fix(function_schema): raise UserError for Pydantic-reserved parameter names Pydantic's create_model() treats 'model_config', 'model_fields', and 'model_computed_fields' as model-level config keys rather than fields. Passing a FieldInfo for those names caused a TypeError inside Pydantic's ConfigWrapper.for_model() with no actionable error message. Add a pre-flight check that raises UserError before calling create_model() whenever a function parameter uses one of these reserved names. Fixes #3547 --- src/agents/function_schema.py | 12 ++++++++++++ tests/test_function_schema.py | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/agents/function_schema.py b/src/agents/function_schema.py index 8fe52df320..93e5deccc3 100644 --- a/src/agents/function_schema.py +++ b/src/agents/function_schema.py @@ -318,7 +318,19 @@ def function_schema( # field_name -> (type_annotation, default_value_or_Field(...)) fields: dict[str, Any] = {} + # Pydantic's create_model() treats certain names as model-level configuration + # keys rather than fields (e.g. 'model_config', 'model_fields'). Passing + # a FieldInfo for those names causes a TypeError deep inside Pydantic, so + # we reject them early with a clear message. + _PYDANTIC_RESERVED_NAMES = {"model_config", "model_fields", "model_computed_fields"} + for name, param in filtered_params: + if name in _PYDANTIC_RESERVED_NAMES: + raise UserError( + f"Function '{func.__name__}' has a parameter named '{name}', which is reserved " + f"by Pydantic and cannot be used as a tool parameter name. " + f"Please rename the parameter." + ) ann = type_hints.get(name, param.annotation) default = param.default diff --git a/tests/test_function_schema.py b/tests/test_function_schema.py index 9771bda99d..f749de2166 100644 --- a/tests/test_function_schema.py +++ b/tests/test_function_schema.py @@ -885,3 +885,13 @@ def func_with_annotated_multiple_field_constraints( with pytest.raises(ValidationError): # zero factor fs.params_pydantic_model(**{"score": 50, "factor": 0.0}) + + +def test_pydantic_reserved_param_name_raises_user_error(): + """Parameters named 'model_config' (or other Pydantic reserved names) must raise UserError.""" + + def func_with_reserved(model_config: str) -> str: + return model_config + + with pytest.raises(UserError, match="reserved by Pydantic"): + function_schema(func_with_reserved)