perf(desktop): incremental markdown rendering during streams

Re-parsing the full message markdown every reveal frame is O(N^2) over a
long answer and dominated stream CPU.

- Throttle useSmoothReveal commits to ~1 frame (REVEAL_MIN_COMMIT_MS).
- Memoize block parsing with an LRU keyed on source text so only changed
  blocks re-parse.
- Replace Streamdown's full-text parseIncompleteMarkdown with a
  tail-bounded remend: scan to the last top-level boundary outside
  fences/math and repair only the trailing open block. New remend-tail.ts
  is proven render-equivalent to full remend at every streaming prefix
  (remend-tail.test.ts), minus an intentional, documented divergence on
  cross-block dangling openers.
This commit is contained in:
Brooklyn Nicholson
2026-06-12 21:07:36 -05:00
parent 7c226cc57f
commit edc36f3a45
5 changed files with 300 additions and 11 deletions
+105
View File
@@ -0,0 +1,105 @@
import { parseMarkdownIntoBlocks } from '@assistant-ui/react-streamdown'
import remend from 'remend'
import { describe, expect, it } from 'vitest'
import { findRemendWindowStart, tailBoundedRemend } from './remend-tail'
const CORPUS = `# Heading one
Intro paragraph with **bold**, *italic*, \`inline code\`, and a [link](https://example.com).
## Code
\`\`\`python
def main():
cost = "$5"
print(f"total: $\{cost}")
\`\`\`
Some text after the fence with $x^2 + y^2$ inline math.
$$
\\int_0^1 f(x) dx
$$
- list item one with **bold**
- list item two
| col a | col b |
| ----- | ----- |
| 1 | 2 |
~~~js
const s = \`template \${value}\`
~~~
Final paragraph with ~~strike~~ and unfinished [link text](https://exa
`
/**
* Render-equivalence oracle: full-text remend and tail-bounded remend may
* differ in raw string output ONLY in ways that cannot affect rendering —
* i.e. after block splitting, every block must be identical. (Streamdown
* renders blocks independently, so block-level equality IS render equality.)
*/
function blocksOf(text: string): string[] {
return parseMarkdownIntoBlocks(text)
}
describe('tailBoundedRemend', () => {
it('matches full remend block output at every streaming prefix', () => {
for (let end = 1; end <= CORPUS.length; end++) {
const prefix = CORPUS.slice(0, end)
const full = blocksOf(remend(prefix))
const tail = blocksOf(tailBoundedRemend(prefix))
expect(tail, `prefix length ${end}: ${JSON.stringify(prefix.slice(-60))}`).toEqual(full)
}
})
it('repairs an unclosed fence opened early in a long message', () => {
const text = `intro\n\n\`\`\`python\n${'x = 1\n'.repeat(500)}print("$dollar")`
const repaired = tailBoundedRemend(text)
expect(blocksOf(repaired)).toEqual(blocksOf(remend(text)))
// the window must reach back to the fence opener
expect(findRemendWindowStart(text)).toBe(text.indexOf('```python'))
})
it('bounds the window to the tail paragraph when no fence is open', () => {
const text = `para one\n\npara two\n\npara three with **bold`
const start = findRemendWindowStart(text)
expect(start).toBe(text.indexOf('para three'))
expect(tailBoundedRemend(text)).toBe(remend(text))
})
it('widens the window across an open $$ math block', () => {
const text = `before\n\n$$\n\\frac{a}{b}`
const start = findRemendWindowStart(text)
expect(start).toBeLessThanOrEqual(text.indexOf('$$'))
expect(blocksOf(tailBoundedRemend(text))).toEqual(blocksOf(remend(text)))
})
it('handles closed constructs without modification', () => {
const text = `done **bold** and \`code\`\n\n\`\`\`js\nconst a = 1\n\`\`\`\n\nlast line.`
expect(tailBoundedRemend(text)).toBe(text)
})
it('intentionally diverges from full remend on cross-block dangling openers', () => {
// Full remend scans the whole document and appends `**` for an opener
// left dangling in an EARLIER block, dumping stray asterisks into the
// unrelated tail block ("|**"). Because Streamdown splits into blocks
// after the repair, that opener never renders as bold either way — the
// tail-bounded result is the cleaner of the two. This test documents
// the divergence so a future remend upgrade that changes the behavior
// gets noticed.
const text = `- item with **dangling\n- item two\n\n|`
expect(remend(text).endsWith('|**')).toBe(true)
expect(tailBoundedRemend(text).endsWith('|')).toBe(true)
expect(tailBoundedRemend(text).endsWith('|**')).toBe(false)
})
})
+108
View File
@@ -0,0 +1,108 @@
import remend from 'remend'
// Tail-bounded incomplete-markdown repair.
//
// Streamdown's built-in `parseIncompleteMarkdown` runs `remend` over the whole
// accumulated message on every streaming flush (~18% of script time on 50KB+
// messages). But repairs only ever matter in the trailing block: inline
// constructs can't cross a blank line, and Streamdown splits into blocks AFTER
// the repair, so a dangling opener in an earlier block can't reach the tail.
// We run `remend` on just that block instead.
const BACKTICK = 96 // `
const TILDE = 126 // ~
const SPACE = 32
const TAB = 9
const BACKSLASH = 92
const isSpace = (c: number) => c === SPACE || c === TAB
/**
* Index of the last top-level block start — the char after the most recent
* blank line that sits outside any open code fence or `$$` math block. An
* unclosed fence/math always begins after that blank, so it stays wholly
* inside the window without separate tracking. One cheap char pass, no regex.
*/
export function findRemendWindowStart(text: string): number {
const n = text.length
let inFence = false
let fenceChar = 0
let fenceRun = 0
let inMath = false
let boundary = 0
let pending = -1 // a blank line, committed to `boundary` once content follows
for (let lineStart = 0; lineStart <= n; ) {
let lineEnd = text.indexOf('\n', lineStart)
if (lineEnd === -1) {
lineEnd = n
}
let i = lineStart
while (i < lineEnd && isSpace(text.charCodeAt(i))) {
i += 1
}
const first = i < lineEnd ? text.charCodeAt(i) : -1
let marker = false
// Fence open/close (``` or ~~~, ≤3 spaces indent).
if ((first === BACKTICK || first === TILDE) && i - lineStart <= 3) {
let run = i
while (run < lineEnd && text.charCodeAt(run) === first) {
run += 1
}
if (run - i >= 3) {
marker = true
if (!inFence) {
inFence = true
fenceChar = first
fenceRun = run - i
} else if (first === fenceChar && run - i >= fenceRun && onlyWhitespace(text, run, lineEnd)) {
inFence = false
}
}
}
// Toggle `$$` math state on plain lines ($$ inside a fence is literal).
if (!inFence && !marker) {
for (let s = text.indexOf('$$', lineStart); s !== -1 && s < lineEnd - 1; s = text.indexOf('$$', s + 2)) {
if (s === 0 || text.charCodeAt(s - 1) !== BACKSLASH) {
inMath = !inMath
}
}
}
if (first === -1 && !inFence && !inMath) {
pending = lineEnd + 1
} else if (pending !== -1) {
boundary = pending
pending = -1
}
lineStart = lineEnd + 1
}
return boundary
}
function onlyWhitespace(text: string, from: number, to: number): boolean {
for (let i = from; i < to; i += 1) {
if (!isSpace(text.charCodeAt(i))) {
return false
}
}
return true
}
export function tailBoundedRemend(text: string): string {
const start = findRemendWindowStart(text)
return start <= 0 ? remend(text) : text.slice(0, start) + remend(text.slice(start))
}