Accept integer input for union types that include number#2523
Open
sohumt123 wants to merge 1 commit into
Open
Conversation
validate_tool_arguments coerces an integer to a number when the expected type is the scalar string "number", but not when "number" appears inside a union type list such as ["number", "string"] (e.g. a parameter annotated `float | str`). In that case a valid whole-number JSON value (a Python int) is rejected with "Argument ... has type 'integer' but should be '['number', 'string']'". This surfaces in production through execute_tool_call, where the TypeError is wrapped into an AgentToolCallError, so a model that passes 1 instead of 1.0 to such a tool fails unnecessarily. Broaden the coercion so it fires whenever "number" is acceptable: the scalar case, or a union list that contains "number". The isinstance(expected_type, list) guard keeps the membership check off plain strings. Booleans are unaffected since bool maps to "boolean", never "integer". Extend test_validate_tool_arguments with union-with-number cases (int and float into `float | str` / `str | float`, plus a string case) covering both hint orderings, which normalize to the same sorted schema.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
validate_tool_argumentssupports coercing an integer to anumber, but only when the expected type is the scalar string"number". When"number"appears inside a union type list (e.g. a parameter annotatedfloat | str, which_parse_union_typenormalizes to{"type": ["number", "string"]}), the coercion never fires and a valid whole-number JSON value (a Pythonint) is rejected:Root cause is the coercion escape hatch in
src/smolagents/tools.py:The surrounding mismatch guard already handles union lists correctly (
actual_type not in expected_type), but the coercion branch is scalar-only, so anintfed to a union that containsnumberskips the escape hatch and raises.This is not just a validation-helper edge case: it reaches production through
execute_tool_call, where theTypeErroris wrapped into anAgentToolCallError(src/smolagents/agents.py:1476-1478). A model that emits1instead of1.0for a tool whose parameter is typedfloat | str(or any union including a number) fails unnecessarily, even though the scalar-numberversion of the same tool accepts the exact same value.Minimal repro:
Fix
Broaden the coercion so it fires whenever
numberis an acceptable type — the scalar case, or a union list that contains"number":Notes:
isinstance(expected_type, list)guard keeps theinmembership check off plain strings, so there is no accidental substring matching._get_json_schema_typemapsboolto"boolean", never"integer", soTrue/Falsestill cannot slip into a number union (the existing(str | int, True, True)case continues to reject)._parse_union_typesorts union members, so bothfloat | strandstr | floatnormalize to["number", "string"].The docstring
Notewas updated to reflect that coercion also applies when"number"is one member of a union type list.I intentionally kept this scoped to the dict-argument coercion branch. The non-dict single-argument branch (
tools.py, theelseat the bottom of the function) has separate pre-existing gaps (no int→number coercion at all, and a!=comparison that does not account for list expected types), and a union containingAnyis also rejected because that wildcard check is scalar-only. Those are worth a follow-up but are out of scope here.Testing
Extended the existing parametrized
test_validate_tool_argumentswith union-with-number cases (no new fixtures; the@tool-decorated closure builds the schema exactly as production does):Before the fix (new cases added, fix not yet applied):
After the fix:
Wider regression run and the quality gate both pass:
Tested locally on Python 3.10.