Small compatibility helpers for OpenAI-compatible providers that emit tool calls
as XML-like text in message.content instead of structured OpenAI
message.tool_calls.
This was extracted from the TAU3 / Tinker Qwen3.6 evaluation debugging. The core problem was:
-
Tinker/Qwen sometimes returns:
{ "role": "assistant", "content": "<think>...</think>\n<tool_call><function=get_order_details><parameter=order_id>#W123</parameter></function></tool_call>", "tool_calls": null } -
Most OpenAI-style agent frameworks expect:
{ "role": "assistant", "content": null, "tool_calls": [ { "id": "call_xxx", "type": "function", "function": { "name": "get_order_details", "arguments": "{\"order_id\":\"#W123\"}" } } ] }
This package does two things:
- Convert inbound Tinker XML-like tool calls to OpenAI-style
tool_calls. - Convert outbound OpenAI tool-call history and tool results into plain
assistant text for providers that reject
role=toolhistory.
from tinker2openai_tool import (
normalize_tinker_assistant_message,
to_tinker_compatible_messages,
)
raw_message = {
"role": "assistant",
"content": """
<think>Need order details.</think>
<tool_call>
<function=get_order_details>
<parameter=order_id>
"#W123"
</parameter>
</function>
</tool_call>
""",
"tool_calls": None,
}
normalized = normalize_tinker_assistant_message(
raw_message,
allowed_tool_names={"get_order_details"},
)
print(normalized["tool_calls"][0]["function"]["name"])For the next provider call:
messages = [
{"role": "user", "content": "Return order #W123"},
normalized,
{
"role": "tool",
"tool_call_id": normalized["tool_calls"][0]["id"],
"content": "{\"status\":\"delivered\"}",
},
]
safe_for_tinker = to_tinker_compatible_messages(messages)safe_for_tinker will not contain OpenAI role=tool messages or assistant
tool_calls history. Instead, those are represented as assistant text:
Tool call: get_order_details
Arguments: {"order_id":"#W123"}
Tool result:
{"status":"delivered"}
- Always pass
allowed_tool_namesif you can. It prevents hallucinated tool names from being converted into executable calls. - This is a compatibility shim, not a model-quality fix. If the model emits pure planning text with no XML-like tool call, this code will not invent one.
- The implementation is dependency-free Python 3.10+.