fix(chat): stop leftover * and _ at the end of finished replies - #487
Merged
xintaofei merged 5 commits intoSep 1, 2026
Merged
Conversation
Adam-Dalloul
force-pushed
the
fix/streamdown-trailing-emphasis
branch
2 times, most recently
from
August 21, 2026 17:39
316128b to
4d3a439
Compare
Streamdown defaults to mode=streaming, so remend ran on every completed assistant bubble. remend 1.2.0 then appended a closer after globs like `foo/*` and `_meta` / `_blank`. Default finished markdown to static and only remend the live streaming turn.
Adam-Dalloul
force-pushed
the
fix/streamdown-trailing-emphasis
branch
from
August 28, 2026 18:30
73c0e98 to
d2708fb
Compare
Finished markdown going static is right, but ReasoningContent was pinned there unconditionally — and Reasoning auto-opens the panel the moment the model starts thinking, so it re-renders on every delta of a block that routinely runs to thousands of tokens. Static re-parses the whole text each time instead of only the tail block: measured 5897ms vs 2067ms over 120 growing deltas, and the gap widens with length. Track the turn there too, the way the reply prose already does. Also fold the two mode/parseIncompleteMarkdown defaults into shared constants so the impl default and the memo comparator cannot drift apart, and record which half of the fix actually repaints — Streamdown's own memo compares `mode` and not `parseIncompleteMarkdown`, so at the live to finished flip only the mode change forces the remended DOM off screen. The final-fence regression waited on a 400ms wall clock; anchor it on the code block's content instead, which is what the stray closer would be part of anyway.
Owner
|
codeg work task |
Only completed-turn-content.tsx conflicted. Main's 73e96ac rewrote the exact region this branch had patched: the single early return that used to catch every live reply became a `foldable` predicate plus per-round fold state. Took main's structure wholesale — this branch has no stake in the fold logic — and re-applied its own intent on top. That re-application is not the one-line patch it was. Under the old shape `!completed` always took the early return, so the progress and answer renderers below it were provably settled and needed nothing. Main's `foldable` disjunct (`!completed || hasVisibleAnswer(...)`) drops a live reply that has already made a tool call into the fold branch instead, so both halves now render growing text and both need to be told so. Hence a named `isStreaming` passed at every renderer in the component rather than at one of them. completed-turn-streaming-mode.test.tsx pins that: a live foldable reply renders both halves streaming, a settled one static. Dropping the flag from the two fold-branch sites fails it.
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.
Finished assistant replies were showing a stray
*or_at the end. Not the model. Streamdown defaults tomode="streaming", so remend ran on every completed bubble. remend 1.2.0 then appends a closer after a glob like`foo/*`or`_meta`/_blank.Finished markdown now stays
mode="static". Only the live streaming turn still remends. Reasoning and file previews are static too.Any agent that writes those shapes could hit this. Grok just does it a lot.
Also fixes #555. That report looked like a separate code-fence parser bug: a reply ending exactly at a closing fence rendered
_ ``` as a line inside the block. Same cause. The appended_lands after the final fence, the fence stops closing, and the backticks become code content. Added a regression test for that shape (`message-final-fence.test.tsx`).Measured truth table on the exact reply from #555, driving
MessageResponseunder vitest:_ ``` inside the blockBoth defaults have to be at the bad value to reproduce, so either half of this PR is enough; it ships both.
Independent of the other open PRs. One concern.