perf(desktop): bound tool-result rendering so big /learn runs don't freeze - #52273
Merged
Conversation
…reeze ToolFallback rebuilt the `part` wrapper every render, defeating the buildToolView memo and re-running a full JSON.stringify of the result on every ~33ms stream delta. A /learn over a large directory (many ~100KB tool results) saturated the renderer main thread (hang/throttle) and spiked memory until it OOMd (crash). - Re-derive a stable `part` from the referentially-stable args/result so the view/copy memos hold across deltas. - Clamp every inline-painted payload (detail, stdout/stderr, rawResult, technical trace) to MAX_TOOL_RENDER_CHARS; the row's Copy button still reads the uncapped view.detail for the full output.
OutThisLife
enabled auto-merge (squash)
June 25, 2026 02:52
pai-scaffolde
pushed a commit
to pai-scaffolde/hermes-agent
that referenced
this pull request
Jun 28, 2026
…reeze (NousResearch#52273) ToolFallback rebuilt the `part` wrapper every render, defeating the buildToolView memo and re-running a full JSON.stringify of the result on every ~33ms stream delta. A /learn over a large directory (many ~100KB tool results) saturated the renderer main thread (hang/throttle) and spiked memory until it OOMd (crash). - Re-derive a stable `part` from the referentially-stable args/result so the view/copy memos hold across deltas. - Clamp every inline-painted payload (detail, stdout/stderr, rawResult, technical trace) to MAX_TOOL_RENDER_CHARS; the row's Copy button still reads the uncapped view.detail for the full output.
1 task
waefrebeorn
pushed a commit
to waefrebeorn/slermes
that referenced
this pull request
Jul 2, 2026
…reeze (NousResearch#52273) ToolFallback rebuilt the `part` wrapper every render, defeating the buildToolView memo and re-running a full JSON.stringify of the result on every ~33ms stream delta. A /learn over a large directory (many ~100KB tool results) saturated the renderer main thread (hang/throttle) and spiked memory until it OOMd (crash). - Re-derive a stable `part` from the referentially-stable args/result so the view/copy memos hold across deltas. - Clamp every inline-painted payload (detail, stdout/stderr, rawResult, technical trace) to MAX_TOOL_RENDER_CHARS; the row's Copy button still reads the uncapped view.detail for the full output.
habarmc1223-sudo
pushed a commit
to habarmc1223-sudo/hermes-agent-fluxmem
that referenced
this pull request
Jul 8, 2026
…reeze (NousResearch#52273) ToolFallback rebuilt the `part` wrapper every render, defeating the buildToolView memo and re-running a full JSON.stringify of the result on every ~33ms stream delta. A /learn over a large directory (many ~100KB tool results) saturated the renderer main thread (hang/throttle) and spiked memory until it OOMd (crash). - Re-derive a stable `part` from the referentially-stable args/result so the view/copy memos hold across deltas. - Clamp every inline-painted payload (detail, stdout/stderr, rawResult, technical trace) to MAX_TOOL_RENDER_CHARS; the row's Copy button still reads the uncapped view.detail for the full output.
santhreal
pushed a commit
to santhreal/hermes-agent
that referenced
this pull request
Jul 13, 2026
…reeze (NousResearch#52273) ToolFallback rebuilt the `part` wrapper every render, defeating the buildToolView memo and re-running a full JSON.stringify of the result on every ~33ms stream delta. A /learn over a large directory (many ~100KB tool results) saturated the renderer main thread (hang/throttle) and spiked memory until it OOMd (crash). - Re-derive a stable `part` from the referentially-stable args/result so the view/copy memos hold across deltas. - Clamp every inline-painted payload (detail, stdout/stderr, rawResult, technical trace) to MAX_TOOL_RENDER_CHARS; the row's Copy button still reads the uncapped view.detail for the full output.
Gravezzz
pushed a commit
to Gravezzz/hermes-agent
that referenced
this pull request
Jul 21, 2026
…reeze (NousResearch#52273) ToolFallback rebuilt the `part` wrapper every render, defeating the buildToolView memo and re-running a full JSON.stringify of the result on every ~33ms stream delta. A /learn over a large directory (many ~100KB tool results) saturated the renderer main thread (hang/throttle) and spiked memory until it OOMd (crash). - Re-derive a stable `part` from the referentially-stable args/result so the view/copy memos hold across deltas. - Clamp every inline-painted payload (detail, stdout/stderr, rawResult, technical trace) to MAX_TOOL_RENDER_CHARS; the row's Copy button still reads the uncapped view.detail for the full output.
leewenjie
pushed a commit
to leewenjie/hermes-agent
that referenced
this pull request
Aug 7, 2026
…reeze (NousResearch#52273) ToolFallback rebuilt the `part` wrapper every render, defeating the buildToolView memo and re-running a full JSON.stringify of the result on every ~33ms stream delta. A /learn over a large directory (many ~100KB tool results) saturated the renderer main thread (hang/throttle) and spiked memory until it OOMd (crash). - Re-derive a stable `part` from the referentially-stable args/result so the view/copy memos hold across deltas. - Clamp every inline-painted payload (detail, stdout/stderr, rawResult, technical trace) to MAX_TOOL_RENDER_CHARS; the row's Copy button still reads the uncapped view.detail for the full output.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
/learnover a large file/directory makes the desktop app hang/throttle forever or crash outright — the agent's gathering loop never visibly completes. (Reported: "On large files/directories, the desktop app either crashes completely or just hangs/throttles forever without actually executing the learning process.")It is not a
/learnbug —build_learn_prompt()is fixed-size and never embeds file contents. The fault is in the desktop tool renderer.Root cause
ToolFallbackconstructs a freshpartobject on every render:That fresh reference defeats the
useMemoaroundbuildToolView, which unconditionallyJSON.stringifys the entire result (rawResult) and extracts the fulldetail. During a/learnrun over a big directory — many ~100KB tool results — every ~33ms stream flush re-renders the thread and re-serializes every row: the main thread saturates (hang/throttle) and accumulated strings spike renderer memory (crash). Small dirs never trip it because results are few and tiny.Fix
stablePartfrom the referentially-stableargs/result/… and keybuildToolView+toolCopyPayloadon it, so they recompute only when this tool's data changes — not on every unrelated stream delta.clampForDisplay(MAX_TOOL_RENDER_CHARS = 20_000) applied toprettyJson(rawArgs/rawResult),rawTechnicalTrace, and the rendered detail/stdout/stderr blocks, with a "… N more characters truncated — use Copy" notice. The row's Copy button still reads the uncappedview.detail, so the full output is one click away.No new core surface, no schema change — purely desktop renderer.
Test plan
vitest run apps/desktop/src/components/assistant-ui/tool-fallback-model.test.ts— 14 passed (3 new: clamp pass-through, truncation + omitted-count,buildToolViewrawResult cap)tsc -p apps/desktop --noEmit— cleaneslinton changed files — clean (pre-existing model-file lints left untouched)block-direction/streaming/user-message-edit) are pre-existing jsdom-layout failures — confirmed identical with these changes stashed