Revert "[Bugfix] Fix Qwen3CoderToolParser anyOf/oneOf type resolution for nullable params (#37831)"#38751
Conversation
… for nullable params (vllm-project#37831)" This reverts commit 582340f.
There was a problem hiding this comment.
Code Review
This pull request simplifies the parameter type resolution logic in the qwen3coder_tool_parser and removes associated unit tests. The review feedback identifies several regressions introduced by this simplification, specifically regarding the handling of array-based types, $ref schemas, and oneOf definitions, which will cause tool call arguments to be incorrectly processed as raw strings instead of parsed objects or typed values.
| if ( | ||
| isinstance(param_config[param_name], dict) | ||
| and "type" in param_config[param_name] | ||
| ): | ||
| param_type = str(param_config[param_name]["type"]).strip().lower() | ||
| elif ( | ||
| isinstance(param_config[param_name], dict) | ||
| and "anyOf" in param_config[param_name] | ||
| ): | ||
| # anyOf has no top-level "type"; treat as object to trigger json.loads. | ||
| param_type = "object" | ||
| else: | ||
| param_type = "string" |
There was a problem hiding this comment.
The simplified type resolution logic introduced in this revert has several regressions compared to the logic being removed:
- Array
typesupport: If a parameter definition uses an array for thetypefield (e.g.,"type": ["integer", "null"]),str(param_config[param_name]["type"])will result in a string like"['integer', 'null']". This will fail the subsequent.startswith("int")and other type checks, defaulting to string or relying on theast.literal_evalfallback, which may fail for booleans. - Missing
$refandoneOf: The previous logic correctly handled$ref(treating it as anobject) andoneOf. The new logic defaults these to"string", which will cause nested objects (common with Pydantic models) to be returned as raw strings instead of parsed dictionaries.
Since this is a revert intended to fix CI, if a full restoration of the previous logic is not desired, consider at least handling these common cases to avoid breaking tool calls with nested models or nullable fields.
param_def = param_config[param_name]
if not isinstance(param_def, dict):
param_type = "string"
elif "type" in param_def:
t = param_def["type"]
if isinstance(t, list):
# Extract first non-null type
param_type = next((str(x).strip().lower() for x in t if x and str(x).strip().lower() != "null"), "string")
else:
param_type = str(t).strip().lower()
elif any(k in param_def for k in ("anyOf", "oneOf", "$ref")):
# Treat complex schemas and references as objects to trigger json.loads
param_type = "object"
else:
param_type = "string"… for nullable params (vllm-project#37831)" (vllm-project#38751)
Summary
vllm/tool_parsers/qwen3coder_tool_parser.pyand added tests intests/tool_parsers/test_qwen3coder_tool_parser.pyfor anyOf/oneOf type resolution for nullable params.Test plan
🤖 Generated with Claude Code