diff --git a/vllm/tool_parsers/qwen3coder_tool_parser.py b/vllm/tool_parsers/qwen3coder_tool_parser.py index 216ae163b77a..e4b09bed1e71 100644 --- a/vllm/tool_parsers/qwen3coder_tool_parser.py +++ b/vllm/tool_parsers/qwen3coder_tool_parser.py @@ -157,12 +157,16 @@ def _convert_param_value( 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] + 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" + elif isinstance(param_config[param_name], dict) and ( + "$ref" in param_config[param_name] + ): + # $ref has no type information at this level; treat it separately. + param_type = "$ref" else: param_type = "string" if param_type in ["string", "str", "text", "varchar", "char", "enum"]: @@ -214,6 +218,24 @@ def _convert_param_value( func_name, ) return param_value == "true" + elif param_type == "$ref": + # For $ref types, we don't have direct type information here. + # Attempt JSON parsing first, then fallback to string. + # We avoid ast.literal_eval for $ref types due to potential complexity and + # security concerns. + try: + param_value = json.loads(param_value) + return param_value + except (json.JSONDecodeError, TypeError, ValueError): + logger.debug( + "Parsed value '%s' of parameter '%s' cannot be " + "parsed with json.loads for $ref type in tool '%s', " + "degenerating to string.", + param_value, + param_name, + func_name, + ) + return param_value else: if ( param_type in ["object", "array", "arr"]