diff --git a/python/packages/core/agent_framework/_tools.py b/python/packages/core/agent_framework/_tools.py index bfde7930c10..f75588e20b7 100644 --- a/python/packages/core/agent_framework/_tools.py +++ b/python/packages/core/agent_framework/_tools.py @@ -1471,7 +1471,7 @@ def _parse_annotation(annotation: Any) -> Any: args_list = list(args) if len(args_list) == 2: return Annotated[args_list[0], Field(description=args_list[1])] - return Annotated[args_list[0], Field(description=args_list[1]), tuple(args_list[2:])] + return Annotated[(args_list[0], Field(description=args_list[1]), *args_list[2:])] return annotation diff --git a/python/packages/core/tests/core/test_tools.py b/python/packages/core/tests/core/test_tools.py index 3071e191513..c20c72a3148 100644 --- a/python/packages/core/tests/core/test_tools.py +++ b/python/packages/core/tests/core/test_tools.py @@ -1565,6 +1565,40 @@ def test_parse_annotation_with_annotated_and_literal(): assert get_args(literal_type) == ("A", "B", "C") +def test_parse_annotation_with_description_preserves_extra_metadata(): + """Test that metadata after a string description is kept as separate Annotated metadata.""" + from pydantic import Field + + constraints = Field(ge=1, le=10) + result = _parse_annotation(Annotated[int, "How many items", constraints]) + + assert get_origin(result) is Annotated + args = get_args(result) + assert args[0] is int + assert args[1].description == "How many items" + assert args[2] is constraints + + +async def test_tool_annotated_description_keeps_field_constraints(): + """Test that Field constraints after a string description reach the schema and validation.""" + from pydantic import Field + + @tool + def pick(count: Annotated[int, "How many items", Field(ge=1, le=10)]) -> str: + return str(count) + + count_schema = pick.parameters()["properties"]["count"] + assert count_schema["description"] == "How many items" + assert count_schema["minimum"] == 1 + assert count_schema["maximum"] == 10 + + result = await pick.invoke(arguments={"count": 5}) + assert result[0].text == "5" + + with pytest.raises(TypeError, match="less_than_equal"): + await pick.invoke(arguments={"count": 999}) + + # endregion