Conversation
Signed-off-by: Ho Lim <166576253+HOYALIM@users.noreply.github.com>
Signed-off-by: Ho Lim <subhoya@gmail.com>
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Approved
Fixes idle renderer animation loops by tracking window visibility state (isMinimized, isVisible) and handling minimize/restore/hide/show events. Well-scoped fix with Electron event listeners added appropriately. No security concerns.
Reviewed by Hermes Agent
|
Thanks for the focused performance work. I verified the reported continuous loops still exist on current main: terminal rect polling in No substantive correctness issue was identified in the reviewed diff. The change keeps The PR base is 121 commits behind current main, but only Automated hermes-sweeper review. |
# Conflicts: # apps/desktop/electron/main.ts
# Conflicts: # apps/desktop/src/app/session/hooks/use-message-stream/index.ts
Summary
Hermes deliberately disables Chromium's background throttling so an answer keeps painting while its window is blurred or covered. That workaround is load-bearing, but it also exposed three decorative/layout loops that ran at the display refresh rate forever:
PetSpriterequested RAF continuously although the sprite changes only about 5–6 times/sec.usePetRoamrequested RAF during idle dwell periods, not only while the pet was moving.PersistentTerminalpolled an unchanged slot rectangle every frame.On a 120 Hz Mac, the terminal alone scheduled about 1,200 callbacks per 10 seconds; enabling the pet doubled that to about 2,400. Fully occluding the window did not stop them because background rendering is intentionally unthrottled.
This PR keeps that streaming workaround and makes decorative/layout work bounded instead:
This builds on and preserves the authorship of @HOYALIM's earlier work in #61084.
Why the anti-throttling remains
backgroundThrottling: falseand the renderer backgrounding switches were added because Chromium otherwise pauses/clamps renderer scheduling when a user switches to another app or covers Hermes. A chat response would appear to stall and then catch up on refocus.This PR does not remove or relax those flags. Transcript flushing is decoupled from RAF and remains active on a bounded timer. Decorative loops independently subscribe to visibility/focus/Electron window-state signals and sleep when they have nothing useful to paint.
macOS measurements
Measured on Apple Silicon, macOS 26.5.2. Process CPU uses fixed 10-second
SystemInfo.getProcessInfo.cpuTimedeltas; RAF sites were instrumented through CDP. Before and after used the same Electron version, machine, harness, window states, and duration.The installed production app reproduced the reported symptom directly:
A controlled renderer harness isolated the changed paths:
The remaining 60 visible pet callbacks per 10 seconds match the sprite's real animation cadence instead of the 120 Hz display.
Background streaming verification
A synthetic stream emitted 250 deltas at 25 deltas/sec, which exercises the old RAF path because each delta arrives after the 33 ms flush floor.
The patched build reached the full transcript length while visible, unfocused, and fully covered. Background streaming therefore remains uninterrupted while decorative work stays asleep.
Tests
Added coverage for:
backgroundThrottling: falseon all chat windows.Verification performed:
npm run typechecknpm run lint— 0 errors (repository warnings remain)npm run build— renderer, Electron main/preload, native staging, and dist assertion passedgit diff --checknpm test— 1,785 passed, 1 skipped; three unrelatedSkillsViewtests flaked under full-suite load and passed 3/3 when rerun aloneAn independent review found no blocking issues. Its two findings—nested terminal layout observation and the initial-unfocused mount race—were fixed and covered before submission.
Tradeoffs / scope