diff --git a/vllm/entrypoints/openai/tool_parsers/hermes_tool_parser.py b/vllm/entrypoints/openai/tool_parsers/hermes_tool_parser.py
index c7030d34d45..1d445a049f6 100644
--- a/vllm/entrypoints/openai/tool_parsers/hermes_tool_parser.py
+++ b/vllm/entrypoints/openai/tool_parsers/hermes_tool_parser.py
@@ -44,7 +44,8 @@ def __init__(self, tokenizer: AnyTokenizer):
self.tool_call_end_token: str = ""
self.tool_call_regex = re.compile(
- r"(.*?)|(.*)", re.DOTALL)
+ r"\s*(.*?)\s*(?:\s*|\s*|$)",
+ re.DOTALL)
self.scratch_pad_regex = re.compile(
r"(.*?)", re.DOTALL)
@@ -80,15 +81,18 @@ def extract_tool_calls(
# tag and end-of-string so the result of
# findall is an array of tuples where one is a function call and
# the other is None
- function_call_tuples = (
- self.tool_call_regex.findall(model_output))
-
- # load the JSON, and then use it to build the Function and
- # Tool Call
- raw_function_calls = [
- json.loads(match[0] if match[0] else match[1])
- for match in function_call_tuples
- ]
+ matches = self.tool_call_regex.findall(model_output)
+ raw_function_calls = []
+ for match in matches:
+ if not match:
+ continue
+ try:
+ parsed = json.loads(match.strip())
+ raw_function_calls.append(parsed)
+ except json.JSONDecodeError as e:
+ logger.warning(
+ "Skipping malformed tool_call block: %s", e)
+
tool_calls = [
ToolCall(
type="function",
@@ -99,9 +103,9 @@ def extract_tool_calls(
ensure_ascii=False)))
for function_call in raw_function_calls
]
-
- content = model_output[:model_output.
- find(self.tool_call_start_token)]
+ tool_call_start = model_output.find(self.tool_call_start_token)
+ content = (model_output[:tool_call_start]
+ if tool_call_start >= 0 else None)
return ExtractedToolCallInformation(
tools_called=True,
tool_calls=tool_calls,