Reasoning that survives a model switch
Asking a model to think is one half of reasoning. The other half is what comes back: the model's reasoning, which arrives alongside its answer, and which some models need to see again on the next turn.
Our earlier post covered the first half, one setting for how much a model thinks. This one is about the second half, and about a conversation that starts on one model and continues on another. That conversation shouldn't break.
Four shapes for the same thing
Providers don't agree on how to return reasoning:
- DeepSeek, Kimi, MiMo and GLM put it in a
reasoning_contentfield on the message. - Groq and Cerebras put it in a bare
reasoningfield. - Claude returns thinking blocks, each with a signature, and sometimes a
redacted_thinkingblock instead. - OpenAI keeps reasoning on its side, and hands it out in encrypted form if you ask.
If your client reads one of these, it misses the others. That's annoying when you only want to show the reasoning. It matters more in an agent loop, because some models need their earlier reasoning back when they call a tool. Claude needs its thinking blocks on a tool-calling turn. DeepSeek, Z.AI, Moonshot and Xiaomi MiMo models need their reasoning back as reasoning_content across tool calls. Drop it, and the model carries on without its earlier reasoning.
Then the conversation moves. You start a task on one model, switch to another halfway through, or a fallback chain sends one turn somewhere else. The history now holds reasoning in the first provider's shape, and the next provider may not accept it.
One shape out, the provider's own kept
On /v1/chat/completions, the Tempr Gateway returns a model's reasoning as reasoning text and reasoning_details on the message, or on delta when streaming. That's the shape OpenRouter returns, and it's the same for every model.
Where a provider has its own field, such as reasoning_content, that field comes back too. A client written for DeepSeek's API keeps working, and a client written for OpenRouter's shape works on DeepSeek.
{
"role": "assistant",
"content": null,
"reasoning": "The test fails because the fixture is stale...",
"reasoning_details": [ ... ],
"reasoning_content": "The test fails because the fixture is stale...",
"tool_calls": [ ... ]
}To keep reasoning across a tool call, send the assistant message back with its reasoning_details unchanged. For Claude, Tempr turns them back into Claude's thinking blocks.
OpenAI's newest models are a special case. Tempr doesn't store responses, so when it bridges a request to OpenAI's Responses API it asks for the reasoning in encrypted form. That also comes back in reasoning_details, and goes back to OpenAI on the next request. The post on OpenAI's newest models explains the bridge.
Claude's signatures, kept intact
Claude Code and other clients built on Anthropic's SDK speak the Messages API, /v1/messages. Claude models on Anthropic pass straight through, so their thinking blocks are Anthropic's own.
Some Claude requests are translated rather than passed through: Claude on AWS Bedrock, and Anthropic models when a request asks for response caching. On those, Tempr keeps Claude's signature on each thinking block, and redacted thinking comes back as a redacted_thinking block. On Claude 4.7 and later the thinking text is empty, because Anthropic leaves it out by default, but the signature still holds the reasoning, so Tempr returns the block anyway. Send the blocks back unchanged, as Claude Code does, and Claude gets them on the next turn.
If Claude on Bedrock rejects a signature sent back in a later turn, Tempr retries once without that thinking instead of returning the error, as it does for Anthropic.
Other labs' reasoning as thinking blocks
When a Messages API request runs on a model outside Claude, such as DeepSeek, Z.AI, Moonshot or Xiaomi MiMo, its reasoning comes back as a thinking block ahead of the text and tool calls, with thinking_delta events when streaming. Claude Code sees reasoning the way it expects to.
These models don't sign their thinking, so Tempr gives the block the signature tempr:reasoning. Send it back unchanged and the model gets its text back as reasoning_content, which it needs across tool calls.
If a later turn goes to Claude, Tempr leaves those blocks out, because Claude would reject a signature it didn't write. Claude's own blocks stay. So a Claude Code session can move from Claude to DeepSeek and back without the history becoming something either side refuses.
Providers that reject what others send
Some providers are stricter than others about what an assistant turn can carry, and a conversation that has been on another model brings fields with it.
- Fireworks AI rejects some of the reasoning fields an earlier turn can carry. Tempr turns
reasoningintoreasoning_contentand removesreasoning_detailsbefore sending the request. - Mistral rejects them too, so Tempr removes
reasoning,reasoning_detailsandreasoning_contentfrom earlier turns. - Cerebras rejects fields such as prompt-cache markers, which a conversation that started on another model can carry. Tempr removes them before the request is sent.
In each case the request goes through instead of failing on history the new provider didn't write.
What doesn't carry over
Not every model's reasoning can travel. On the Messages API, a model that doesn't take its earlier reasoning back as reasoning_content doesn't get it. Its thinking is readable in the answer, but it isn't sent back, and the model answers the next turn reasoning afresh rather than failing.
And reasoning doesn't cross between labs. When a Messages API conversation moves from DeepSeek to Claude, Claude doesn't see DeepSeek's thinking, only the answers and tool calls. That's the price of a turn that works.
The details, field by field, are in the Reasoning and Messages API sections of the docs.