diff --git a/strix/llm/llm.py b/strix/llm/llm.py
index e500d80..6fd727d 100644
--- a/strix/llm/llm.py
+++ b/strix/llm/llm.py
@@ -26,8 +26,10 @@ from strix.utils.resource_paths import get_strix_resource_path
litellm.drop_params = True
litellm.modify_params = True
-_THINKING_BLOCK_RE = re.compile(r"]*>.*?", re.DOTALL)
-_THINKING_BLOCK_OR_OPEN_RE = re.compile(r"]*>.*?(?:|\Z)", re.DOTALL)
+_THINKING_BLOCK_RE = re.compile(r"]*>.*?", re.DOTALL)
+_THINKING_BLOCK_OR_OPEN_RE = re.compile(
+ r"]*>.*?(?:|\Z)", re.DOTALL
+)
def _find_end_tag_outside_thinking(content: str, end_tag: str) -> int:
diff --git a/strix/llm/utils.py b/strix/llm/utils.py
index 0f56bed..8b3e4cd 100644
--- a/strix/llm/utils.py
+++ b/strix/llm/utils.py
@@ -1,4 +1,5 @@
import html
+import json
import re
from typing import Any
@@ -6,6 +7,7 @@ from typing import Any
_INVOKE_OPEN = re.compile(r'')
_PARAM_NAME_ATTR = re.compile(r'')
_FUNCTION_CALLS_TAG = re.compile(r"?function_calls>")
+_MINIMAX_TOOL_CALL_TAG = re.compile(r"?minimax:tool_call>")
_STRIP_TAG_QUOTES = re.compile(r"<(function|parameter)\s*=\s*([^>]*?)>")
@@ -13,6 +15,7 @@ def normalize_tool_format(content: str) -> str:
"""Convert alternative tool-call XML formats to the expected one.
Handles:
+ ... → stripped
... → stripped
→
→
@@ -20,6 +23,8 @@ def normalize_tool_format(content: str) -> str:
→
→
"""
+ content = _MINIMAX_TOOL_CALL_TAG.sub("", content)
+
if (
" list[dict[str, Any]] | None:
param_value = html.unescape(param_value)
args[param_name] = param_value
+ if not args:
+ body_stripped = html.unescape(fn_body.strip())
+ if body_stripped.startswith("{"):
+ try:
+ parsed = json.loads(body_stripped)
+ if isinstance(parsed, dict):
+ args = {
+ k: v if isinstance(v, str) else json.dumps(v)
+ for k, v in parsed.items()
+ }
+ except (json.JSONDecodeError, ValueError):
+ pass
+
tool_invocations.append({"toolName": fn_name, "args": args})
return tool_invocations if tool_invocations else None