← back to Exo
Normalise Responses API tool call format (#1704)
f221a6c85c427757df547cce71f92fdf0861b5f5 · 2026-03-11 18:10:12 +0000 · rltakashige
## Motivation
The responses API often does not provide tool args nested under a
"function" field. Since we follow the chat completions format of tools
in the backend (for MLX chat templates), we need to normalise to this
format.
## Test Plan
### Manual Testing
Works on n8n!
<img width="3442" height="2076" alt="image"
src="https://github.com/user-attachments/assets/9e11d679-0102-4d83-9a8e-b0a7a5898708"
/>
Files touched
M src/exo/master/adapters/responses.py
Diff
commit f221a6c85c427757df547cce71f92fdf0861b5f5
Author: rltakashige <rl.takashige@gmail.com>
Date: Wed Mar 11 18:10:12 2026 +0000
Normalise Responses API tool call format (#1704)
## Motivation
The responses API often does not provide tool args nested under a
"function" field. Since we follow the chat completions format of tools
in the backend (for MLX chat templates), we need to normalise to this
format.
## Test Plan
### Manual Testing
Works on n8n!
<img width="3442" height="2076" alt="image"
src="https://github.com/user-attachments/assets/9e11d679-0102-4d83-9a8e-b0a7a5898708"
/>
---
src/exo/master/adapters/responses.py | 24 +++++++++++++++++++++++-
1 file changed, 23 insertions(+), 1 deletion(-)
diff --git a/src/exo/master/adapters/responses.py b/src/exo/master/adapters/responses.py
index 0a40c016..c92c4e37 100644
--- a/src/exo/master/adapters/responses.py
+++ b/src/exo/master/adapters/responses.py
@@ -128,6 +128,28 @@ def responses_request_to_text_generation(
effort_from_reasoning, request.enable_thinking
)
+ # The responses API often does not provide tool args nested under a "function" field.
+ # Since we follow the chat completions format of tools in the backend (for MLX chat templates)
+ # we need to normalise to this format.
+ normalised_tools: list[dict[str, Any]] | None = None
+ if request.tools:
+ normalised_tools = []
+ for tool in request.tools:
+ if "function" in tool:
+ normalised_tools.append(tool)
+ else:
+ normalised_tools.append(
+ {
+ "type": "function",
+ "function": {
+ "name": tool.get("name", ""),
+ "description": tool.get("description", ""),
+ "parameters": tool.get("parameters", {}),
+ **({"strict": tool["strict"]} if "strict" in tool else {}),
+ },
+ }
+ )
+
return TextGenerationTaskParams(
model=request.model,
input=input_value,
@@ -136,7 +158,7 @@ def responses_request_to_text_generation(
temperature=request.temperature,
top_p=request.top_p,
stream=request.stream,
- tools=request.tools,
+ tools=normalised_tools,
top_k=request.top_k,
stop=request.stop,
seed=request.seed,
← 2994b410 fix: validate num_key_value_heads in tensor sharding placeme
·
back to Exo
·
fix: show partial download progress on initial dashboard loa 0782d90e →