← Back to PRs

#16733: fix(ui): avoid injected newlines when tool output is hidden

by jp117 open 2026-02-15 02:16 View on GitHub →
app: web-ui stale size: XS
## Summary - Problem: assistant text in the web UI gets split by an extra newline when thinking/tool output is hidden and content is segmented. - Why it matters: chat output formatting changes based on thinking toggle state. - What changed: in `extractText`, assistant text blocks are concatenated without forced newline insertion; added regression test. - What did NOT change (scope boundary): no protocol, routing, backend, or tool execution behavior changes. ## Change Type (select all) - [x] Bug fix ## Scope (select all touched areas) - [x] UI / DX ## Linked Issue/PR - Closes #16636 ## User-visible / Behavior Changes Assistant messages no longer gain artificial line breaks around hidden tool output blocks. ## Security Impact (required) - New permissions/capabilities? (No) - Secrets/tokens handling changed? (No) - New/changed network calls? (No) - Command/tool execution surface changed? (No) - Data access scope changed? (No) ## Repro + Verification ### Environment - OS: macOS - Runtime/container: Node 24 / pnpm - Model/provider: N/A - Integration/channel (if any): Control UI web chat - Relevant config (redacted): thinking/working output toggle off ### Steps 1. Render assistant message content containing text, tool block, text. 2. With thinking/tool output hidden, view assistant text. 3. Confirm no artificial newline is inserted between text blocks. ### Expected - Assistant text renders continuously unless newline is present in original text. ### Actual - Before fix, a newline was injected between text blocks (`"Hello \nworld"`). ## Evidence - [x] Failing test/log before + passing after ## Human Verification (required) - Verified scenarios: new regression case in `ui/src/ui/chat/ message-extract.test.ts` plus targeted and full test runs. - Edge cases checked: non-assistant join behavior unchanged. - What you did **not** verify: manual browser walkthrough on all providers/channels. ## Compatibility / Migration - Backward compatible? (Yes) - Config/env changes? (No) - Migration needed? (No) ## Failure Recovery (if this breaks) - How to disable/revert this change quickly: revert this commit. - Files/config to restore: `ui/src/ui/chat/message-extract.ts`, `ui/src/ui/chat/message-extract.test.ts` - Known bad symptoms reviewers should watch for: unexpected spacing differences in assistant message rendering. ## Risks and Mitigations - Risk: assistant text concatenation could alter spacing in rare segmented-message cases. - Mitigation: regression test added; all local checks and tests pass. AI-assisted: Yes Testing level: Fully tested locally (`pnpm check`, `pnpm protocol:check`, `pnpm test`). first attempt at contributing to openclaw, if this is not the correct way to do it, please let me know. <!-- greptile_comment --> <h3>Greptile Summary</h3> This PR fixes an issue where assistant text in the web UI gained artificial newlines when thinking/tool output was hidden and the message content was segmented into multiple text blocks separated by tool blocks. - **Core fix** (`message-extract.ts`): Changes `parts.join("\n")` to `parts.join("")` for assistant role messages, preventing injected newlines between text blocks. Non-assistant messages retain the original `"\n"` join behavior. - **Inlined `stripEnvelope`**: The import from the shared module `src/shared/chat-envelope.js` was replaced with a local implementation in the UI. However, the inlined `ENVELOPE_CHANNELS` list is **missing `"Google Chat"`** — this entry is present in the original shared module and in `src/gateway/chat-sanitize.ts`. - **Removed `stripDirectiveTags`**: The UI-side stripping of `[[reply_to_current]]`, `[[reply_to:<id>]]`, and `[[audio_as_voice]]` directive tags was removed. These tags are processed server-side in the auto-reply pipeline, so this is likely safe but worth verifying that stored transcripts don't contain raw directive tags. - **Test deflake** (`gateway-lock.test.ts`): The "proc access fails" test case was simplified to use real timers with short timeouts instead of fake timers, reducing CI flakiness. - **Regression test**: A new test validates the newline fix for assistant messages with interleaved tool blocks. <h3>Confidence Score: 3/5</h3> - PR is mostly safe but has a missing channel entry in the inlined envelope stripping logic that could cause a minor UI rendering regression for Google Chat users. - The core newline fix is correct and well-tested. However, the inlined `ENVELOPE_CHANNELS` array drops "Google Chat" which exists in the original shared module and the gateway's chat-sanitize.ts. This is a data loss bug that could cause envelope prefixes to render visibly for Google Chat channel messages. The `stripDirectiveTags` removal is likely safe but adds some uncertainty. The gateway-lock test deflake changes are reasonable. - Pay close attention to `ui/src/ui/chat/message-extract.ts` — the inlined `ENVELOPE_CHANNELS` is missing "Google Chat" compared to the authoritative copies in the codebase. <sub>Last reviewed commit: 7be5f96</sub> <!-- greptile_other_comments_section --> <sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub> <!-- /greptile_comment -->

Most Similar PRs