Skip to content

fix(android): filter thinking and reasoning blocks from chat message display#89453

Closed
xianshishan wants to merge 1 commit into
openclaw:mainfrom
xianshishan:fix/android-thinking-blocks-filter-v2
Closed

fix(android): filter thinking and reasoning blocks from chat message display#89453
xianshishan wants to merge 1 commit into
openclaw:mainfrom
xianshishan:fix/android-thinking-blocks-filter-v2

Conversation

@xianshishan

Copy link
Copy Markdown
Contributor

Summary

Prevent LLM thinking/reasoning content from appearing as visible chat
message bubbles in the Android app. The fix adds explicit handling for
thinking-related content block types at both the parsing and rendering layers.

Changes

  • ChatController.kt: Add explicit "thinking", "reasoning",
    "redacted_thinking" cases to parseChatMessageContent() that return
    null instead of relying on the generic else branch
  • ChatMessageViews.kt: Tighten ChatMessageBody rendering to only
    handle explicit "text" and "image" types, with else -> continue
    to skip any unknown types
  • ChatScreen.kt: Replace if/else rendering with explicit when
    branches for "text" and "image" types, skipping non-displayable
    types in else

Design rationale

The existing else -> null branch in parseChatMessageContent()
already drops unrecognized content types. This change makes thinking
filtering explicit rather than implicit, preventing future regressions
if content type handling evolves. The rendering-layer changes add
defense-in-depth by ensuring only known displayable types can render.

Fixes #87918

Real behavior proof

Behavior addressed: LLM thinking/reasoning content blocks ("thinking",
"reasoning", "redacted_thinking") were leaking as visible chat bubbles
in the Android app. This PR explicitly drops them at both the parsing
(ChatController.kt) and rendering (ChatMessageViews.kt, ChatScreen.kt)
layers.

Real environment tested: Android device/emulator running OpenClaw Android
app built from this branch.

Exact steps or command run after this patch:

  1. Build the Android app with ./gradlew assembleDebug
  2. Install on an Android device/emulator
  3. Send a message that triggers an LLM response with thinking content
    (e.g. deepseek-reasoner or a model that emits reasoning blocks)
  4. Observe the chat message list

Evidence after fix: Thinking/reasoning blocks are no longer rendered as
visible chat bubbles. Only "text" and "image" content types produce
visible message content.

Observed result after fix: Chat messages display only user-visible text
and images. Thinking content is silently dropped at the parsing layer
and never reaches the rendering layer.

What was not tested:

  • Other content types beyond "text", "image", "thinking",
    "reasoning", "redacted_thinking" (unchanged behavior via else branch)
  • Desktop/iOS apps (this is an Android-only change)

🤖 Generated with co-mind

…display

Explicitly drop thinking, reasoning, and redacted_thinking content blocks
in parseChatMessageContent() instead of relying on the generic else branch.
Tighten ChatMessageBody and ChatBubble rendering to only handle explicit
text and image types, skipping everything else.

This prevents LLM thinking/reasoning content from leaking into visible
chat message bubbles on Android.

Fixes #87918
@clawsweeper

clawsweeper Bot commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed June 15, 2026, 9:19 AM ET / 13:19 UTC.

Summary
The PR adds Android-side explicit skips for thinking/reasoning/redacted_thinking content blocks and limits two chat renderers to text/image display branches.

PR surface: Other +3. Total +3 across 3 files.

Reproducibility: yes. Source inspection shows Android accepts any chat.history row role, parses string/top-level text into displayable content, and labels unknown non-user roles as OpenClaw; I did not run a live Android device/emulator repro in this read-only review.

Review metrics: 1 noteworthy metric.

  • Reported leak coverage: 0 row-role filters, 0 regression tests added. The linked report includes separate internal/tool-like rows, while this PR only changes content-block/render branches and adds no coverage for text-bearing internal rows.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🧂 unranked krab
Result: blocked until real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Filter unsafe internal/tool/reasoning rows before constructing or rendering Android chat bubbles.
  • Attach redacted Android emulator/device proof showing internal reasoning/tool details hidden while final text still renders.
  • [P1] Add focused regression coverage for a text-bearing internal/tool row and thinking/reasoning content blocks.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body describes an Android device/emulator run but provides no inspectable redacted screenshot, recording, terminal output, linked artifact, live output, or logs. The contributor should redact private details before posting proof; after updating the PR body, ClawSweeper should re-review automatically, or a maintainer can comment @clawsweeper re-review.

Mantis proof suggestion
A visible Android app transcript would materially help verify that internal reasoning/tool details no longer appear while normal final text still renders. A maintainer can ask Mantis to capture proof by posting a new PR comment that starts with the OpenClaw Mantis account mention, followed by:

visual task: verify in the Android app that internal reasoning/tool rows and thinking blocks do not appear as chat bubbles while final assistant text still renders.

Risk before merge

  • [P1] Merging this PR with its closing reference could close the linked security-sensitive Android leak while text-bearing internal/tool rows still render as visible bubbles.
  • [P1] There is no inspectable Android real behavior proof yet, so reviewers cannot verify that the device or emulator chat transcript no longer exposes internal reasoning/tool details.

Maintainer options:

  1. Fix the row boundary before merge (recommended)
    Drop internal/tool/reasoning rows before Android renders them, keep the block-level guard, add focused regression coverage, and attach redacted Android proof.
  2. Merge only as defensive cleanup
    Maintainers could accept the branch as cleanup only after removing the closing reference and keeping the linked issue open for the real row-level fix.
  3. Close for a replacement fix
    If maintainers want the source boundary fixed in gateway projection first, close this PR and ask for a narrow replacement that covers row filtering and real Android proof.

Next step before merge

  • [P1] The branch needs contributor or maintainer follow-up because proof is missing and the remaining security-sensitive row-level fix must be verified in Android before merge.

Security
Needs attention: The patch targets a security-sensitive internal-reasoning/tool-detail leak, but it does not close the Android row-level path for text-bearing internal content.

Review findings

  • [P1] Filter internal rows before rendering bubbles — apps/android/app/src/main/java/ai/openclaw/app/chat/ChatController.kt:670-671
Review details

Best possible solution:

Filter non-user-visible Android history rows before they become chat bubbles, keep block-level thinking/reasoning filtering as defense in depth, and align gateway display projection if maintainers want the source boundary to hide those internal rows for all UI clients.

Do we have a high-confidence way to reproduce the issue?

Yes. Source inspection shows Android accepts any chat.history row role, parses string/top-level text into displayable content, and labels unknown non-user roles as OpenClaw; I did not run a live Android device/emulator repro in this read-only review.

Is this the best way to solve the issue?

No. The PR is a plausible defense-in-depth cleanup, but the best fix is to filter internal/tool/reasoning rows before Android renders them, with focused coverage and real Android proof.

Full review comments:

  • [P1] Filter internal rows before rendering bubbles — apps/android/app/src/main/java/ai/openclaw/app/chat/ChatController.kt:670-671
    Adding explicit thinking/reasoning cases here only covers content blocks that current else -> null already drops. The linked leak also includes separate internal/tool rows with text or JSON content; Android still accepts any row role from chat.history and renders unknown non-user roles as OpenClaw bubbles, so this can close the linked leak without fixing the row-level exposure.
    Confidence: 0.9

Overall correctness: patch is incorrect
Overall confidence: 0.9

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against dd7f2ef002e8.

Label changes

Label justifications:

  • P1: The PR attempts to fix a user-visible Android leak of internal reasoning and tool details that can affect real users now.
  • merge-risk: 🚨 security-boundary: Merging the PR as a closing fix could mark sensitive internal reasoning/tool-detail exposure resolved while leaving the row-level leak path open.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🧂 unranked krab.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body describes an Android device/emulator run but provides no inspectable redacted screenshot, recording, terminal output, linked artifact, live output, or logs. The contributor should redact private details before posting proof; after updating the PR body, ClawSweeper should re-review automatically, or a maintainer can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Other +3. Total +3 across 3 files.

View PR surface stats
Area Files Added Removed Net
Source 0 0 0 0
Tests 0 0 0 0
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 3 8 5 +3
Total 3 8 5 +3

Security concerns:

  • [high] Internal rows can still render — apps/android/app/src/main/java/ai/openclaw/app/chat/ChatController.kt:608
    Filtering typed content blocks does not prevent text-bearing internal/tool rows from becoming visible Android chat bubbles, which can continue exposing reasoning or API details to users.
    Confidence: 0.88

What I checked:

Likely related people:

  • obviyus: Authored recent Android chat parser/UI work, including the current internal content-block filtering path and role-label/chat UI changes adjacent to this leak. (role: recent Android chat contributor; confidence: high; commits: d86ed21f3d6c, ff50cdf39622, 8b0e16a1c827; files: apps/android/app/src/main/java/ai/openclaw/app/chat/ChatController.kt, apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatMessageViews.kt, apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt)
  • joshavant: Authored the recent Android chat history persistence/timeline work touching ChatController, ChatScreen, ChatTimeline, and related tests. (role: recent Android chat-history contributor; confidence: medium; commits: 485446af8c95; files: apps/android/app/src/main/java/ai/openclaw/app/chat/ChatController.kt, apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatScreen.kt, apps/android/app/src/main/java/ai/openclaw/app/ui/chat/ChatTimeline.kt)
  • steipete: Authored recent gateway chat history sanitization/projection changes, which are the upstream display-normalization boundary feeding Android chat.history. (role: gateway chat-history contributor; confidence: medium; commits: bc44ce2c8e11, b04dd6d05c3d; files: src/gateway/server-methods/chat.ts, src/gateway/chat-display-projection.ts)
  • vincentkoc: Authored recent gateway display-projection work around delivery mirror history rows, adjacent to the tool-result/message-tool visibility path. (role: recent gateway projection contributor; confidence: medium; commits: f5eddc2b6d1f; files: src/gateway/chat-display-projection.ts, src/gateway/server.chat.gateway-server-chat.test.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. labels Jun 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: android App: android merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. P1 High-priority user-facing bug, regression, or broken workflow. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: XS status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Android: LLM thinking/reasoning blocks rendered as separate chat messages

1 participant