fix(site/src/pages/AgentsPage): stabilize chat scroll on git watcher updates#23716
Draft
fix(site/src/pages/AgentsPage): stabilize chat scroll on git watcher updates#23716
Conversation
…updates The chat scroll position jumped every time the git watcher WebSocket received data because urlTransform was recreated on every AgentDetail render due to React Compiler hook interleaving, and isConnected state caused unnecessary re-renders on every WebSocket lifecycle event. Three changes fix this: 1. Extract buildUrlTransform as a module-level function and pass primitive fields (proxyHost, agentName, wsName, wsOwner) via urlTransformProps instead of a pre-built function. The compiler guards the props object on primitives (stable) and guards the buildUrlTransform call inside AgentDetailView (slot 5). The AgentDetailTimeline guard (slot 59) now hits when git data changes, keeping the scroll container content cached. 2. Convert isConnected from useState to useRef in useGitWatcher. No component renders this value; it was causing two wasted full-tree re-renders per WebSocket open/close cycle. 3. Split the gitWatcher prop into gitRepositories and gitRefresh, and use repositoriesRef for imperative access in handleOpenInEditor. This removes the opaque gitWatcher object from the AgentDetailView JSX guard, preventing unnecessary element re-creation when only git data changes.
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.
The chat scroll position jumped every time the git watcher WebSocket received data. Root cause:
urlTransformwas recreated on everyAgentDetailrender due to React Compiler hook interleaving, andisConnectedstate caused unnecessary re-renders on every WebSocket lifecycle event.Changes
Extract
buildUrlTransformas a module-level function and pass primitive fields viaurlTransformPropsinstead of a pre-built closure. The compiler guards the props object on primitives (stable) and guards thebuildUrlTransformcall insideAgentDetailView. TheAgentDetailTimelineguard now hits when git data changes, keeping the scroll container content cached.Convert
isConnectedfromuseStatetouseRefinuseGitWatcher. No component renders this value; it was causing two wasted full-tree re-renders per WebSocket open/close cycle.Split
gitWatcherprop intogitRepositoriesandgitRefresh, and userepositoriesReffor imperative access inhandleOpenInEditor. This removes the opaquegitWatcherobject from theAgentDetailViewJSX guard.Diagnosis (compiler output analysis)
Before:
urlTransformhad no compiler cache guard (bareconstin compiled output) becauseuseProxy()between its dependencies and definition prevented the compiler from grouping the closure. TheAgentDetailTimelineguard (slot 57 inAgentDetailView) depended onurlTransform, so it missed on every render, cascading a full conversation re-render into the scroll container.After:
urlTransformPropsobject is guarded on primitive string values (slot 157-160 inAgentDetail). InsideAgentDetailView,buildUrlTransformcall is guarded (slot 5). Timeline guard depends on stableurlTransform. Compiler lint: 0 diagnostics, 188 compiled functions (was 187).Vault patterns applied:
compiler-pattern-hook-interleaving,compiler-output-is-diagnosis-not-proof,compiler-pattern-usequery-whole-object-dep.