Skip to content

Bug report:TUI - final response missing after +Thought block (all reasoning models: DeepSeek/GLM/Qwen, Plan & Build mode) #37073

Closed as not planned

Description

@Start-Gao

Environment

  • opencode version: 1.17.20 (TUI & Desktop)
  • Models confirmed affected: deepseek-v4-pro, deepseek-v4-flash, glm-5.2, qwen3.6-plus-free (see Frequency table for sample sizes)
  • OS: Debian 13 (Linux 6.12.95) and Windows 11 (10.0.26200) — both confirmed
  • Terminal: SSH xterm-256color (Linux) / opencode Desktop (Windows)

Description

After a +Thought block completes, the final response text sometimes does not render at all. The TUI shows only the Thought block content and then the mode indicator (e.g. ▣ Plan · DeepSeek V4 Pro · 43.2s or ▣ Build · DeepSeek V4 Pro · 12.4s) with no summary text below it.

Database inspection confirms: the buggy turn has a reasoning part but no text part at all — the text part was never created. The text-start event appears to have never fired, so processor.ts never instantiated a TextPart.

Screenshot: see comments.

Steps to Reproduce

  1. Start opencode in TUI or Desktop mode
  2. Use a reasoning model (DeepSeek V4 Pro confirmed most affected) with thinking mode enabled
  3. Have a multi-turn conversation (the bug tends to appear after context accumulates — first observed occurrence ranged from turn 15 to turn 304 in different sessions)
  4. Some turns end with only the Thought block — no summary text is rendered after it

Frequency

Bug rate varies significantly by model, provider, and platform. Cross-platform data (Debian 13: 2 sessions, Windows 11: 70 sessions, 1211+ turns):

Platform Provider Model Mode Turns Bugs Bug rate
Debian 13 opencode-go deepseek-v4-pro build 27 9 33.3%
Debian 13 opencode-go deepseek-v4-pro plan 50 5 10.0%
Debian 13 opencode-go deepseek-v4-flash build 261 1 0.38%
Debian 13 opencode-go glm-5.2 build 15 1 6.7% (small sample)
Windows 11 opencode-go deepseek-v4-pro build 96 0 0.00%
Windows 11 opencode-go deepseek-v4-flash build 501 1 0.20%
Windows 11 deepseek (direct) deepseek-v4-pro build 105 5 4.76%
Windows 11 opencode qwen3.6-plus-free build 8 2 25.0% (small sample)

Key observations:

  • DeepSeek V4 Pro is the most affected model (up to 33.3% in Debian opencode-go+Pro+build); Flash is nearly immune (<0.4%)
  • Not limited to DeepSeek: GLM-5.2 and Qwen3.6-plus-free also triggered the bug (though with small sample sizes — noted as inconclusive)
  • All bug turns share: finish=stop + a reasoning part + no text part
  • Platform discrepancy for opencode-go+Pro: Debian 33.3% vs Windows 0% — same provider, same model, same opencode version (1.17.20). Root cause of the discrepancy is unknown (could be proxy routing, backend version, or other factors — not investigated)
  • The bug tends to appear after conversation context accumulates; it was not triggered in fresh short test sessions during reproduction attempts

Detection Method

Bug turns can be detected via SQLite query on opencode.db. The correct unit is the last assistant message of each turn (finish=stop with no later assistant message sharing the same parentID), not every intermediate message (intermediate reasoning → tool → step-finish sequences are normal tool-call steps, not bugs).

SELECT 
  json_extract(m.data,$.providerID) as provider,
  json_extract(m.data,$.modelID) as model_id,
  json_extract(m.data,$.agent) as mode,
  CASE WHEN EXISTS (SELECT 1 FROM part p 
    WHERE p.message_id=m.id AND json_extract(p.data,$.type)='text') 
    THEN 'ok' ELSE 'bug' END as ending,
  COUNT(*) as turn_count
FROM message m
WHERE json_extract(m.data,$.role)='assistant'
  AND json_extract(m.data,$.finish)='stop'
  AND json_extract(m.data,$.parentID) IS NOT NULL
  AND EXISTS (SELECT 1 FROM part p WHERE p.message_id=m.id AND json_extract(p.data,$.type)='reasoning')
  AND NOT EXISTS (
    SELECT 1 FROM message m2 
    WHERE json_extract(m2.data,$.parentID) = json_extract(m.data,$.parentID)
      AND m2.session_id = m.session_id
      AND m2.time_created > m.time_created
      AND json_extract(m2.data,$.role)='assistant')
GROUP BY 1, 2, 3, 4
ORDER BY 1, 2, 3, 4;

Root Cause Analysis

Source code review + database inspection findings:

  1. Not a TUI rendering bug: The text part is entirely absent from the database (0 empty text parts found in buggy sessions — the text part was never created, not created-empty-then-hidden). The TUI <Show when={props.part.text.trim()}> in TextPart correctly renders nothing because there is nothing to render.

  2. Not a processor.ts logic bug: processor.ts creates a TextPart immediately on text-start (yield* session.updatePart(ctx.currentText) at line 496). If text-start had fired, a text part would exist in the DB. Its absence means text-start never fired.

  3. The text-start event never fired: Tracing upstream — ai-sdk.ts emits text-start only when the AI SDK receives a non-null content delta from the provider response stream. If the provider response contained no content field (only reasoning_content), no text-start is emitted.

  4. Smoking gun evidence: Multiple buggy turns have reasoning content ending with a complete summary sentence (e.g. "简单说:配置、数据、日志全都沿用了原来的,和删除前的状态一致。" or "所以两平台的原始数据都可靠,issue 内容也是准确的,不需要重新检查。"), but no text part was emitted. The model appears to have written its full reply inside reasoning_content but did not emit it as content.

  5. Most likely root cause (not yet directly verified): The model, in finish=stop turns, sometimes outputs only reasoning_content without a content field. This could be model behavior, AI SDK stream parsing, or provider proxy behavior — the exact layer was not isolated because capturing raw API responses from the Bun-compiled opencode binary was not feasible with available tooling.

See the latest comment for the cross-platform verification details.

Activity

  1. Start-Gao commented on Jul 15, 2026

    @Start-Gao
    Author
    Image
  2. changed the title [-]TUI: Plan mode - final response missing after +Thought block (DeepSeek V4 Pro)[/-] [+]Bug report:TUI: Plan mode - final response missing after +Thought block (DeepSeek V4 Pro)[/+] on Jul 15, 2026
  3. Start-Gao commented on Jul 15, 2026

    @Start-Gao
    Author

    Cross-platform verification & root cause analysis

    Detection methodology

    The correct unit for counting this bug is the last assistant message of each turn (the finish=stop message with no later assistant message sharing the same parentID). Counting every intermediate reasoning → tool → step-finish message as a bug is wrong — those are normal tool-call steps where the model is still working and should not yet produce summary text.

    Field names matter: message-level model info is in $.modelID and $.providerID (not $.model).

    Cross-platform bug rates

    Debian 13 (2 sessions) + Windows 11 (70 sessions), 1211+ turns total:

    Platform Provider Model Mode Turns Bugs Bug rate
    Debian 13 opencode-go deepseek-v4-pro build 27 9 33.3%
    Debian 13 opencode-go deepseek-v4-pro plan 50 5 10.0%
    Debian 13 opencode-go deepseek-v4-flash build 261 1 0.38%
    Debian 13 opencode-go glm-5.2 build 15 1 6.7% (small sample)
    Windows 11 opencode-go deepseek-v4-pro build 96 0 0.00%
    Windows 11 opencode-go deepseek-v4-flash build 501 1 0.20%
    Windows 11 deepseek (direct) deepseek-v4-pro build 105 5 4.76%
    Windows 11 opencode qwen3.6-plus-free build 8 2 25.0% (small sample)

    Source code review findings

    • processor.ts (line 486-496): On text-start, a TextPart with empty text is created and immediately published via session.updatePart(). If text-start had fired, a text part (possibly empty) would exist in the database.
    • Database inspection: In all buggy sessions, 0 empty text parts were found. Buggy turns have reasoning parts but no text part at all — not an empty one, none. This means text-start never fired.
    • ai-sdk.ts (line 126-135): text-start is emitted only when the AI SDK receives a non-null content delta from the provider stream. No content delta → no text-start → no TextPart.
    • TUI TextPart component (session/index.tsx:1679): <Show when={props.part.text.trim()}> correctly hides empty text. This is not the bug — there is simply no text part to render.

    Smoking gun evidence

    Multiple buggy turns have reasoning content that ends with a complete summary sentence, but no text part was emitted:

    • Debian GLM-5.2 turn: reasoning ends with "...所以两平台的原始数据都可靠,issue 内容也是准确的,不需要重新检查。"
    • Debian DeepSeek Pro turn: reasoning ends with "...简单说:配置、数据、日志全都沿用了原来的,和删除前的状态一致。"
    • Windows Qwen3.6 turn: reasoning ends with a complete code analysis summary
    • Windows DeepSeek Pro turn: reasoning ends with "...commit→rebase→push→PR 刷新流程总结"

    The model wrote its full reply inside reasoning_content but did not emit it as content.

    What is confirmed vs. what is not

    Confirmed:

    • The bug exists on both Debian 13 and Windows 11
    • DeepSeek V4 Pro is the most affected (up to 33.3%)
    • Not isolated to one model family (GLM-5.2, Qwen3.6 also triggered, though small samples)
    • The text part is entirely absent — text-start never fired
    • processor.ts and TUI rendering logic are correct

    Not confirmed (would need raw API response capture):

    • Whether the model itself omits the content field, or the AI SDK drops it, or a proxy alters it
    • The exact cause of the Debian-vs-Windows discrepancy for opencode-go+Pro (33.3% vs 0%)

    Capturing raw API responses from the Bun-compiled opencode binary was attempted via NODE_OPTIONS=--require fetch hook, but the Bun binary does not honor NODE_OPTIONS. A plugin-based approach is possible but was out of scope for this report.

  4. changed the title [-]Bug report:TUI: Plan mode - final response missing after +Thought block (DeepSeek V4 Pro)[/-] [+]Bug report:TUI - final response missing after +Thought block (DeepSeek V4 Pro & Flash, Plan & Build mode)[/+] on Jul 15, 2026
  5. changed the title [-]Bug report:TUI - final response missing after +Thought block (DeepSeek V4 Pro & Flash, Plan & Build mode)[/-] [+]Bug report:TUI - final response missing after +Thought block (all reasoning models: DeepSeek/GLM/Qwen, Plan & Build mode)[/+] on Jul 15, 2026
  6. github-actions commented on Sep 14, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions