Conversation
…tory [skip release] Console Go (a DeepSeek-style gateway) rejected the next request with "The reasoning_content in the thinking mode must be passed back to the API": the assistant turns in the conversation carry the thinking a reasoning model produced, and the API demands it comes back verbatim. Kit streamed the reasoning live and then threw it away, and a resumed session lost it again at the store's message whitelist. The thought now rides the wire end to end, gated by a per-spoke declaration: - ModelReply and the stored ModelMessage keep the reply's reasoning text. - loop-core records it on the assistant message it introduces, and the session store's parseMessage carries it across resume. - chat.ts maps it onto the SDK message as a reasoning part (the openai- compatible adapter serializes that as reasoning_content) and reads it back from the response; toReply and toAiMessage are exported and unit tested. - Only the spokes whose adapters carry the part back declare it (reasoningEcho: custom, deepseek, local, nanogpt, openrouter, groq). Anthropic and Google need signature metadata they cannot reconstruct, openai chat-completions drops the part, and mistral would fold it into the visible text, so those stay silent by default. Tests: loop records reasoning for say and use replies, wire mapping for echoing and non-echoing spokes, and the declared set (mirrors the images capability test). verify:ci green; only the pre-existing Claude plan usage live tests hit their known Anthropic 429s. AI model: DeepSeek V4 Flash (via pi, a coding agent).
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2fafaaea84
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| role: "assistant", | ||
| content: reply.text, | ||
| toolCalls: reply.calls, | ||
| reasoning: reply.reasoning, |
There was a problem hiding this comment.
Preserve reasoning through the agent-window history
When using the Studio agent window with a reasoningEcho provider, recording reply.reasoning here is not enough: the browser posts follow-up history as only {role, content} in src/ui/agent/use-agent-chat.ts:190-198, and the server immediately rebuilds history the same way in src/ui/agent/turn-stream.ts:194-195. That means the next turn from the window still drops every prior assistant reasoning field before toAiMessage can emit reasoning_content, so DeepSeek-style backends continue to reject the follow-up/tool-loop history in the exact path this change is meant to fix.
Useful? React with 👍 / 👎.
Fixes an error from OpenAI-compatible thinking providers (seen on Console Go, a DeepSeek-style gateway):
Root cause. A reasoning model answers with
reasoning_contentbeside its content. DeepSeek-style backends REQUIRE that thinking to come back verbatim in the assistant turns of the next request; drop it and the API rejects the history. Kit streamed the thinking live (reasoning deltas) and then threw it away, and even where it was kept, the session store's message whitelist dropped it again on resume.Fix. The thought now rides the wire end to end, gated by a per-spoke declaration:
ModelReplyand the storedModelMessagekeep the reply's reasoning text;loop-corerecords it on the assistant message, and the session store'sparseMessagecarries it across resume.chat.tsmaps it onto the SDK message as a reasoning part (the openai-compatible adapter serializes that asreasoning_content) and reads it back from the response.reasoningEcho: custom, deepseek, local, nanogpt, openrouter, groq. Anthropic and Google need signature metadata a replica cannot reconstruct, openai chat-completions drops the part, and mistral would fold the thought into the visible text, so those stay silent by default (absent means no, matching theimagescapability pattern).Proof. Red-first: a reply's reasoning records into history (say and use), the wire mapper attaches the part only when the spoke declared the echo, and the declared set is pinned by a capability test mirroring
images.test.ts.verify:ciis green; the only failures across many runs are the pre-existing Claude plan usage live tests hitting Anthropic 429s. (One under-load run also showed a singlenot.toContainfailure that never reproduced across ten subsequent full-suite runs; the changed code is deterministic and was re-run 10x clean.)AI model: DeepSeek V4 Flash (via pi, a coding agent).