feat(desktop): keep the machine awake while local agents work - #5535
feat(desktop): keep the machine awake while local agents work#5535leo-mathurin wants to merge 2 commits into
Conversation
Add an off-by-default "Caffeinate while agents are running" setting. While enabled and a desktop-hosted agent is busy, the renderer asks the Electron main process to hold a prevent-app-suspension power-save blocker, so system sleep cannot interrupt a running turn. The display can still turn off, and the assertion releases below 10% battery while discharging.
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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. Comment |
| if (typeof setKeepAwake !== "function") { | ||
| return; | ||
| } | ||
| const send = (value: boolean) => { |
There was a problem hiding this comment.
🟡 Medium state/desktopCaffeinate.ts:143
send sets lastSentRef.current before awaiting setKeepAwake(value) and then swallows rejections, so a failed IPC call records the value as delivered. A transient rejection of setKeepAwake(true) is never retried while the agent keeps running, and a rejected setKeepAwake(false) during unmount leaves the main-process keep-awake blocker held. Consider updating lastSentRef only after the promise resolves and retrying or reconciling on failure.
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/state/desktopCaffeinate.ts around line 143:
`send` sets `lastSentRef.current` before awaiting `setKeepAwake(value)` and then swallows rejections, so a failed IPC call records the value as delivered. A transient rejection of `setKeepAwake(true)` is never retried while the agent keeps running, and a rejected `setKeepAwake(false)` during unmount leaves the main-process keep-awake blocker held. Consider updating `lastSentRef` only after the promise resolves and retrying or reconciling on failure.
There was a problem hiding this comment.
Hardened in e37eb60: a rejected setKeepAwake no longer latches its value as delivered; the catch resets lastSentRef so the next state evaluation resends, and the main-process handler is idempotent so duplicate sends are harmless.
We kept the ref update before the await on purpose: moving it after resolution makes the dedup racy under rapid flips (two in-flight sends can interleave and latch a stale value). We also skipped a retry loop: the realistic rejection paths were checked (handlers are registered app-globally before any window loads, the payload is a plain boolean, and Electron's powerSaveBlocker never throws; on Linux without DBus the inhibit no-ops at the OS level, which a renderer retry could neither detect nor fix), and the main process force-releases on renderer death and window close as a backstop.
There was a problem hiding this comment.
Sorry, I'm unable to act on this request because you do not have permissions within this repository.
A rejected setKeepAwake call no longer latches its value as delivered: the failed send is forgotten so the next state evaluation resends. The main-process handler is idempotent, so a duplicate send stays harmless.
Fixes #663
Problem. Long agent turns die when the machine goes to sleep. #663 asked for a sleep inhibitor held only while a thread is running, using
prevent-app-suspensionso the display can still turn off.What this does. Adds an off-by-default desktop setting, "Caffeinate while agents are running" (Settings > General, hidden on hosted web). While it is on and at least one agent hosted by this desktop (primary local or WSL backend) has an active turn, the renderer asks the main process to hold a single idempotent
prevent-app-suspensionblocker over the typed IPC bridge. Remote, SSH, and relay agents do not count since local sleep does not interrupt them. The assertion releases below 10% battery while discharging and re-acquires when charging or recovered. Toggling off releases immediately, and a crashed or closed renderer cannot leak the assertion.Verified.
pmset -g assertionsshows the Electron assertion appear seconds after a turn starts and disappear when the turn settles; toggling off mid-turn releases immediately; nothing leaks after quit.powercfg /requests) or a Linux user (systemd-inhibit --list) while an agent runs would be very welcome.Screenshots.
Before (Settings > General on main):

After, toggle off (default):

After, toggle on:

Implemented by Claude (Fable 5) via Claude Code.