fix: 5 message-rendering bugs (frozen tool cards, diff OOM, CRLF, markdown)#132
Merged
Conversation
- MessageBubble: memo comparator only checked the last part's `.text`, which is always undefined for tool parts, so tool-state/token/cost updates never re-rendered when a tool part was last. Replace with a full reference-equality sweep over message + all parts (the store always replaces changed refs, so this catches every real change). - DiffView: computeDiff's O(a.length*b.length) LCS table was unbounded, risking OOM/ANR on large diffs, and the rendered line list was unbounded too. Add a size-guarded fallback (simple truncated remove/add diff) and cap the normal path's rendered lines, both with a truncation marker. Extracted computeDiff into a plain diff-compute.ts module (mirrors src/lib/scroll-config.ts) so it's unit-testable with node:test, which can't render .tsx components. - DiffView: normalize line endings (\r?\n) before diffing so a CRLF vs LF mismatch doesn't show a whole file as changed. - Markdown: the module-scope singleton CustomRenderer's github-slugger never reset, so useMarkdown's keys climbed on every streamed token, remounting the whole subtree. Scope the renderer per `children` via useMemo instead. - Markdown: theme objects used heading1/heading2/heading3/listItem, but react-native-marked's MarkedStyles expects h1/h2/h3/li, so the custom heading/list styling was silently dropped. Rename the keys in both themes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T12AhSnQVrSxNnvwfCx2z6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Five verified correctness bugs in the rendering path — where users see the agent's work. typecheck clean, 199 tests (2 new).
High impact
.text; tool parts have none, soundefined === undefinedmade every status change (running→done) and every output/diff arrival a no-op until an unrelated re-render. A user watching a bash/edit tool saw a spinner that never resolved. Now a reference sweep over all parts + the message.computeDiffbuilt an unboundedm×nLCS table and rendered every line unvirtualized — a multi-thousand-line edit (agents do whole-file rewrites) = ANR/crash. Now guarded (size caps + truncated fallback), logic extracted to a testeddiff-compute.ts.\rnormalization, so a CRLF-vs-LF mismatch made the LCS find zero matches and render the whole file red+green — misrepresenting the agent's edit. Now splits on/\r?\n/.Medium
4. Markdown used a module-singleton renderer whose slugger never reset → unstable React keys on every streamed token → subtree remounts (code-block scroll position reset, layout thrash). Now a fresh renderer per value.
5. Markdown theme keys (
heading1/listItem) didn't match the library's schema (h1/li), so custom heading sizes were dropped and## Headingrendered as oversized bordered GitHub-style headers inside chat bubbles. Renamed.🤖 Generated with Claude Code
https://claude.ai/code/session_01T12AhSnQVrSxNnvwfCx2z6