perf: lazy-load tool data on demand, fix reasoning state & action button visibility#4354
Merged
Merged
Conversation
added 4 commits
June 14, 2026 11:25
…uring streaming
- Add reasoningComplete flag to LiveStream to track when reasoning finishes
- Auto-close reasoning panel and update label when reasoningComplete becomes true
- Suppress current-turn action buttons (copy/fork/summarize/rewind) while model is running
- Keep previous completed turns' action buttons visible with copy enabled
useController.ts: reasoningComplete logic in reducer (turn_started/reasoning/text)
Message.tsx: reasoningComplete-driven auto-close, label toggle, data-running control
Transcript.tsx: running-guarded final pushTurnActions for hot zone
App.tsx: pass running={state.running} to Transcript
Add backend ToolResult endpoint (Controller + Wails binding App.ToolResultForTab) to retrieve full tool args/output from Session.Messages by tool ID. Frontend truncates oldest tool items (>100) to 200-char previews on turn_done, loading full data via the backend when the card is expanded. Prefix cache invariance: untouched — session messages, system prompt, and tool schemas are never modified by this change.
12 tests verify: archiving triggers at threshold, truncates args to ≤200 chars, drops output to undefined, sets dataArchived flag, does not crash on undefined output, does not archive running tools, and reduces total string size by 33% in a 150-tool session.
Tool cards now only keep tool name + command (200-char args preview) in items[] after tool_result. Full output is dropped immediately; full data is loaded on demand via app.ToolResultForTab when the card is expanded. Running tools still keep full args for subject/UI display; archiving only triggers on tool_result (completion or error). Test: 18 tests confirm every completed tool is archived, running tools keep full data, undefined output doesn't crash, and a 500-tool session sees 99% reduction in tool string data (7.5M chars → 100K chars).
added 2 commits
June 14, 2026 12:48
Three root-cause fixes for the 600MB→2GB→600MB memory spike during streaming model output: 1. LiveAssistantMessage (Transcript.tsx): wrap object in useMemo so React.memo on AssistantMessage is not defeated by new object identity on every render → stops the cascade through Markdown when text hasn't changed. 2. Markdown (Markdown.tsx): wrap normalizeMath(deferred) in useMemo so the full-text math normalization is skipped when deferred value is stable. 3. HljsCode (editors/HljsCode.tsx): add React.memo + useMemo for highlightToHtml so code blocks are not re-highlighted when value and language are unchanged.
14 tests proving the streaming markdown rendering fixes work: - LiveAssistantMessage shown computation: stable output for stable input, updates only when live.text/reasoning change (Test 1) - normalizeMath: deterministic, fast (100 calls in 0.5ms) (Test 2) - highlightToHtml LRU cache: cached call (0.01ms) vs first call (5.67ms), streaming-adjacent calls under 1ms (Test 3) - Streaming growth simulation: pattern confirmed correct (Test 4)
Contributor
Author
|
Temporarily closing to merge complementary changes from #4318 and test locally |
added 4 commits
June 14, 2026 13:34
historyMessagesToItems creates items with full args/output, bypassing the tool_result reducer. Added archiving in the 'history' action handler so history-loaded tools also get args truncated and output dropped.
useDeferredValue caused the rendered markdown to jump from the stale (shorter) deferred text to the current (longer) value, creating a visible flash when streaming long code blocks. Using text directly ensures incremental rendering with no jumps. The rAF batch already provides sufficient coalescing (~16ms per flush) for smooth streaming without useDeferredValue.
- E2: normalizeDisplayMode default changed from 'compact' to 'standard' to match getDisplayMode (fixes inconsistent fallback) - A4: history archive skips items with empty output string (avoids unnecessary object allocation for already-small data) - A5: ToolCard resets fullData cache when item reference changes (prevents stale tool data after rewind) - D3: confirmed MAX=30 cap already exists in breadcrumbs.ts (no fix needed — review was a false alarm)
Combined test suites from both branches: reasoning-display.test.ts, crash-reporting.test.ts (upstream), tool-data-archive.test.ts, render-optimization.test.ts (ours).
Use a session snapshot when resolving archived tool data so the desktop query does not race live session writes. Also make archived tool cards expandable when only lazy-loaded output is available, restore shell previews from fetched output, and keep the new frontend tests typecheck-safe and deterministic. Co-authored-by: SivanCola <32437197+SivanCola@users.noreply.github.com>
Collaborator
|
@codex review |
|
Codex Review: Didn't find any major issues. Breezy! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
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.
Summary
This PR addresses memory growth and UX issues in long-running Reasonix sessions across three areas: tool card memory optimization (99% string reduction), reasoning state tracking (eliminating the "still thinking" false state), and action button visibility during streaming. It also merges complementary reasoning display improvements from #4318.
1. Tool Memory Optimization
argstrimmed to 200 chars (command/subject preview),outputdropped entirely. Collapsed cards only hold tool name + command in memory.Controller.ToolResult()walksSession().MessagesbyToolCallID.App.ToolResultForTabexposes it to the frontend. When a card is expanded, full data is fetched on demand.historyaction is also archived, not just new turns.useEffectcleanup clears cached data when item identity changes.Tested: 18 unit tests confirm archiving behavior, null-safety, and 99% reduction in tool string data (500-tool session: 7.5M → 100K chars).
Files:
internal/control/controller.go,desktop/app.go,useController.ts,ToolCard.tsx,bridge.ts,tool-data-archive.test.ts2. Reasoning State & Display
reasoningCompleteflag: NewLiveStream.reasoningCompletetracks the reasoning→text transition. Auto-closes the reasoning panel as soon as the first text chunk arrives after reasoning, without waiting formessage/turn_done.expandWhileStreaming(from Fix streaming reasoning UI jank / 修复流式思考过程导致的界面卡顿 #4318): Controls auto-open per display mode. Standard mode auto-expands reasoning; compact mode keeps it collapsed.{reasoningOpen && <div>}instead of always-mounted CSS-hidden body.displayReasoningTextkeeps only the tail (12K chars / 240 lines) while streaming in compact mode.Files:
Message.tsx,Transcript.tsx,useController.ts,reasoningDisplay.ts,reasoning-display.test.ts3. Action Button Visibility
Copy/fork/summarize/rewind buttons below each assistant message are hidden while the model is actively generating (
state.running === true). Previous completed turns' buttons remain visible with copy enabled. Arunningprop gates the hot zone's finalpushTurnActions().Files:
Transcript.tsx,App.tsx4. Rendering Performance
Three root-cause fixes for the streaming memory spike (600MB->2GB->600MB):
LiveAssistantMessageshowninuseMemo->AssistantMessage.memono longer defeated by new object identityMarkdown: removeduseDeferredValue(caused code-block flicker);normalizeMathinuseMemoHljsCode: wrapped inReact.memo+useMemo— code blocks not re-highlighted when value unchangedscrollVersionsimplified:{id}:{streaming}/{id}:{status}instead of full length fieldsrequestAnimationFrameper frame (from Fix streaming reasoning UI jank / 修复流式思考过程导致的界面卡顿 #4318)Files:
Transcript.tsx,Markdown.tsx,editors/HljsCode.tsx,render-optimization.test.ts5. Display Mode Default
Removed "minimal" from
DisplayMode.normalizeDisplayModefallback changed to"standard"to matchgetDisplayMode.Files:
SettingsPanel.tsx,displayMode.ts,types.ts,config.goFiles Changed
Prefix Cache Invariance
Zero impact. System prompt, tool schemas, session message serialization, and agent Run/Compose paths are untouched.
Controller.ToolResult()is a read-only query overSession().Messages— it never mutates history.