Repository navigation
Description
Environment
- opencode version: 1.18.x (Windows 11, PowerShell terminal)
- Model:
deepseek-v4-flash(accessed via an OpenAI-compatible interface) - Access method: third-party relay/proxy service (OpenAI-compatible protocol)
Problem description
When using a relay/proxy, the model's reasoning content is not placed in the standard reasoning_content field. Instead, it is mixed directly into the content field and pushed with extremely fine granularity (1-4 characters per chunk), word by word.
opencode renders the beginning of the content stream (the reasoning text before the actual answer) as a Thought block. Because the granularity is so fine, this produces a spam of one Thought line per chunk, causing the terminal to scroll uncontrollably.
Steps to reproduce
- Configure an OpenAI-compatible relay provider and connect a reasoning-capable model (e.g.
deepseek-v4-flash) - Send a complex question that triggers deep reasoning
- Observe the TUI: during the reasoning phase, a large number of single-line
Thoughtindicators scroll by rapidly, spamming the screen
SSE evidence (raw captured data)
1. reasoning_content is empty in every chunk
Out of 2081 streamed chunks captured from the same request, 0 chunks carried a non-empty reasoning_content field:
data: {"id":"xxx-...","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning_content":"","function_call":null,"refusal":"","tool_calls":[]},"finish_reason":""}],"usage":null}2. Reasoning text is pushed word-by-word inside content
2079 non-empty content chunks, with the reasoning text cut into 1-4 character fragments:
data: {"id":"xxx-...","choices":[{"index":0,"delta":{"content":"这个","reasoning_content":"","..." }},"finish_reason":""}]}
data: {"id":"xxx-...","choices":[{"index":0,"delta":{"content":"问题","reasoning_content":"","..." }},"finish_reason":""}]}
data: {"id":"xxx-...","choices":[{"index":0,"delta":{"content":"涉及","reasoning_content":"","..." }},"finish_reason":""}]}
data: {"id":"xxx-...","choices":[{"index":0,"delta":{"content":"分布式","reasoning_content":"","..." }},"finish_reason":""}]}
...3. Chunk length statistics
- Total chunks: 2081
- Chunks with non-empty
reasoning_content: 0 - Non-empty
contentchunks: 2079 - Total
contentcharacters: 4438 - Average chunk length: 2.1 characters
- 93% of chunks are ≤ 4 characters long
4. Structure of the concatenated content
After concatenating all 2079 chunks, the content reads as: a reasoning preamble ("I will build the solution via ...") followed by the full answer. There is no protocol-level separator between the reasoning section and the actual answer (no reasoning_content, no thinking field), so opencode cannot distinguish between them.
Expected behavior
Reasoning content should be delivered via a standard field (e.g. OpenAI's reasoning_content / Anthropic's thinking), or there should be a recognizable boundary between the reasoning text and the answer inside the content stream. opencode should not misclassify the leading text of an ordinary content stream as a reasoning block and render it per chunk.
Impact
- Terminal spam, making the conversation unreadable
- The
/thinkingtoggle cannot hide these lines (it can only hide proper reasoning blocks; this content arrives via thecontentfield, so hiding has no effect) - No way to keep the model's reasoning ability while removing the visual noise
Notes
The root cause is likely the relay service's non-compliant passthrough of the upstream reasoning stream. At the same time, opencode's recognition/rendering strategy for reasoning text inside the content stream could be more robust (e.g. coalescing rendering when detecting a burst of consecutive high-frequency short chunks). Responsibility attribution is up to the opencode maintainers.
Attachments
- Full SSE capture file:
wb_stream2.txt(681KB, 2081 chunks) - Analysis script:
analyze_stream.py(paths contain no service-provider information)
Activity
github-actions commentedon Aug 6, 2026
This issue might be a duplicate of existing issues. Please check:
Jsliu28 commentedon Aug 7, 2026
补充证据:opencode 1.18.15 未合并 reasoning delta,每个 chunk 创建独立 part
在 issue #40865 基础上补充实测证据(来源:本地 opencode 1.18.15 + 数据库
opencode.db+ 抓包 + 二进制分析)。1. 数据库铁证:每条消息的 reasoning 被拆成几百个独立 part
会话
ses_028f25532ffel29lZXVCp1Z69W(普通对话)共 8412 个type: "reasoning"part,每条助手消息数百个:每个 part 只有 1-3 个字符,且为独立 part(各自 id、各自 time.start/end):
{"type": "reasoning", "text": "用户", "time": {"start": ..., "end": ...}} {"type": "reasoning", "text": "的", "time": {"start": ..., "end": ...}} {"type": "reasoning", "text": "的是", "time": {"start": ..., "end": ...}} {"type": "reasoning", "text": "为什么", "time": {"start": ..., "end": ...}}2. 抓包证据:流本身是干净的
对 workbuddy 中转(OpenAI 兼容)抓取的 SSE 流:
reasoning_contentchunk 连续出现,随后 660 个contentchunk3. 二进制证据:1.18.15 缺少 reasoning 合并逻辑
对
opencode.exe(1.18.15,178MB)二进制搜索:reasoning-delta/reasoning-start/reasoning_content/reasoning_textisActiveReasoning(AI SDK v6 中用于"同一 reasoning 区间只发一次 start"的合并标志)对照 AI SDK v6 源码
packages/openai-compatible/src/chat/openai-compatible-chat-language-model.ts:515-539:结论:opencode 1.18.15 打包的 AI SDK 为旧版本,缺少
isActiveReasoning去重。当上游(中转服务)以极细粒度(1-4 字符/chunk)推送reasoning_content时,每个 chunk 都被当作独立 reasoning 区间 → 创建独立 reasoning part → TUI 渲染为独立+ Thought块 → 刷屏。预期行为
无论上游 chunk 粒度多细,同一个流内的所有
reasoning_contentdelta 都应合并为一个 reasoning part(对应一个 Thought 块)。影响
reasoning_content的细粒度流都会刷屏/thinking折叠无效,因为每个块都是独立 part)建议修复
isActiveReasoning合并逻辑的版本(≥ 2.0.41)packages/opencode/src/session/processor.ts的reasoningMap)按 reasoning 区间合并,而非每个 delta 新建 partgithub-actions commentedon Oct 8, 2026
To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.