-
Notifications
You must be signed in to change notification settings - Fork 517
Open
Description
When a conversation history includes prior tool calls (assistant message with tool_calls), process_message_content() in server.py converts arguments from a JSON string
to a Python dict via json.loads(). However, some model chat templates (e.g. DepSeek-R1) perform direct string concatenation with arguments, causing a TypeError: can only concatenate str (not "dict") to str → HTTP 404.
Steps to Reproduce
curl -X POST http://localhost:8081/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "mlx-community/DeepSeek-R1-0528-Qwen3-8B-8bit",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "run ls"},
{"role": "assistant", "content": null, "tool_calls": [{"id": "call_1", "type": "function", "function": {"name": "exec", "arguments": "{\"command\": \"ls\"}"}}]},
{"role": "tool", "tool_call_id": "call_1", "content": "file1.txt"}
],
"tools": [{"type": "function", "function": {"name": "exec", "description": "Run shell", "parameters": {"type": "object", "properties": {"command": {"type": "string"}},
"required": ["command"]}}}],
"max_tokens": 10
}'Root Cause
process_message_content() (server.py ~line 165):
func["arguments"] = json.loads(args) # converts string → dictThe DeepSeek-R1 Jinja2 template then does:
'```json\n' + tool['function']['arguments'] + '\n```'
Fails because arguments is now a dict, not a string.
Fix
Re-serialize back to string instead of leaving as dict:
if isinstance(args, str):
func["arguments"] = json.dumps(json.loads(args), ensure_ascii=False)
elif isinstance(args, dict):
func["arguments"] = json.dumps(args, ensure_ascii=False)Environment
- mlx-lm: 0.31.2
- Model: mlx-community/DeepSeek-R1-0528-Qwen3-8B-8bit
- macOS arm64
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels