You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Messages carrying both reasoning and reasoning_content are rejected with 400 #46
/v1/chat/completions rejects a message that carries both reasoning and reasoning_content, with
{"error": "Use one reasoning field per message"}
Either field on its own is accepted. This makes the server unusable for multi-turn clients that replay assistant reasoning on every carrier they know about — such a client works for the first turn and then fails on every turn afterwards.
Steps to reproduce
Server running (rec status → ready, 0.1.1, flint-int4).
Plain request works:
curl -s http://127.0.0.1:11500/v1/chat/completions \
-H "Authorization: Bearer $(rec auth token)" -H 'Content-Type: application/json' \
-d '{"model":"flint","messages":[{"role":"user","content":"hi"}],"max_tokens":8}'
→ 200, message.reasoning = "Hmm, the user just said ..."
reasoning only → 200. reasoning_content only → 200. Both → 400:
curl -s http://127.0.0.1:11500/v1/chat/completions \
-H "Authorization: Bearer $(rec auth token)" -H 'Content-Type: application/json' \
-d '{"model":"flint","max_tokens":8,"messages":[
{"role":"user","content":"hi"},
{"role":"assistant","content":"ok","reasoning":"t","reasoning_content":"t"}]}'
{"error": "Use one reasoning field per message"}
Why it matters
Local OpenAI-compatible servers disagree about the replay carrier: llama.cpp/SGLang read reasoning_content, vLLM/Ollama read reasoning. Harnesses therefore send both (Hermes Agent does exactly this for any localhost endpoint), and every other server tested simply ignores the key it does not read. A 400 here turns a benign extra key into a hard failure that only appears from turn 2 onwards, so it reads as "the model is broken" rather than "the request shape is rejected".
The message also does not name the offending field, so clients that recover from strict-schema 400s by dropping the named key have nothing to match on.
Expected
Per OpenAI-compat convention, accept the message and pick one field (e.g. prefer reasoning, ignore the alias) — or ignore unknown message keys. If you prefer to keep the check, naming the field (reasoning / reasoning_content) would at least let clients drop it and retry.
Environment
rec 0.1.1, model flint (flint-int4), context 262144
macOS 27.0.1, Apple M5 Max, 128 GiB
Client: Hermes Agent 0.22.5 (chat_completions, replays both carriers to localhost endpoints)
Thanks for reporting this. I reproduced the 400 and opened #52. It accepts either alias and normalizes once; when both are present, reasoning takes precedence by field presence, including empty/null values. The focused suite passed 38 tests, including equal/different aliases and both response modes. This has not shipped yet, and I have not claimed a full Hermes end-to-end run.
Activity
strin commentedon Nov 5, 2026
Thanks for reporting this. I reproduced the 400 and opened #52. It accepts either alias and normalizes once; when both are present, reasoning takes precedence by field presence, including empty/null values. The focused suite passed 38 tests, including equal/different aliases and both response modes. This has not shipped yet, and I have not claimed a full Hermes end-to-end run.