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,