Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions vllm/tool_parsers/glm4_moe_tool_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
streaming experience for long content.
"""

import ast
import json
from collections.abc import Sequence
from typing import Any
Expand Down Expand Up @@ -42,6 +41,7 @@
extract_types_from_schema,
find_tool_properties,
partial_tag_overlap,
safe_literal_eval,
)

logger = init_logger(__name__)
Expand Down Expand Up @@ -110,7 +110,7 @@ def _deserialize(value: str) -> Any:
pass

try:
return ast.literal_eval(value)
return safe_literal_eval(value)
except (ValueError, SyntaxError):
pass

Expand Down
6 changes: 3 additions & 3 deletions vllm/tool_parsers/hy_v3_tool_parser.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project

import ast
import json
from collections.abc import Sequence
from typing import Any
Expand All @@ -27,6 +26,7 @@
Tool,
ToolParser,
)
from vllm.tool_parsers.utils import safe_literal_eval

logger = init_logger(__name__)

Expand Down Expand Up @@ -183,13 +183,13 @@ def _try_parse_wildcard_number(value: str) -> int | float | None:

@staticmethod
def _deserialize(value: str) -> Any:
"""Deserialize a string value using json.loads then ast.literal_eval."""
"""Deserialize a string value using json.loads then safe_literal_eval."""
try:
return json.loads(value)
except Exception:
pass
try:
return ast.literal_eval(value)
return safe_literal_eval(value)
except Exception:
pass
return value
Expand Down
5 changes: 2 additions & 3 deletions vllm/tool_parsers/minicpm5xml_tool_parser.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project

import ast
import json
from collections.abc import Sequence
from typing import Any
Expand All @@ -28,7 +27,7 @@
Tool,
ToolParser,
)
from vllm.tool_parsers.utils import partial_tag_overlap
from vllm.tool_parsers.utils import partial_tag_overlap, safe_literal_eval
from vllm.utils import random_uuid

logger = init_logger(__name__)
Expand Down Expand Up @@ -116,7 +115,7 @@ def _parse_arguments(json_value: str) -> tuple[Any, bool]:
try:
parsed_value = json.loads(json_value)
except json.JSONDecodeError:
parsed_value = ast.literal_eval(json_value)
parsed_value = safe_literal_eval(json_value)
return parsed_value, True
except Exception:
return json_value, False
Expand Down
4 changes: 2 additions & 2 deletions vllm/tool_parsers/poolside_v1_tool_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
streaming experience for long content.
"""

import ast
import json
from collections.abc import Sequence
from typing import Any
Expand Down Expand Up @@ -41,6 +40,7 @@
Tool,
ToolParser,
)
from vllm.tool_parsers.utils import safe_literal_eval

logger = init_logger(__name__)

Expand Down Expand Up @@ -106,7 +106,7 @@ def _deserialize(value: str) -> Any:
pass

try:
return ast.literal_eval(value)
return safe_literal_eval(value)
except (ValueError, SyntaxError):
pass

Expand Down
5 changes: 2 additions & 3 deletions vllm/tool_parsers/qwen3xml_tool_parser.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
import ast
import json
from collections.abc import Sequence
from typing import Any
Expand All @@ -26,7 +25,7 @@
Tool,
ToolParser,
)
from vllm.tool_parsers.utils import find_tool_properties
from vllm.tool_parsers.utils import find_tool_properties, safe_literal_eval

logger = init_logger(__name__)

Expand Down Expand Up @@ -824,7 +823,7 @@ def _end_element(self, name: str):
try:
parsed_value = json.loads(raw_for_parse)
except json.JSONDecodeError:
parsed_value = ast.literal_eval(raw_for_parse)
parsed_value = safe_literal_eval(raw_for_parse)
output_arguments = json.dumps(parsed_value, ensure_ascii=False)
except Exception:
# Fallback: output as string as-is
Expand Down
4 changes: 2 additions & 2 deletions vllm/tool_parsers/step3p5_tool_parser.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
import ast
import json
from collections.abc import Sequence
from typing import Any
Expand All @@ -23,6 +22,7 @@
from vllm.logger import init_logger
from vllm.tokenizers import TokenizerLike
from vllm.tool_parsers.abstract_tool_parser import Tool, ToolParser
from vllm.tool_parsers.utils import safe_literal_eval

logger = init_logger(__name__)

Expand Down Expand Up @@ -1016,7 +1016,7 @@ def _end_element(self, name: str):
raw_for_parse = raw_text + "\n"
else:
raw_for_parse = raw_text
parsed_value = ast.literal_eval(raw_for_parse)
parsed_value = safe_literal_eval(raw_for_parse)
output_arguments = json.dumps(parsed_value, ensure_ascii=False)
except Exception:
# Fallback: output as string as-is
Expand Down
7 changes: 7 additions & 0 deletions vllm/tool_parsers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import ast
import json
import warnings
from json import JSONDecodeError, JSONDecoder
from typing import Any, TypeAlias

Expand Down Expand Up @@ -31,6 +32,12 @@
logger = init_logger(__name__)


def safe_literal_eval(text: str):
with warnings.catch_warnings():
warnings.simplefilter("ignore", SyntaxWarning)
return ast.literal_eval(text)


def partial_tag_overlap(text: str, tag: str) -> int:
"""Length of the longest prefix of *tag* that matches a suffix of *text*.

Expand Down
Loading