Skip to content

fix(oaistream): replay ReasoningContent when converting messages - #4485

Open
MysticalMount wants to merge 1 commit into
docker:mainfrom
MysticalMount:fix/reasoning-content-oaistream-v2
Open

MysticalMount wants to merge 1 commit into
docker:mainfrom
MysticalMount:fix/reasoning-content-oaistream-v2

Conversation

@MysticalMount

@MysticalMount MysticalMount commented Sep 30, 2026 •

Copy link
Copy Markdown

Fixes #4363

Supersedes #4365 (re-based onto current main with signed commits, extended so reasoning-only assistant messages are no longer dropped as empty).

Root cause

convertMessagesWithCaps in pkg/model/provider/oaistream/messages.go built the outgoing assistant message param from Content, FunctionCall, and ToolCalls only. msg.ReasoningContent was never read, so reasoning captured from OpenAI-compatible custom providers (e.g. Qwen via llama.cpp, vLLM) was silently dropped when the conversation history was replayed on the next request.

The same assistant-turn skip predicate also dropped messages that contain only reasoning (no text, no tool calls — e.g. a model that exhausted its output budget mid-reasoning) before conversion ever saw them.

Fix

  • Attach stored reasoning to the replayed assistant message via SetExtraFields — openai-go's typed ChatCompletionAssistantMessageParam has no field for reasoning_content (non-standard, provider-specific extension; see can @chatcompletion.go support reasoning_content? openai/openai-go#558). Nothing is added when the stored history contains no reasoning.
  • Keep reasoning-only assistant messages instead of skipping them as empty.

Compatibility note

reasoning_content is only serialized when a stored message actually carries reasoning. Since this path serves many OpenAI-compatible endpoints (xAI, Mistral, Groq, OpenRouter, DeepSeek, ...), a session that accumulates reasoning on one endpoint will send the field when later routed to any other endpoint through this provider. If a specific endpoint is known to reject unknown fields, preservation could be made per-model opt-out via the existing capability-override mechanism (as the issue itself suggested) — happy to add that as a follow-up if maintainers prefer.

Testing

Added repro_issue4363_test.go covering: reasoning is carried onto the replayed message, no field is added when reasoning is absent, reasoning survives alongside tool calls, and a reasoning-only assistant message survives conversion.

@MysticalMount
MysticalMount requested a review from a team as a code owner September 30, 2026 07:43
@aheritier aheritier added area/providers/openai For features/issues/fixes related to the usage of OpenAI models kind/fix PR fixes a bug (maps to fix:). Use on PRs only. labels Sep 30, 2026
OpenAI-compatible custom providers (e.g. Qwen served via llama.cpp, vLLM,
or other endpoints using the DeepSeek-style reasoning_content convention)
have their streamed reasoning captured into msg.ReasoningContent, but
convertMessagesWithCaps built the outgoing assistant param from Content,
FunctionCall, and ToolCalls only -- the stored reasoning was silently
dropped when the conversation history was replayed on the next request.

openai-go's typed ChatCompletionAssistantMessageParam has no field for
reasoning_content (non-standard extension -- see openai/openai-go#558), so
it is attached via SetExtraFields when present; nothing is added when the
history contains no reasoning. The assistant-turn skip predicate is also
taught to keep reasoning-only messages (e.g. a model that exhausted its
output budget mid-reasoning) instead of dropping them as empty.

Fixes docker#4363

Signed-off-by: Jay <12496124+MysticalMount@users.noreply.github.com>
@MysticalMount
MysticalMount force-pushed the fix/reasoning-content-oaistream-v2 branch from ab8d68a to 15d5b95 Compare September 30, 2026 08:10

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/providers/openai For features/issues/fixes related to the usage of OpenAI models kind/fix PR fixes a bug (maps to fix:). Use on PRs only.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenAI custom provider does not send reasoning from previous turns

2 participants