perf(desktop): a transcript page that moves nothing redraws nothing above the agent's tab
Charles reported that the Neon Realtime task makes the app laggy. On his Mac (0.17.0), the window's renderer reached about 1.1 GB and used 10–30% CPU while idle with the task open.
Cause (one part of it)
The tab of a running agent reads its transcript through the service's held long-poll. That is up to about two pages a second while the agent writes, and one every 20 s while it is quiet. Every page, even an empty one, re-rendered the whole window from its root:
onStatusalways set the coding agents' list to a new array, becausewithAgentRunalways mapped.- Each page built
subagentTitles,delegations, andsubagentsas new Maps.AgentTab'sonHeldeffect depends onsubagentTitles, so it handed the task's page a new held transcript every time.
The root re-render then re-derives the shown transcript and re-parses the full plan, because neither is memoized. On a task this large that is real work.
Change
withAgentRunreturns the agents unchanged when the agent already has that status and run start.onStatuskeeps the list as it was in that case.- A page that lists the workers exactly as they were keeps the held maps.
Tests
coding-agent-model.test.ts: an unchanged run returns the same list; a changed run moves only that agent.- New
use-agent-transcript.test.ts: a repeated page keeps the worker maps, and a changed worker standing is still picked up. This test fails without the change.
pnpm check:affected passes locally, except that discarded-effect ran out of heap in the sandbox; it passes when run on its own with a bigger heap.
Not in this PR
This removes the extra root renders that pages repeating the same state caused. A page that carries new messages still re-renders the task page through onHeld. That redraws the whole transcript, with AgentMessage not memoized and no virtualization, and the whole plan through MarkdownMessage. I'd like a profile of the real task before changing those.
Made with Luke