ab4e979352
## Rationale `LazyMarkdownRenderer` re-parses and re-renders the **entire accumulated message** through react-markdown on every throttled stream flush (10/s). Render cost grows linearly with message length while streaming, so long answers degrade progressively — this is the dominant jank vector in the chat (verified in the perf audit: no memoization anywhere in the message-render path). ## Why this is the root cause, not a symptom patch The waste is structural: 99% of a streaming message is settled text that cannot change, yet it re-renders because the whole string is one react-markdown call. Splitting at real markdown block boundaries via `marked.lexer` (already a dependency, used in the advanced text editor) and memoizing per block means settled blocks keep their rendered subtree; only the growing tail block re-parses per flush — cost becomes O(tail) instead of O(message). Index keys are stable because streaming is append-only. This is the standard memoized-markdown pattern from the AI SDK ecosystem. Deliberately **not** included: list virtualization for very long threads. The audit's verdict was memoize first, virtualize only if profiling still shows mount cost matters — virtualization changes scroll behavior and deserves its own evaluation. One known tradeoff: markdown reference-style links whose definition lives in a *different* block won't resolve across blocks. Model output uses inline links; the tradeoff is shared by every implementation of this pattern. ## User impact Long streaming answers stop stuttering — keystroke-to-paint stays flat instead of degrading as the answer grows. Most noticeable on tool-heavy turns that produce big final summaries. ## Test plan - [ ] CI green (existing markdown rendering covered by storybook visual tests) - [ ] Manual: stream a long answer with code fences and tables — identical rendering, no per-flush jank in the profiler https://claude.ai/code/session_01Lyi6zTema2FMVVh8MD6c38 --- _Generated by [Claude Code](https://claude.ai/code/session_01Lyi6zTema2FMVVh8MD6c38)_ <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22489?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->