fix(tools): wrap bare scalars in single-element list for array-typed args#19717
Merged
Conversation
…args
Open-weight models (DeepSeek, Qwen, GLM) sometimes emit tool calls like
`{"urls": "https://a.com"}` when the tool schema declares
`type: array`. The call was JSON-valid but semantically wrong, and
`coerce_tool_args` would pass the bare string through — the tool then
failed with a confusing type error.
`coerce_tool_args` now wraps non-list, non-null values in a
single-element list when the schema declares `array`. Strings still go
through `_coerce_value` first so JSON-encoded arrays
(`'["a","b"]'`) parse correctly and nullable `"null"` still
becomes `None`. `None` itself is preserved — tools with sensible
defaults already handle it, and we don't want to silently mask a
deliberate null.
Salvaged from #19652 (NikolayGusev-astra) — the broader validate-then-
repair layer had several issues (duplicated existing coercion,
mis-classified `old_string` as a path field, prepended non-JSON
prefixes to tool results that break downstream JSON parsing, hardcoded
offset/limit defaults unsuitable for non-read_file tools). The one
genuinely new capability is wrapping bare scalars, which is implemented
here directly inside the existing coercion path.
Co-authored-by: Nikolay Gusev <ngusev@astralinux.ru>
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.
Open-weight models (DeepSeek, Qwen, GLM) sometimes emit
{"urls": "https://a.com"}where the schema expectstype: array. The call was JSON-valid but semantically wrong — the tool then failed with a confusing type error.coerce_tool_argsnow wraps non-list, non-null values into a single-element list.Changes
model_tools.coerce_tool_args: +24 LOC — new array-wrap branch that runs strings through_coerce_valuefirst (so JSON-encoded arrays and nullable"null"still work), then falls back to[value]wrap for bare scalars.Nonepreserved.tests/run_agent/test_tool_arg_coercion.pycovering bare string / int / dict / JSON-encoded / list-passthrough / None / existing-test-updated.Validation
{"urls": "https://a.com"}on array field["https://a.com"]{"urls": '["a","b"]'}["a","b"]["a","b"](unchanged){"stages": "null"}nullable arrayNoneNone(unchanged){"items": None}NoneNone(unchanged — we don't second-guess deliberate nulls)tests/run_agent/Relation to #19652
Salvaged from #19652 by @NikolayGusev-astra. The broader validate-then-repair layer in that PR had several problems: it duplicated the existing
coerce_tool_argspath for string→array, mis-classifiedold_stringas a path field (would silently corruptpatchcalls), hardcodedoffset=1 / limit=500defaults that only fitread_file, and prepended a[validate-then-repair: ...]prefix to every tool result — breaking any downstream consumer that JSON-parses tool output. The genuinely new capability was bare-scalar-as-array wrapping, which this PR implements directly inside the existing coercion path in ~24 LOC.Co-authored-by: Nikolay Gusev ngusev@astralinux.ru