fix: MiniMax tool call normalization and thinking block handling (#458)
Co-authored-by: 0xallam <ahmed39652003@gmail.com>
This commit is contained in:
+20
-3
@@ -1,4 +1,5 @@
|
||||
import asyncio
|
||||
import re
|
||||
from collections.abc import AsyncIterator
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
@@ -25,6 +26,19 @@ from strix.utils.resource_paths import get_strix_resource_path
|
||||
litellm.drop_params = True
|
||||
litellm.modify_params = True
|
||||
|
||||
_THINKING_BLOCK_RE = re.compile(r"<thinking[^>]*>.*?</thinking>", re.DOTALL)
|
||||
_THINKING_BLOCK_OR_OPEN_RE = re.compile(r"<thinking[^>]*>.*?(?:</thinking>|\Z)", re.DOTALL)
|
||||
|
||||
|
||||
def _find_end_tag_outside_thinking(content: str, end_tag: str) -> int:
|
||||
thinking_spans = [(m.start(), m.end()) for m in _THINKING_BLOCK_OR_OPEN_RE.finditer(content)]
|
||||
start = 0
|
||||
while (idx := content.find(end_tag, start)) != -1:
|
||||
if not any(s <= idx < e for s, e in thinking_spans):
|
||||
return idx
|
||||
start = idx + 1
|
||||
return -1
|
||||
|
||||
|
||||
class LLMRequestFailedError(Exception):
|
||||
def __init__(self, message: str, details: str | None = None):
|
||||
@@ -197,9 +211,10 @@ class LLM:
|
||||
delta = self._get_chunk_content(chunk)
|
||||
if delta:
|
||||
accumulated += delta
|
||||
if "</function>" in accumulated or "</invoke>" in accumulated:
|
||||
end_tag = "</function>" if "</function>" in accumulated else "</invoke>"
|
||||
pos = accumulated.find(end_tag)
|
||||
check_content = _THINKING_BLOCK_OR_OPEN_RE.sub("", accumulated)
|
||||
if "</function>" in check_content or "</invoke>" in check_content:
|
||||
end_tag = "</function>" if "</function>" in check_content else "</invoke>"
|
||||
pos = _find_end_tag_outside_thinking(accumulated, end_tag)
|
||||
accumulated = accumulated[: pos + len(end_tag)]
|
||||
yield LLMResponse(content=accumulated)
|
||||
done_streaming = 1
|
||||
@@ -209,8 +224,10 @@ class LLM:
|
||||
if chunks:
|
||||
self._update_usage_stats(stream_chunk_builder(chunks))
|
||||
|
||||
accumulated = _THINKING_BLOCK_RE.sub("", accumulated)
|
||||
accumulated = normalize_tool_format(accumulated)
|
||||
accumulated = fix_incomplete_tool_call(_truncate_to_first_function(accumulated))
|
||||
|
||||
yield LLMResponse(
|
||||
content=accumulated,
|
||||
tool_invocations=parse_tool_invocations(accumulated),
|
||||
|
||||
+6
-1
@@ -20,7 +20,12 @@ def normalize_tool_format(content: str) -> str:
|
||||
<function="X"> → <function=X>
|
||||
<parameter="X"> → <parameter=X>
|
||||
"""
|
||||
if "<invoke" in content or "<function_calls" in content:
|
||||
if (
|
||||
"<invoke" in content
|
||||
or "<function_calls" in content
|
||||
or '<parameter name="' in content
|
||||
or "<parameter name='" in content
|
||||
):
|
||||
content = _FUNCTION_CALLS_TAG.sub("", content)
|
||||
content = _INVOKE_OPEN.sub(r"<function=\1>", content)
|
||||
content = _PARAM_NAME_ATTR.sub(r"<parameter=\1>", content)
|
||||
|
||||
Reference in New Issue
Block a user