fix(chat): don't apply hard-break newlines to AI-streamed messages#385
fix(chat): don't apply hard-break newlines to AI-streamed messages#385FelipeRamos-neuro wants to merge 1 commit into
Conversation
The blanket `.replace(/\n/gi, ' \n')` in the chat message renderer ran over every message, not just user input as the comment intended. Since it's a raw string transform applied before markdown parsing, it injected trailing double-spaces into every line of AI-streamed fenced code blocks, corrupting copy-pasted code with invisible trailing whitespace. Scope the hard-break transform to user messages only.
pjdoland
left a comment
There was a problem hiding this comment.
Thanks for this, and nice root-cause writeup in #384. The trailing-whitespace-in-code-blocks bug is real and worth fixing: injecting \n before markdown parsing does corrupt copied code.
I think the sender-based scoping trades one bug for another, though, because the real axis here is code-fence context rather than who sent the message:
-
Regression for AI prose.
MarkdownRendereruses onlyremarkGfm(noremark-breaks), so once the hard-break transform no longer applies to AI messages, single newlines in AI output become CommonMark soft breaks and collapse to spaces. Plain-text AI output that separates lines with single newlines (not blank lines or list syntax) now renders run-on:First point\nSecond pointshows asFirst point Second pointon one line, where it used to be two. It is lower-frequency since most model output is well-formed markdown, but it is a real visible change, and it would not show up in the code-block repro. -
The same bug still hits user-pasted code. The
.replacestill runs on user messages, so if a user pastes a fenced code snippet, every line still gets trailing double-spaces. Scoping by sender only fixes the AI direction.
Both of these go away if the transform is markdown-aware instead of a pre-parse string replace. The cleanest fix is to drop the .replace entirely and add remark-breaks to remarkPlugins in markdown-renderer.tsx alongside remarkGfm. remark-breaks converts soft breaks to hard breaks at the AST level, so it respects code fences (no corruption for AI or user code) while preserving intended line breaks in all prose. That resolves the run-on regression and the user-code case in one move, and removes the string hack. It does add remark-breaks as a dependency, but it is a standard, tiny remark plugin.
Would you be up for switching to that approach? Happy to help if anything is unclear.
Summary
Fixes #384
src/chat-sidebar.tsx:891) applied a blanket.replace(/\n/gi, ' \n')hard-break transform to every rendered message, not just user input as the adjacent comment intended.msg.from === 'user'only, matching the comment's stated intent. AI-streamed messages already contain well-formed markdown and don't need the hack.See #384 for the full root-cause writeup and reproduction.
Test plan
react-markdown@9.0.1+remark-gfm@4.0.0: AI-message code blocks no longer carry trailing whitespace on any line, while user-message hard breaks are preserved🤖 Generated with Claude Code