HTTP 400 Bad Request
{
"error": {
"message": "The `reasoning_content` in the thinking mode must be passed back to the API.",
"type": "invalid_request_error",
"param": null,
"code": "invalid_request_error"
}
}
Triggered when a multi-turn loop's PRIOR assistant message (the one carrying
tool_calls) is replayed to DeepSeek without its original reasoning_content
field.
Reproduction rate (probe_2, n=3, model=deepseek-v4-pro): 3/3 = 100%.
Important corollary: this bug fires ONLY when
thinkingis enabled (which is the default fordeepseek-v4-pro). If your client setsextra_body={"thinking":{"type":"disabled"}}it will never see this 400, but it also gives up the model's deep-reasoning behaviour.
| Source | What it says |
|---|---|
microsoft/agent-framework#5538 |
reasoning_content must be echoed back in tool-call loops |
NousResearch/hermes-agent#15353 |
tool-call message missing reasoning_content → 400 |
cline/cline PR #7888 |
adds addReasoningContent + isNextGenModelProvider list including DeepSeek — gold-standard fix |
cline/cline#8365, #8130 |
V3.2/V4 ALSO pack XML tool calls inside reasoning_content (cross-cuts §2) |
Probes: probe_2_reasoning_lifecycle phase B.
- The adapter MUST preserve the
reasoning_contentfield on every assistant message it receives from DeepSeek thinking-mode. - When the adapter re-sends an assistant message that has
tool_calls != nullAND the IMMEDIATELY-NEXT message in the request body hasrole == "tool", the assistant message MUST carry the originalreasoning_content. - Across user-turn boundaries (i.e. once a NEW message with
role == "user"arrives), the adapter SHOULD stripreasoning_contentfrom prior assistant messages, because:- the server does not require it across turns, AND
- keeping it bloats the prefix and breaks byte-for-byte cache equality (§4).
- Streaming chunks MAY contain
delta.reasoning_contenteven whendelta.contentis null. The adapter MUST NOT skip such chunks. - The terminal SSE chunk MAY have
choices == []and only carryusage. The adapter MUST tolerate this. (Cross-ref §5, cline #1594.)
src/deepseek_v4pro_kit/reasoning.py::ReasoningLifecycle and
normalize.prepare_for_new_user_turn.
probe_2's phase B is allowed to fail (we WANT the 400). If it stops failing,
we have evidence DeepSeek changed the contract — open an issue and re-spec.