perf(web): coalesce streaming Markdown renders - #4349

Open
nateEc wants to merge 1 commit into
pingdotgg:mainfrom
nateEc:codex/fix-4074-streaming-markdown-cpu
Open

perf(web): coalesce streaming Markdown renders#4349
nateEc wants to merge 1 commit into
pingdotgg:mainfrom
nateEc:codex/fix-4074-streaming-markdown-cpu

Conversation

@nateEc

@nateEcnateEc commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Closes#4074

Summary

  • coalesce streaming assistant Markdown updates to a 50ms rendering cadence
  • keep Markdown component identities stable while text deltas arrive
  • flush the final response immediately without splitting whole-document Markdown semantics

Verification

  • vp test run apps/web/src/components/ChatMarkdown.logic.test.ts apps/web/src/components/markdown-list-indentation.test.tsx apps/web/src/components/markdown-links.test.ts (27 passed)
  • vp run --filter @t3tools/web typecheck
  • targeted lint for the changed files (only pre-existing nested-component warnings)
  • test-t3-app: streamed a live Codex response containing paragraphs, bullet/task lists, a table, and a fenced TypeScript block; all rendered after completion

Note

Low Risk
UI-only throttling in chat markdown rendering with immediate flush when streaming stops; no auth, data, or API changes.

Overview
Coalesces assistant Markdown updates during streaming so ChatMarkdown re-parses and re-renders at most once every 50ms, instead of on every token delta.

Adds useStreamingMarkdownText and a small streamingMarkdownRenderDelay helper (with unit tests). While isStreaming is true, visible source and derived work (link/meta extraction, task-list marker offsets) follow the throttled renderedText; when streaming ends, the hook flushes immediately to the latest text. The ReactMarkdown tree is also memoized on renderedText so component identity stays steadier between batched updates.

Behavior: live output can lag the incoming stream by up to ~50ms; completed messages should match prior semantics.

Reviewed by Cursor Bugbot for commit 6497047. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Coalesce streaming Markdown renders in ChatMarkdown to a 50ms interval

  • Adds useStreamingMarkdownText hook in ChatMarkdown.tsx that throttles text updates during streaming to at most one render per 50ms, clearing superseded timers and recording render timestamps
  • Adds streamingMarkdownRenderDelay util in ChatMarkdown.logic.ts that computes the non-negative remaining delay since the last render, clamping elapsed time to zero when the clock moves backwards
  • ChatMarkdown now uses throttled renderedText for file-link extraction, inline-code extraction, task-list markers, and the memoized ReactMarkdown output; non-streaming renders sync immediately
  • Behavioral Change: streaming ChatMarkdown no longer re-parses and re-renders on every incoming text value; output updates at most every 50ms while streaming is active

Macroscope summarized 6497047.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 23, 2026
@coderabbitai

coderabbitaiBot commented Jul 23, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 99527976-11c4-4004-9674-6ac5d821e8e1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment threadapps/web/src/components/ChatMarkdown.tsx Outdated

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a46d860c61e47a8f6ad2ff9b7334ae213d5ae908. Configure here.

Comment threadapps/web/src/components/ChatMarkdown.tsx
@macroscopeapp

macroscopeappBot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The PR changes an existing assistant-message path by automatically suppressing Markdown parsing and DOM updates between 50 ms snapshots during streaming. Since this gate controls when substantial rendering work occurs without an operator choice, the runtime behavior merits human review.

You can add or adjust custom eligibility rules. Learn more.

@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Jul 23, 2026
@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 6d2b488 to 26ebe2fCompareAugust 19, 2026 06:33
@nateEc

nateEc commented Aug 19, 2026

Copy link
Copy Markdown
ContributorAuthor

Final refresh on current main: 325e1fe9a.

  • Implementation range-diff is unchanged from the reviewed version.
  • Focused Markdown tests: 65/65 passed.
  • GitHub checks: 20/20 completed, 0 failures.
  • Local web typecheck is blocked only by current-main electronPasskeys test typing errors outside this PR.
  • Linux CPU and Markdown rendering repro instructions were sent to @mudit-loya.
  • PR is mergeable and clean.

macroscopeapp[bot]
macroscopeappBot previously approved these changes Aug 19, 2026
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge@mudit-loya — this is ready for human review and Linux reproduction validation on 26ebe2fb7.

The current-main version coalesces streaming Markdown parsing to at most once every 50ms, while synchronously flushing the complete final response. It preserves current links, task lists, raw HTML, tables, and code-block behavior. The focused suite is 54/54, web typecheck and isolated browser streaming verification pass, and all CI/Bugbot/Macroscope checks are green (including Approvability and UI Consistency).

For review, the main tradeoff is the 50ms intermediate-render cadence; final rendered output and stream-completion timing remain unchanged. A quick check against the original Linux high-CPU reproduction would be especially useful.

@mudit-loya

Copy link
Copy Markdown

@nateEc how can we test this fix?

@nateEc

Copy link
Copy Markdown
ContributorAuthor

Thanks for offering to verify this. The useful comparison is the same one from #4074, using the same model and a response of roughly the same length:

  1. Build/run this PR branch (nateEc:codex/fix-4074-streaming-markdown-cpu) on Linux.
  2. In a fresh thread, stream a reply containing several paragraphs plus a fenced code block, task list, table, and nested list. Record the peak combined CPU for the T3 renderer and GPU helper in htop; repeat once.
  3. Repeat the same prompt in a long thread with many already-rendered messages, again recording two peak samples.
  4. Confirm the final Markdown is complete after streaming: especially blank lines inside code fences, task-list checkboxes, tables, nested lists, and reference-style links.

The primary success signal is that long-thread streaming no longer scales sharply above the fresh-thread result (the original report was roughly 76%/65% versus 35%). The fresh-thread baseline may still be non-trivial; this PR specifically targets the per-token full reparse. Please include the T3 commit, Linux/desktop version, and the four peak samples when reporting back.

@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 26ebe2f to 325e1feCompareAugust 24, 2026 08:12
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge Ready for another review on 325e1fe9a. Rebased onto current main; implementation range-diff is unchanged, 65/65 focused Markdown tests pass, and all 20 GitHub checks completed with 0 failures. Linux CPU/rendering repro instructions were sent to @mudit-loya. Mergeable state is clean.

- 将高频 token 更新限制为每 50 毫秒最多触发一次 Markdown 解析。
- 流式结束时同步刷新完整文本,保留链接、任务列表与代码块行为。
- 最新主线上的 65 个定向测试通过,补丁经 range-diff 确认未漂移。
- Web 类型检查仅剩主线 electronPasskeys 测试中的两条既有错误。
@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 325e1fe to 6497047CompareSeptember 2, 2026 11:33
@macroscopeapp
macroscopeappBot dismissed their stale reviewSeptember 2, 2026 11:33

Dismissing prior approval to re-evaluate 6497047

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. and removed vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Sep 2, 2026
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge Rebased onto the latest main; the focused ChatMarkdown suite passes and the current CI is green. Could you take a human review when you have a moment?

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Heavy CPU Usage on linux

2 participants

@nateEc@mudit-loya
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

perf(web): coalesce streaming Markdown renders - #4349

Open
nateEc wants to merge 1 commit into
pingdotgg:mainfrom
nateEc:codex/fix-4074-streaming-markdown-cpu
Open

perf(web): coalesce streaming Markdown renders#4349
nateEc wants to merge 1 commit into
pingdotgg:mainfrom
nateEc:codex/fix-4074-streaming-markdown-cpu

Conversation

@nateEc

@nateEcnateEc commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Closes#4074

Summary

  • coalesce streaming assistant Markdown updates to a 50ms rendering cadence
  • keep Markdown component identities stable while text deltas arrive
  • flush the final response immediately without splitting whole-document Markdown semantics

Verification

  • vp test run apps/web/src/components/ChatMarkdown.logic.test.ts apps/web/src/components/markdown-list-indentation.test.tsx apps/web/src/components/markdown-links.test.ts (27 passed)
  • vp run --filter @t3tools/web typecheck
  • targeted lint for the changed files (only pre-existing nested-component warnings)
  • test-t3-app: streamed a live Codex response containing paragraphs, bullet/task lists, a table, and a fenced TypeScript block; all rendered after completion

Note

Low Risk
UI-only throttling in chat markdown rendering with immediate flush when streaming stops; no auth, data, or API changes.

Overview
Coalesces assistant Markdown updates during streaming so ChatMarkdown re-parses and re-renders at most once every 50ms, instead of on every token delta.

Adds useStreamingMarkdownText and a small streamingMarkdownRenderDelay helper (with unit tests). While isStreaming is true, visible source and derived work (link/meta extraction, task-list marker offsets) follow the throttled renderedText; when streaming ends, the hook flushes immediately to the latest text. The ReactMarkdown tree is also memoized on renderedText so component identity stays steadier between batched updates.

Behavior: live output can lag the incoming stream by up to ~50ms; completed messages should match prior semantics.

Reviewed by Cursor Bugbot for commit 6497047. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Coalesce streaming Markdown renders in ChatMarkdown to a 50ms interval

  • Adds useStreamingMarkdownText hook in ChatMarkdown.tsx that throttles text updates during streaming to at most one render per 50ms, clearing superseded timers and recording render timestamps
  • Adds streamingMarkdownRenderDelay util in ChatMarkdown.logic.ts that computes the non-negative remaining delay since the last render, clamping elapsed time to zero when the clock moves backwards
  • ChatMarkdown now uses throttled renderedText for file-link extraction, inline-code extraction, task-list markers, and the memoized ReactMarkdown output; non-streaming renders sync immediately
  • Behavioral Change: streaming ChatMarkdown no longer re-parses and re-renders on every incoming text value; output updates at most every 50ms while streaming is active

Macroscope summarized 6497047.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 23, 2026
@coderabbitai

coderabbitaiBot commented Jul 23, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 99527976-11c4-4004-9674-6ac5d821e8e1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment threadapps/web/src/components/ChatMarkdown.tsx Outdated

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a46d860c61e47a8f6ad2ff9b7334ae213d5ae908. Configure here.

Comment threadapps/web/src/components/ChatMarkdown.tsx
@macroscopeapp

macroscopeappBot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The PR changes an existing assistant-message path by automatically suppressing Markdown parsing and DOM updates between 50 ms snapshots during streaming. Since this gate controls when substantial rendering work occurs without an operator choice, the runtime behavior merits human review.

You can add or adjust custom eligibility rules. Learn more.

@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Jul 23, 2026
@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 6d2b488 to 26ebe2fCompareAugust 19, 2026 06:33
@nateEc

nateEc commented Aug 19, 2026

Copy link
Copy Markdown
ContributorAuthor

Final refresh on current main: 325e1fe9a.

  • Implementation range-diff is unchanged from the reviewed version.
  • Focused Markdown tests: 65/65 passed.
  • GitHub checks: 20/20 completed, 0 failures.
  • Local web typecheck is blocked only by current-main electronPasskeys test typing errors outside this PR.
  • Linux CPU and Markdown rendering repro instructions were sent to @mudit-loya.
  • PR is mergeable and clean.

macroscopeapp[bot]
macroscopeappBot previously approved these changes Aug 19, 2026
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge@mudit-loya — this is ready for human review and Linux reproduction validation on 26ebe2fb7.

The current-main version coalesces streaming Markdown parsing to at most once every 50ms, while synchronously flushing the complete final response. It preserves current links, task lists, raw HTML, tables, and code-block behavior. The focused suite is 54/54, web typecheck and isolated browser streaming verification pass, and all CI/Bugbot/Macroscope checks are green (including Approvability and UI Consistency).

For review, the main tradeoff is the 50ms intermediate-render cadence; final rendered output and stream-completion timing remain unchanged. A quick check against the original Linux high-CPU reproduction would be especially useful.

@mudit-loya

Copy link
Copy Markdown

@nateEc how can we test this fix?

@nateEc

Copy link
Copy Markdown
ContributorAuthor

Thanks for offering to verify this. The useful comparison is the same one from #4074, using the same model and a response of roughly the same length:

  1. Build/run this PR branch (nateEc:codex/fix-4074-streaming-markdown-cpu) on Linux.
  2. In a fresh thread, stream a reply containing several paragraphs plus a fenced code block, task list, table, and nested list. Record the peak combined CPU for the T3 renderer and GPU helper in htop; repeat once.
  3. Repeat the same prompt in a long thread with many already-rendered messages, again recording two peak samples.
  4. Confirm the final Markdown is complete after streaming: especially blank lines inside code fences, task-list checkboxes, tables, nested lists, and reference-style links.

The primary success signal is that long-thread streaming no longer scales sharply above the fresh-thread result (the original report was roughly 76%/65% versus 35%). The fresh-thread baseline may still be non-trivial; this PR specifically targets the per-token full reparse. Please include the T3 commit, Linux/desktop version, and the four peak samples when reporting back.

@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 26ebe2f to 325e1feCompareAugust 24, 2026 08:12
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge Ready for another review on 325e1fe9a. Rebased onto current main; implementation range-diff is unchanged, 65/65 focused Markdown tests pass, and all 20 GitHub checks completed with 0 failures. Linux CPU/rendering repro instructions were sent to @mudit-loya. Mergeable state is clean.

- 将高频 token 更新限制为每 50 毫秒最多触发一次 Markdown 解析。
- 流式结束时同步刷新完整文本,保留链接、任务列表与代码块行为。
- 最新主线上的 65 个定向测试通过,补丁经 range-diff 确认未漂移。
- Web 类型检查仅剩主线 electronPasskeys 测试中的两条既有错误。
@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 325e1fe to 6497047CompareSeptember 2, 2026 11:33
@macroscopeapp
macroscopeappBot dismissed their stale reviewSeptember 2, 2026 11:33

Dismissing prior approval to re-evaluate 6497047

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. and removed vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Sep 2, 2026
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge Rebased onto the latest main; the focused ChatMarkdown suite passes and the current CI is green. Could you take a human review when you have a moment?

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Heavy CPU Usage on linux

2 participants

@nateEc@mudit-loya
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

perf(web): coalesce streaming Markdown renders - #4349

Open
nateEc wants to merge 1 commit into
pingdotgg:mainfrom
nateEc:codex/fix-4074-streaming-markdown-cpu
Open

perf(web): coalesce streaming Markdown renders#4349
nateEc wants to merge 1 commit into
pingdotgg:mainfrom
nateEc:codex/fix-4074-streaming-markdown-cpu

Conversation

@nateEc

@nateEcnateEc commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Closes#4074

Summary

  • coalesce streaming assistant Markdown updates to a 50ms rendering cadence
  • keep Markdown component identities stable while text deltas arrive
  • flush the final response immediately without splitting whole-document Markdown semantics

Verification

  • vp test run apps/web/src/components/ChatMarkdown.logic.test.ts apps/web/src/components/markdown-list-indentation.test.tsx apps/web/src/components/markdown-links.test.ts (27 passed)
  • vp run --filter @t3tools/web typecheck
  • targeted lint for the changed files (only pre-existing nested-component warnings)
  • test-t3-app: streamed a live Codex response containing paragraphs, bullet/task lists, a table, and a fenced TypeScript block; all rendered after completion

Note

Low Risk
UI-only throttling in chat markdown rendering with immediate flush when streaming stops; no auth, data, or API changes.

Overview
Coalesces assistant Markdown updates during streaming so ChatMarkdown re-parses and re-renders at most once every 50ms, instead of on every token delta.

Adds useStreamingMarkdownText and a small streamingMarkdownRenderDelay helper (with unit tests). While isStreaming is true, visible source and derived work (link/meta extraction, task-list marker offsets) follow the throttled renderedText; when streaming ends, the hook flushes immediately to the latest text. The ReactMarkdown tree is also memoized on renderedText so component identity stays steadier between batched updates.

Behavior: live output can lag the incoming stream by up to ~50ms; completed messages should match prior semantics.

Reviewed by Cursor Bugbot for commit 6497047. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Coalesce streaming Markdown renders in ChatMarkdown to a 50ms interval

  • Adds useStreamingMarkdownText hook in ChatMarkdown.tsx that throttles text updates during streaming to at most one render per 50ms, clearing superseded timers and recording render timestamps
  • Adds streamingMarkdownRenderDelay util in ChatMarkdown.logic.ts that computes the non-negative remaining delay since the last render, clamping elapsed time to zero when the clock moves backwards
  • ChatMarkdown now uses throttled renderedText for file-link extraction, inline-code extraction, task-list markers, and the memoized ReactMarkdown output; non-streaming renders sync immediately
  • Behavioral Change: streaming ChatMarkdown no longer re-parses and re-renders on every incoming text value; output updates at most every 50ms while streaming is active

Macroscope summarized 6497047.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 23, 2026
@coderabbitai

coderabbitaiBot commented Jul 23, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 99527976-11c4-4004-9674-6ac5d821e8e1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment threadapps/web/src/components/ChatMarkdown.tsx Outdated

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a46d860c61e47a8f6ad2ff9b7334ae213d5ae908. Configure here.

Comment threadapps/web/src/components/ChatMarkdown.tsx
@macroscopeapp

macroscopeappBot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The PR changes an existing assistant-message path by automatically suppressing Markdown parsing and DOM updates between 50 ms snapshots during streaming. Since this gate controls when substantial rendering work occurs without an operator choice, the runtime behavior merits human review.

You can add or adjust custom eligibility rules. Learn more.

@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Jul 23, 2026
@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 6d2b488 to 26ebe2fCompareAugust 19, 2026 06:33
@nateEc

nateEc commented Aug 19, 2026

Copy link
Copy Markdown
ContributorAuthor

Final refresh on current main: 325e1fe9a.

  • Implementation range-diff is unchanged from the reviewed version.
  • Focused Markdown tests: 65/65 passed.
  • GitHub checks: 20/20 completed, 0 failures.
  • Local web typecheck is blocked only by current-main electronPasskeys test typing errors outside this PR.
  • Linux CPU and Markdown rendering repro instructions were sent to @mudit-loya.
  • PR is mergeable and clean.

macroscopeapp[bot]
macroscopeappBot previously approved these changes Aug 19, 2026
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge@mudit-loya — this is ready for human review and Linux reproduction validation on 26ebe2fb7.

The current-main version coalesces streaming Markdown parsing to at most once every 50ms, while synchronously flushing the complete final response. It preserves current links, task lists, raw HTML, tables, and code-block behavior. The focused suite is 54/54, web typecheck and isolated browser streaming verification pass, and all CI/Bugbot/Macroscope checks are green (including Approvability and UI Consistency).

For review, the main tradeoff is the 50ms intermediate-render cadence; final rendered output and stream-completion timing remain unchanged. A quick check against the original Linux high-CPU reproduction would be especially useful.

@mudit-loya

Copy link
Copy Markdown

@nateEc how can we test this fix?

@nateEc

Copy link
Copy Markdown
ContributorAuthor

Thanks for offering to verify this. The useful comparison is the same one from #4074, using the same model and a response of roughly the same length:

  1. Build/run this PR branch (nateEc:codex/fix-4074-streaming-markdown-cpu) on Linux.
  2. In a fresh thread, stream a reply containing several paragraphs plus a fenced code block, task list, table, and nested list. Record the peak combined CPU for the T3 renderer and GPU helper in htop; repeat once.
  3. Repeat the same prompt in a long thread with many already-rendered messages, again recording two peak samples.
  4. Confirm the final Markdown is complete after streaming: especially blank lines inside code fences, task-list checkboxes, tables, nested lists, and reference-style links.

The primary success signal is that long-thread streaming no longer scales sharply above the fresh-thread result (the original report was roughly 76%/65% versus 35%). The fresh-thread baseline may still be non-trivial; this PR specifically targets the per-token full reparse. Please include the T3 commit, Linux/desktop version, and the four peak samples when reporting back.

@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 26ebe2f to 325e1feCompareAugust 24, 2026 08:12
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge Ready for another review on 325e1fe9a. Rebased onto current main; implementation range-diff is unchanged, 65/65 focused Markdown tests pass, and all 20 GitHub checks completed with 0 failures. Linux CPU/rendering repro instructions were sent to @mudit-loya. Mergeable state is clean.

- 将高频 token 更新限制为每 50 毫秒最多触发一次 Markdown 解析。
- 流式结束时同步刷新完整文本,保留链接、任务列表与代码块行为。
- 最新主线上的 65 个定向测试通过,补丁经 range-diff 确认未漂移。
- Web 类型检查仅剩主线 electronPasskeys 测试中的两条既有错误。
@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 325e1fe to 6497047CompareSeptember 2, 2026 11:33
@macroscopeapp
macroscopeappBot dismissed their stale reviewSeptember 2, 2026 11:33

Dismissing prior approval to re-evaluate 6497047

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. and removed vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Sep 2, 2026
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge Rebased onto the latest main; the focused ChatMarkdown suite passes and the current CI is green. Could you take a human review when you have a moment?

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Heavy CPU Usage on linux

2 participants

@nateEc@mudit-loya
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

perf(web): coalesce streaming Markdown renders - #4349

Open
nateEc wants to merge 1 commit into
pingdotgg:mainfrom
nateEc:codex/fix-4074-streaming-markdown-cpu
Open

perf(web): coalesce streaming Markdown renders#4349
nateEc wants to merge 1 commit into
pingdotgg:mainfrom
nateEc:codex/fix-4074-streaming-markdown-cpu

Conversation

@nateEc

@nateEcnateEc commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Closes#4074

Summary

  • coalesce streaming assistant Markdown updates to a 50ms rendering cadence
  • keep Markdown component identities stable while text deltas arrive
  • flush the final response immediately without splitting whole-document Markdown semantics

Verification

  • vp test run apps/web/src/components/ChatMarkdown.logic.test.ts apps/web/src/components/markdown-list-indentation.test.tsx apps/web/src/components/markdown-links.test.ts (27 passed)
  • vp run --filter @t3tools/web typecheck
  • targeted lint for the changed files (only pre-existing nested-component warnings)
  • test-t3-app: streamed a live Codex response containing paragraphs, bullet/task lists, a table, and a fenced TypeScript block; all rendered after completion

Note

Low Risk
UI-only throttling in chat markdown rendering with immediate flush when streaming stops; no auth, data, or API changes.

Overview
Coalesces assistant Markdown updates during streaming so ChatMarkdown re-parses and re-renders at most once every 50ms, instead of on every token delta.

Adds useStreamingMarkdownText and a small streamingMarkdownRenderDelay helper (with unit tests). While isStreaming is true, visible source and derived work (link/meta extraction, task-list marker offsets) follow the throttled renderedText; when streaming ends, the hook flushes immediately to the latest text. The ReactMarkdown tree is also memoized on renderedText so component identity stays steadier between batched updates.

Behavior: live output can lag the incoming stream by up to ~50ms; completed messages should match prior semantics.

Reviewed by Cursor Bugbot for commit 6497047. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Coalesce streaming Markdown renders in ChatMarkdown to a 50ms interval

  • Adds useStreamingMarkdownText hook in ChatMarkdown.tsx that throttles text updates during streaming to at most one render per 50ms, clearing superseded timers and recording render timestamps
  • Adds streamingMarkdownRenderDelay util in ChatMarkdown.logic.ts that computes the non-negative remaining delay since the last render, clamping elapsed time to zero when the clock moves backwards
  • ChatMarkdown now uses throttled renderedText for file-link extraction, inline-code extraction, task-list markers, and the memoized ReactMarkdown output; non-streaming renders sync immediately
  • Behavioral Change: streaming ChatMarkdown no longer re-parses and re-renders on every incoming text value; output updates at most every 50ms while streaming is active

Macroscope summarized 6497047.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 23, 2026
@coderabbitai

coderabbitaiBot commented Jul 23, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 99527976-11c4-4004-9674-6ac5d821e8e1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment threadapps/web/src/components/ChatMarkdown.tsx Outdated

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a46d860c61e47a8f6ad2ff9b7334ae213d5ae908. Configure here.

Comment threadapps/web/src/components/ChatMarkdown.tsx
@macroscopeapp

macroscopeappBot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The PR changes an existing assistant-message path by automatically suppressing Markdown parsing and DOM updates between 50 ms snapshots during streaming. Since this gate controls when substantial rendering work occurs without an operator choice, the runtime behavior merits human review.

You can add or adjust custom eligibility rules. Learn more.

@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Jul 23, 2026
@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 6d2b488 to 26ebe2fCompareAugust 19, 2026 06:33
@nateEc

nateEc commented Aug 19, 2026

Copy link
Copy Markdown
ContributorAuthor

Final refresh on current main: 325e1fe9a.

  • Implementation range-diff is unchanged from the reviewed version.
  • Focused Markdown tests: 65/65 passed.
  • GitHub checks: 20/20 completed, 0 failures.
  • Local web typecheck is blocked only by current-main electronPasskeys test typing errors outside this PR.
  • Linux CPU and Markdown rendering repro instructions were sent to @mudit-loya.
  • PR is mergeable and clean.

macroscopeapp[bot]
macroscopeappBot previously approved these changes Aug 19, 2026
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge@mudit-loya — this is ready for human review and Linux reproduction validation on 26ebe2fb7.

The current-main version coalesces streaming Markdown parsing to at most once every 50ms, while synchronously flushing the complete final response. It preserves current links, task lists, raw HTML, tables, and code-block behavior. The focused suite is 54/54, web typecheck and isolated browser streaming verification pass, and all CI/Bugbot/Macroscope checks are green (including Approvability and UI Consistency).

For review, the main tradeoff is the 50ms intermediate-render cadence; final rendered output and stream-completion timing remain unchanged. A quick check against the original Linux high-CPU reproduction would be especially useful.

@mudit-loya

Copy link
Copy Markdown

@nateEc how can we test this fix?

@nateEc

Copy link
Copy Markdown
ContributorAuthor

Thanks for offering to verify this. The useful comparison is the same one from #4074, using the same model and a response of roughly the same length:

  1. Build/run this PR branch (nateEc:codex/fix-4074-streaming-markdown-cpu) on Linux.
  2. In a fresh thread, stream a reply containing several paragraphs plus a fenced code block, task list, table, and nested list. Record the peak combined CPU for the T3 renderer and GPU helper in htop; repeat once.
  3. Repeat the same prompt in a long thread with many already-rendered messages, again recording two peak samples.
  4. Confirm the final Markdown is complete after streaming: especially blank lines inside code fences, task-list checkboxes, tables, nested lists, and reference-style links.

The primary success signal is that long-thread streaming no longer scales sharply above the fresh-thread result (the original report was roughly 76%/65% versus 35%). The fresh-thread baseline may still be non-trivial; this PR specifically targets the per-token full reparse. Please include the T3 commit, Linux/desktop version, and the four peak samples when reporting back.

@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 26ebe2f to 325e1feCompareAugust 24, 2026 08:12
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge Ready for another review on 325e1fe9a. Rebased onto current main; implementation range-diff is unchanged, 65/65 focused Markdown tests pass, and all 20 GitHub checks completed with 0 failures. Linux CPU/rendering repro instructions were sent to @mudit-loya. Mergeable state is clean.

- 将高频 token 更新限制为每 50 毫秒最多触发一次 Markdown 解析。
- 流式结束时同步刷新完整文本,保留链接、任务列表与代码块行为。
- 最新主线上的 65 个定向测试通过,补丁经 range-diff 确认未漂移。
- Web 类型检查仅剩主线 electronPasskeys 测试中的两条既有错误。
@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 325e1fe to 6497047CompareSeptember 2, 2026 11:33
@macroscopeapp
macroscopeappBot dismissed their stale reviewSeptember 2, 2026 11:33

Dismissing prior approval to re-evaluate 6497047

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. and removed vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Sep 2, 2026
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge Rebased onto the latest main; the focused ChatMarkdown suite passes and the current CI is green. Could you take a human review when you have a moment?

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Heavy CPU Usage on linux

2 participants

@nateEc@mudit-loya
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

perf(web): coalesce streaming Markdown renders - #4349

Open
nateEc wants to merge 1 commit into
pingdotgg:mainfrom
nateEc:codex/fix-4074-streaming-markdown-cpu
Open

perf(web): coalesce streaming Markdown renders#4349
nateEc wants to merge 1 commit into
pingdotgg:mainfrom
nateEc:codex/fix-4074-streaming-markdown-cpu

Conversation

@nateEc

@nateEcnateEc commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Closes#4074

Summary

  • coalesce streaming assistant Markdown updates to a 50ms rendering cadence
  • keep Markdown component identities stable while text deltas arrive
  • flush the final response immediately without splitting whole-document Markdown semantics

Verification

  • vp test run apps/web/src/components/ChatMarkdown.logic.test.ts apps/web/src/components/markdown-list-indentation.test.tsx apps/web/src/components/markdown-links.test.ts (27 passed)
  • vp run --filter @t3tools/web typecheck
  • targeted lint for the changed files (only pre-existing nested-component warnings)
  • test-t3-app: streamed a live Codex response containing paragraphs, bullet/task lists, a table, and a fenced TypeScript block; all rendered after completion

Note

Low Risk
UI-only throttling in chat markdown rendering with immediate flush when streaming stops; no auth, data, or API changes.

Overview
Coalesces assistant Markdown updates during streaming so ChatMarkdown re-parses and re-renders at most once every 50ms, instead of on every token delta.

Adds useStreamingMarkdownText and a small streamingMarkdownRenderDelay helper (with unit tests). While isStreaming is true, visible source and derived work (link/meta extraction, task-list marker offsets) follow the throttled renderedText; when streaming ends, the hook flushes immediately to the latest text. The ReactMarkdown tree is also memoized on renderedText so component identity stays steadier between batched updates.

Behavior: live output can lag the incoming stream by up to ~50ms; completed messages should match prior semantics.

Reviewed by Cursor Bugbot for commit 6497047. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Coalesce streaming Markdown renders in ChatMarkdown to a 50ms interval

  • Adds useStreamingMarkdownText hook in ChatMarkdown.tsx that throttles text updates during streaming to at most one render per 50ms, clearing superseded timers and recording render timestamps
  • Adds streamingMarkdownRenderDelay util in ChatMarkdown.logic.ts that computes the non-negative remaining delay since the last render, clamping elapsed time to zero when the clock moves backwards
  • ChatMarkdown now uses throttled renderedText for file-link extraction, inline-code extraction, task-list markers, and the memoized ReactMarkdown output; non-streaming renders sync immediately
  • Behavioral Change: streaming ChatMarkdown no longer re-parses and re-renders on every incoming text value; output updates at most every 50ms while streaming is active

Macroscope summarized 6497047.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 23, 2026
@coderabbitai

coderabbitaiBot commented Jul 23, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 99527976-11c4-4004-9674-6ac5d821e8e1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment threadapps/web/src/components/ChatMarkdown.tsx Outdated

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a46d860c61e47a8f6ad2ff9b7334ae213d5ae908. Configure here.

Comment threadapps/web/src/components/ChatMarkdown.tsx
@macroscopeapp

macroscopeappBot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The PR changes an existing assistant-message path by automatically suppressing Markdown parsing and DOM updates between 50 ms snapshots during streaming. Since this gate controls when substantial rendering work occurs without an operator choice, the runtime behavior merits human review.

You can add or adjust custom eligibility rules. Learn more.

@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Jul 23, 2026
@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 6d2b488 to 26ebe2fCompareAugust 19, 2026 06:33
@nateEc

nateEc commented Aug 19, 2026

Copy link
Copy Markdown
ContributorAuthor

Final refresh on current main: 325e1fe9a.

  • Implementation range-diff is unchanged from the reviewed version.
  • Focused Markdown tests: 65/65 passed.
  • GitHub checks: 20/20 completed, 0 failures.
  • Local web typecheck is blocked only by current-main electronPasskeys test typing errors outside this PR.
  • Linux CPU and Markdown rendering repro instructions were sent to @mudit-loya.
  • PR is mergeable and clean.

macroscopeapp[bot]
macroscopeappBot previously approved these changes Aug 19, 2026
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge@mudit-loya — this is ready for human review and Linux reproduction validation on 26ebe2fb7.

The current-main version coalesces streaming Markdown parsing to at most once every 50ms, while synchronously flushing the complete final response. It preserves current links, task lists, raw HTML, tables, and code-block behavior. The focused suite is 54/54, web typecheck and isolated browser streaming verification pass, and all CI/Bugbot/Macroscope checks are green (including Approvability and UI Consistency).

For review, the main tradeoff is the 50ms intermediate-render cadence; final rendered output and stream-completion timing remain unchanged. A quick check against the original Linux high-CPU reproduction would be especially useful.

@mudit-loya

Copy link
Copy Markdown

@nateEc how can we test this fix?

@nateEc

Copy link
Copy Markdown
ContributorAuthor

Thanks for offering to verify this. The useful comparison is the same one from #4074, using the same model and a response of roughly the same length:

  1. Build/run this PR branch (nateEc:codex/fix-4074-streaming-markdown-cpu) on Linux.
  2. In a fresh thread, stream a reply containing several paragraphs plus a fenced code block, task list, table, and nested list. Record the peak combined CPU for the T3 renderer and GPU helper in htop; repeat once.
  3. Repeat the same prompt in a long thread with many already-rendered messages, again recording two peak samples.
  4. Confirm the final Markdown is complete after streaming: especially blank lines inside code fences, task-list checkboxes, tables, nested lists, and reference-style links.

The primary success signal is that long-thread streaming no longer scales sharply above the fresh-thread result (the original report was roughly 76%/65% versus 35%). The fresh-thread baseline may still be non-trivial; this PR specifically targets the per-token full reparse. Please include the T3 commit, Linux/desktop version, and the four peak samples when reporting back.

@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 26ebe2f to 325e1feCompareAugust 24, 2026 08:12
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge Ready for another review on 325e1fe9a. Rebased onto current main; implementation range-diff is unchanged, 65/65 focused Markdown tests pass, and all 20 GitHub checks completed with 0 failures. Linux CPU/rendering repro instructions were sent to @mudit-loya. Mergeable state is clean.

- 将高频 token 更新限制为每 50 毫秒最多触发一次 Markdown 解析。
- 流式结束时同步刷新完整文本,保留链接、任务列表与代码块行为。
- 最新主线上的 65 个定向测试通过,补丁经 range-diff 确认未漂移。
- Web 类型检查仅剩主线 electronPasskeys 测试中的两条既有错误。
@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 325e1fe to 6497047CompareSeptember 2, 2026 11:33
@macroscopeapp
macroscopeappBot dismissed their stale reviewSeptember 2, 2026 11:33

Dismissing prior approval to re-evaluate 6497047

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. and removed vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Sep 2, 2026
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge Rebased onto the latest main; the focused ChatMarkdown suite passes and the current CI is green. Could you take a human review when you have a moment?

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Heavy CPU Usage on linux

2 participants

@nateEc@mudit-loya
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

perf(web): coalesce streaming Markdown renders - #4349

Open
nateEc wants to merge 1 commit into
pingdotgg:mainfrom
nateEc:codex/fix-4074-streaming-markdown-cpu
Open

perf(web): coalesce streaming Markdown renders#4349
nateEc wants to merge 1 commit into
pingdotgg:mainfrom
nateEc:codex/fix-4074-streaming-markdown-cpu

Conversation

@nateEc

@nateEcnateEc commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Closes#4074

Summary

  • coalesce streaming assistant Markdown updates to a 50ms rendering cadence
  • keep Markdown component identities stable while text deltas arrive
  • flush the final response immediately without splitting whole-document Markdown semantics

Verification

  • vp test run apps/web/src/components/ChatMarkdown.logic.test.ts apps/web/src/components/markdown-list-indentation.test.tsx apps/web/src/components/markdown-links.test.ts (27 passed)
  • vp run --filter @t3tools/web typecheck
  • targeted lint for the changed files (only pre-existing nested-component warnings)
  • test-t3-app: streamed a live Codex response containing paragraphs, bullet/task lists, a table, and a fenced TypeScript block; all rendered after completion

Note

Low Risk
UI-only throttling in chat markdown rendering with immediate flush when streaming stops; no auth, data, or API changes.

Overview
Coalesces assistant Markdown updates during streaming so ChatMarkdown re-parses and re-renders at most once every 50ms, instead of on every token delta.

Adds useStreamingMarkdownText and a small streamingMarkdownRenderDelay helper (with unit tests). While isStreaming is true, visible source and derived work (link/meta extraction, task-list marker offsets) follow the throttled renderedText; when streaming ends, the hook flushes immediately to the latest text. The ReactMarkdown tree is also memoized on renderedText so component identity stays steadier between batched updates.

Behavior: live output can lag the incoming stream by up to ~50ms; completed messages should match prior semantics.

Reviewed by Cursor Bugbot for commit 6497047. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Coalesce streaming Markdown renders in ChatMarkdown to a 50ms interval

  • Adds useStreamingMarkdownText hook in ChatMarkdown.tsx that throttles text updates during streaming to at most one render per 50ms, clearing superseded timers and recording render timestamps
  • Adds streamingMarkdownRenderDelay util in ChatMarkdown.logic.ts that computes the non-negative remaining delay since the last render, clamping elapsed time to zero when the clock moves backwards
  • ChatMarkdown now uses throttled renderedText for file-link extraction, inline-code extraction, task-list markers, and the memoized ReactMarkdown output; non-streaming renders sync immediately
  • Behavioral Change: streaming ChatMarkdown no longer re-parses and re-renders on every incoming text value; output updates at most every 50ms while streaming is active

Macroscope summarized 6497047.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 23, 2026
@coderabbitai

coderabbitaiBot commented Jul 23, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 99527976-11c4-4004-9674-6ac5d821e8e1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment threadapps/web/src/components/ChatMarkdown.tsx Outdated

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a46d860c61e47a8f6ad2ff9b7334ae213d5ae908. Configure here.

Comment threadapps/web/src/components/ChatMarkdown.tsx
@macroscopeapp

macroscopeappBot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The PR changes an existing assistant-message path by automatically suppressing Markdown parsing and DOM updates between 50 ms snapshots during streaming. Since this gate controls when substantial rendering work occurs without an operator choice, the runtime behavior merits human review.

You can add or adjust custom eligibility rules. Learn more.

@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Jul 23, 2026
@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 6d2b488 to 26ebe2fCompareAugust 19, 2026 06:33
@nateEc

nateEc commented Aug 19, 2026

Copy link
Copy Markdown
ContributorAuthor

Final refresh on current main: 325e1fe9a.

  • Implementation range-diff is unchanged from the reviewed version.
  • Focused Markdown tests: 65/65 passed.
  • GitHub checks: 20/20 completed, 0 failures.
  • Local web typecheck is blocked only by current-main electronPasskeys test typing errors outside this PR.
  • Linux CPU and Markdown rendering repro instructions were sent to @mudit-loya.
  • PR is mergeable and clean.

macroscopeapp[bot]
macroscopeappBot previously approved these changes Aug 19, 2026
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge@mudit-loya — this is ready for human review and Linux reproduction validation on 26ebe2fb7.

The current-main version coalesces streaming Markdown parsing to at most once every 50ms, while synchronously flushing the complete final response. It preserves current links, task lists, raw HTML, tables, and code-block behavior. The focused suite is 54/54, web typecheck and isolated browser streaming verification pass, and all CI/Bugbot/Macroscope checks are green (including Approvability and UI Consistency).

For review, the main tradeoff is the 50ms intermediate-render cadence; final rendered output and stream-completion timing remain unchanged. A quick check against the original Linux high-CPU reproduction would be especially useful.

@mudit-loya

Copy link
Copy Markdown

@nateEc how can we test this fix?

@nateEc

Copy link
Copy Markdown
ContributorAuthor

Thanks for offering to verify this. The useful comparison is the same one from #4074, using the same model and a response of roughly the same length:

  1. Build/run this PR branch (nateEc:codex/fix-4074-streaming-markdown-cpu) on Linux.
  2. In a fresh thread, stream a reply containing several paragraphs plus a fenced code block, task list, table, and nested list. Record the peak combined CPU for the T3 renderer and GPU helper in htop; repeat once.
  3. Repeat the same prompt in a long thread with many already-rendered messages, again recording two peak samples.
  4. Confirm the final Markdown is complete after streaming: especially blank lines inside code fences, task-list checkboxes, tables, nested lists, and reference-style links.

The primary success signal is that long-thread streaming no longer scales sharply above the fresh-thread result (the original report was roughly 76%/65% versus 35%). The fresh-thread baseline may still be non-trivial; this PR specifically targets the per-token full reparse. Please include the T3 commit, Linux/desktop version, and the four peak samples when reporting back.

@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 26ebe2f to 325e1feCompareAugust 24, 2026 08:12
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge Ready for another review on 325e1fe9a. Rebased onto current main; implementation range-diff is unchanged, 65/65 focused Markdown tests pass, and all 20 GitHub checks completed with 0 failures. Linux CPU/rendering repro instructions were sent to @mudit-loya. Mergeable state is clean.

- 将高频 token 更新限制为每 50 毫秒最多触发一次 Markdown 解析。
- 流式结束时同步刷新完整文本,保留链接、任务列表与代码块行为。
- 最新主线上的 65 个定向测试通过,补丁经 range-diff 确认未漂移。
- Web 类型检查仅剩主线 electronPasskeys 测试中的两条既有错误。
@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 325e1fe to 6497047CompareSeptember 2, 2026 11:33
@macroscopeapp
macroscopeappBot dismissed their stale reviewSeptember 2, 2026 11:33

Dismissing prior approval to re-evaluate 6497047

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. and removed vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Sep 2, 2026
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge Rebased onto the latest main; the focused ChatMarkdown suite passes and the current CI is green. Could you take a human review when you have a moment?

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Heavy CPU Usage on linux

2 participants

@nateEc@mudit-loya
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

perf(web): coalesce streaming Markdown renders - #4349

Open
nateEc wants to merge 1 commit into
pingdotgg:mainfrom
nateEc:codex/fix-4074-streaming-markdown-cpu
Open

perf(web): coalesce streaming Markdown renders#4349
nateEc wants to merge 1 commit into
pingdotgg:mainfrom
nateEc:codex/fix-4074-streaming-markdown-cpu

Conversation

@nateEc

@nateEcnateEc commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Closes#4074

Summary

  • coalesce streaming assistant Markdown updates to a 50ms rendering cadence
  • keep Markdown component identities stable while text deltas arrive
  • flush the final response immediately without splitting whole-document Markdown semantics

Verification

  • vp test run apps/web/src/components/ChatMarkdown.logic.test.ts apps/web/src/components/markdown-list-indentation.test.tsx apps/web/src/components/markdown-links.test.ts (27 passed)
  • vp run --filter @t3tools/web typecheck
  • targeted lint for the changed files (only pre-existing nested-component warnings)
  • test-t3-app: streamed a live Codex response containing paragraphs, bullet/task lists, a table, and a fenced TypeScript block; all rendered after completion

Note

Low Risk
UI-only throttling in chat markdown rendering with immediate flush when streaming stops; no auth, data, or API changes.

Overview
Coalesces assistant Markdown updates during streaming so ChatMarkdown re-parses and re-renders at most once every 50ms, instead of on every token delta.

Adds useStreamingMarkdownText and a small streamingMarkdownRenderDelay helper (with unit tests). While isStreaming is true, visible source and derived work (link/meta extraction, task-list marker offsets) follow the throttled renderedText; when streaming ends, the hook flushes immediately to the latest text. The ReactMarkdown tree is also memoized on renderedText so component identity stays steadier between batched updates.

Behavior: live output can lag the incoming stream by up to ~50ms; completed messages should match prior semantics.

Reviewed by Cursor Bugbot for commit 6497047. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Coalesce streaming Markdown renders in ChatMarkdown to a 50ms interval

  • Adds useStreamingMarkdownText hook in ChatMarkdown.tsx that throttles text updates during streaming to at most one render per 50ms, clearing superseded timers and recording render timestamps
  • Adds streamingMarkdownRenderDelay util in ChatMarkdown.logic.ts that computes the non-negative remaining delay since the last render, clamping elapsed time to zero when the clock moves backwards
  • ChatMarkdown now uses throttled renderedText for file-link extraction, inline-code extraction, task-list markers, and the memoized ReactMarkdown output; non-streaming renders sync immediately
  • Behavioral Change: streaming ChatMarkdown no longer re-parses and re-renders on every incoming text value; output updates at most every 50ms while streaming is active

Macroscope summarized 6497047.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 23, 2026
@coderabbitai

coderabbitaiBot commented Jul 23, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 99527976-11c4-4004-9674-6ac5d821e8e1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment threadapps/web/src/components/ChatMarkdown.tsx Outdated

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a46d860c61e47a8f6ad2ff9b7334ae213d5ae908. Configure here.

Comment threadapps/web/src/components/ChatMarkdown.tsx
@macroscopeapp

macroscopeappBot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The PR changes an existing assistant-message path by automatically suppressing Markdown parsing and DOM updates between 50 ms snapshots during streaming. Since this gate controls when substantial rendering work occurs without an operator choice, the runtime behavior merits human review.

You can add or adjust custom eligibility rules. Learn more.

@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Jul 23, 2026
@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 6d2b488 to 26ebe2fCompareAugust 19, 2026 06:33
@nateEc

nateEc commented Aug 19, 2026

Copy link
Copy Markdown
ContributorAuthor

Final refresh on current main: 325e1fe9a.

  • Implementation range-diff is unchanged from the reviewed version.
  • Focused Markdown tests: 65/65 passed.
  • GitHub checks: 20/20 completed, 0 failures.
  • Local web typecheck is blocked only by current-main electronPasskeys test typing errors outside this PR.
  • Linux CPU and Markdown rendering repro instructions were sent to @mudit-loya.
  • PR is mergeable and clean.

macroscopeapp[bot]
macroscopeappBot previously approved these changes Aug 19, 2026
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge@mudit-loya — this is ready for human review and Linux reproduction validation on 26ebe2fb7.

The current-main version coalesces streaming Markdown parsing to at most once every 50ms, while synchronously flushing the complete final response. It preserves current links, task lists, raw HTML, tables, and code-block behavior. The focused suite is 54/54, web typecheck and isolated browser streaming verification pass, and all CI/Bugbot/Macroscope checks are green (including Approvability and UI Consistency).

For review, the main tradeoff is the 50ms intermediate-render cadence; final rendered output and stream-completion timing remain unchanged. A quick check against the original Linux high-CPU reproduction would be especially useful.

@mudit-loya

Copy link
Copy Markdown

@nateEc how can we test this fix?

@nateEc

Copy link
Copy Markdown
ContributorAuthor

Thanks for offering to verify this. The useful comparison is the same one from #4074, using the same model and a response of roughly the same length:

  1. Build/run this PR branch (nateEc:codex/fix-4074-streaming-markdown-cpu) on Linux.
  2. In a fresh thread, stream a reply containing several paragraphs plus a fenced code block, task list, table, and nested list. Record the peak combined CPU for the T3 renderer and GPU helper in htop; repeat once.
  3. Repeat the same prompt in a long thread with many already-rendered messages, again recording two peak samples.
  4. Confirm the final Markdown is complete after streaming: especially blank lines inside code fences, task-list checkboxes, tables, nested lists, and reference-style links.

The primary success signal is that long-thread streaming no longer scales sharply above the fresh-thread result (the original report was roughly 76%/65% versus 35%). The fresh-thread baseline may still be non-trivial; this PR specifically targets the per-token full reparse. Please include the T3 commit, Linux/desktop version, and the four peak samples when reporting back.

@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 26ebe2f to 325e1feCompareAugust 24, 2026 08:12
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge Ready for another review on 325e1fe9a. Rebased onto current main; implementation range-diff is unchanged, 65/65 focused Markdown tests pass, and all 20 GitHub checks completed with 0 failures. Linux CPU/rendering repro instructions were sent to @mudit-loya. Mergeable state is clean.

- 将高频 token 更新限制为每 50 毫秒最多触发一次 Markdown 解析。
- 流式结束时同步刷新完整文本,保留链接、任务列表与代码块行为。
- 最新主线上的 65 个定向测试通过,补丁经 range-diff 确认未漂移。
- Web 类型检查仅剩主线 electronPasskeys 测试中的两条既有错误。
@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 325e1fe to 6497047CompareSeptember 2, 2026 11:33
@macroscopeapp
macroscopeappBot dismissed their stale reviewSeptember 2, 2026 11:33

Dismissing prior approval to re-evaluate 6497047

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. and removed vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Sep 2, 2026
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge Rebased onto the latest main; the focused ChatMarkdown suite passes and the current CI is green. Could you take a human review when you have a moment?

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Heavy CPU Usage on linux

2 participants

@nateEc@mudit-loya
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

perf(web): coalesce streaming Markdown renders - #4349

Open
nateEc wants to merge 1 commit into
pingdotgg:mainfrom
nateEc:codex/fix-4074-streaming-markdown-cpu
Open

perf(web): coalesce streaming Markdown renders#4349
nateEc wants to merge 1 commit into
pingdotgg:mainfrom
nateEc:codex/fix-4074-streaming-markdown-cpu

Conversation

@nateEc

@nateEcnateEc commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Closes#4074

Summary

  • coalesce streaming assistant Markdown updates to a 50ms rendering cadence
  • keep Markdown component identities stable while text deltas arrive
  • flush the final response immediately without splitting whole-document Markdown semantics

Verification

  • vp test run apps/web/src/components/ChatMarkdown.logic.test.ts apps/web/src/components/markdown-list-indentation.test.tsx apps/web/src/components/markdown-links.test.ts (27 passed)
  • vp run --filter @t3tools/web typecheck
  • targeted lint for the changed files (only pre-existing nested-component warnings)
  • test-t3-app: streamed a live Codex response containing paragraphs, bullet/task lists, a table, and a fenced TypeScript block; all rendered after completion

Note

Low Risk
UI-only throttling in chat markdown rendering with immediate flush when streaming stops; no auth, data, or API changes.

Overview
Coalesces assistant Markdown updates during streaming so ChatMarkdown re-parses and re-renders at most once every 50ms, instead of on every token delta.

Adds useStreamingMarkdownText and a small streamingMarkdownRenderDelay helper (with unit tests). While isStreaming is true, visible source and derived work (link/meta extraction, task-list marker offsets) follow the throttled renderedText; when streaming ends, the hook flushes immediately to the latest text. The ReactMarkdown tree is also memoized on renderedText so component identity stays steadier between batched updates.

Behavior: live output can lag the incoming stream by up to ~50ms; completed messages should match prior semantics.

Reviewed by Cursor Bugbot for commit 6497047. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Coalesce streaming Markdown renders in ChatMarkdown to a 50ms interval

  • Adds useStreamingMarkdownText hook in ChatMarkdown.tsx that throttles text updates during streaming to at most one render per 50ms, clearing superseded timers and recording render timestamps
  • Adds streamingMarkdownRenderDelay util in ChatMarkdown.logic.ts that computes the non-negative remaining delay since the last render, clamping elapsed time to zero when the clock moves backwards
  • ChatMarkdown now uses throttled renderedText for file-link extraction, inline-code extraction, task-list markers, and the memoized ReactMarkdown output; non-streaming renders sync immediately
  • Behavioral Change: streaming ChatMarkdown no longer re-parses and re-renders on every incoming text value; output updates at most every 50ms while streaming is active

Macroscope summarized 6497047.

@github-actionsgithub-actionsBot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Jul 23, 2026
@coderabbitai

coderabbitaiBot commented Jul 23, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 99527976-11c4-4004-9674-6ac5d821e8e1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment threadapps/web/src/components/ChatMarkdown.tsx Outdated

@cursorcursorBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit a46d860c61e47a8f6ad2ff9b7334ae213d5ae908. Configure here.

Comment threadapps/web/src/components/ChatMarkdown.tsx
@macroscopeapp

macroscopeappBot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — The PR changes an existing assistant-message path by automatically suppressing Markdown parsing and DOM updates between 50 ms snapshots during streaming. Since this gate controls when substantial rendering work occurs without an operator choice, the runtime behavior merits human review.

You can add or adjust custom eligibility rules. Learn more.

@github-actionsgithub-actionsBot added size:M 30-99 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Jul 23, 2026
@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 6d2b488 to 26ebe2fCompareAugust 19, 2026 06:33
@nateEc

nateEc commented Aug 19, 2026

Copy link
Copy Markdown
ContributorAuthor

Final refresh on current main: 325e1fe9a.

  • Implementation range-diff is unchanged from the reviewed version.
  • Focused Markdown tests: 65/65 passed.
  • GitHub checks: 20/20 completed, 0 failures.
  • Local web typecheck is blocked only by current-main electronPasskeys test typing errors outside this PR.
  • Linux CPU and Markdown rendering repro instructions were sent to @mudit-loya.
  • PR is mergeable and clean.

macroscopeapp[bot]
macroscopeappBot previously approved these changes Aug 19, 2026
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge@mudit-loya — this is ready for human review and Linux reproduction validation on 26ebe2fb7.

The current-main version coalesces streaming Markdown parsing to at most once every 50ms, while synchronously flushing the complete final response. It preserves current links, task lists, raw HTML, tables, and code-block behavior. The focused suite is 54/54, web typecheck and isolated browser streaming verification pass, and all CI/Bugbot/Macroscope checks are green (including Approvability and UI Consistency).

For review, the main tradeoff is the 50ms intermediate-render cadence; final rendered output and stream-completion timing remain unchanged. A quick check against the original Linux high-CPU reproduction would be especially useful.

@mudit-loya

Copy link
Copy Markdown

@nateEc how can we test this fix?

@nateEc

Copy link
Copy Markdown
ContributorAuthor

Thanks for offering to verify this. The useful comparison is the same one from #4074, using the same model and a response of roughly the same length:

  1. Build/run this PR branch (nateEc:codex/fix-4074-streaming-markdown-cpu) on Linux.
  2. In a fresh thread, stream a reply containing several paragraphs plus a fenced code block, task list, table, and nested list. Record the peak combined CPU for the T3 renderer and GPU helper in htop; repeat once.
  3. Repeat the same prompt in a long thread with many already-rendered messages, again recording two peak samples.
  4. Confirm the final Markdown is complete after streaming: especially blank lines inside code fences, task-list checkboxes, tables, nested lists, and reference-style links.

The primary success signal is that long-thread streaming no longer scales sharply above the fresh-thread result (the original report was roughly 76%/65% versus 35%). The fresh-thread baseline may still be non-trivial; this PR specifically targets the per-token full reparse. Please include the T3 commit, Linux/desktop version, and the four peak samples when reporting back.

@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 26ebe2f to 325e1feCompareAugust 24, 2026 08:12
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge Ready for another review on 325e1fe9a. Rebased onto current main; implementation range-diff is unchanged, 65/65 focused Markdown tests pass, and all 20 GitHub checks completed with 0 failures. Linux CPU/rendering repro instructions were sent to @mudit-loya. Mergeable state is clean.

- 将高频 token 更新限制为每 50 毫秒最多触发一次 Markdown 解析。
- 流式结束时同步刷新完整文本,保留链接、任务列表与代码块行为。
- 最新主线上的 65 个定向测试通过,补丁经 range-diff 确认未漂移。
- Web 类型检查仅剩主线 electronPasskeys 测试中的两条既有错误。
@nateEc
nateEcforce-pushed the codex/fix-4074-streaming-markdown-cpu branch from 325e1fe to 6497047CompareSeptember 2, 2026 11:33
@macroscopeapp
macroscopeappBot dismissed their stale reviewSeptember 2, 2026 11:33

Dismissing prior approval to re-evaluate 6497047

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. and removed vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Sep 2, 2026
@nateEc

Copy link
Copy Markdown
ContributorAuthor

@juliusmarminge Rebased onto the latest main; the focused ChatMarkdown suite passes and the current CI is green. Could you take a human review when you have a moment?

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M30-99 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Heavy CPU Usage on linux

2 participants

@nateEc@mudit-loya