Client or integration
Codex App
Area
Provider adapter
Summary
When routing to Volcengine Ark endpoints (e.g. huoshan-kimi-k3 via doubao/ark), multi-turn agent workflows that involve tool calls fail with a 400 error once an assistant message with tool_calls is present in history.
Expected: the request should succeed, matching the behavior of OpenAI/DeepSeek/xAI providers, which accept empty-string content on tool-call assistant messages.
Reproduction
ocx start --port 10100
- Send a chat-completions request where the history contains an assistant message with
tool_calls and empty content:
curl -X POST http://127.0.0.1:10100/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "9router/huoshan-kimi-k3",
"messages": [
{"role": "user", "content": "list dir"},
{"role": "assistant", "content": "", "tool_calls": [{"id": "call_1", "type": "function", "function": {"name": "shell", "arguments": "{\"cmd\":\"ls\"}"}}]},
{"role": "tool", "tool_call_id": "call_1", "content": "file1.txt"}
],
"stream": false
}'
- Observe:
Provider error 400: {"error":{"code":"MissingParameter","message":"The request failed because it is missing `input.content.text` parameter.","param":"input.content.text","type":"BadRequest"}}
A single-turn request (no tool history) works fine. The failure requires an assistant message with tool_calls + empty content.
Root cause
In src/adapters/openai-chat.ts, opencodex sets content = "" (empty string) in three places when an assistant message has tool_calls but no text:
- Line ~209:
if (!chatMsg.content) chatMsg.content = "";
- Line ~212:
chatMsg.content = ""; (reasoning-only path)
- Line ~243:
content: "" (orphan tool-call synthesis)
Volcengine Ark endpoints (Kimi-K3) treat empty-string content as missing input.content.text and return 400.
| assistant content |
Volcengine Ark result |
"" (empty string) |
400 MissingParameter |
null |
400 MissingParameter |
" " (single space) |
200 OK |
"any text" |
200 OK |
Suggested fix
Change the empty-string fallback to a single space in all three locations:
- if (!chatMsg.content) chatMsg.content = "";
+ if (!chatMsg.content) chatMsg.content = " ";
A single space satisfies both xAI's "at least one content element" validator and Volcengine Ark's non-empty content.text requirement, without altering model semantics.
Version
2.7.43-preview.20260728
Operating system
macOS (arm64, Darwin)
Client or integration
Codex App
Area
Provider adapter
Summary
When routing to Volcengine Ark endpoints (e.g.
huoshan-kimi-k3via doubao/ark), multi-turn agent workflows that involve tool calls fail with a 400 error once an assistant message withtool_callsis present in history.Expected: the request should succeed, matching the behavior of OpenAI/DeepSeek/xAI providers, which accept empty-string content on tool-call assistant messages.
Reproduction
ocx start --port 10100tool_callsand emptycontent:A single-turn request (no tool history) works fine. The failure requires an assistant message with
tool_calls+ emptycontent.Root cause
In
src/adapters/openai-chat.ts, opencodex setscontent = ""(empty string) in three places when an assistant message hastool_callsbut no text:if (!chatMsg.content) chatMsg.content = "";chatMsg.content = "";(reasoning-only path)content: ""(orphan tool-call synthesis)Volcengine Ark endpoints (Kimi-K3) treat empty-string
contentas missinginput.content.textand return 400.""(empty string)null" "(single space)"any text"Suggested fix
Change the empty-string fallback to a single space in all three locations:
A single space satisfies both xAI's "at least one content element" validator and Volcengine Ark's non-empty
content.textrequirement, without altering model semantics.Version
2.7.43-preview.20260728
Operating system
macOS (arm64, Darwin)