perf: reduce UI render fanout and scroll jitter
- Cut broad render fanout across the app by replacing shared-store whole-object subscriptions with leaf selectors, memoizing hot chrome boundaries, and isolating disabled global providers from live session/message state. This keeps header controls, composer toolbars, side panels, and other non-hot UI surfaces from repainting on every assistant update or keystroke. - Rework sidebar session ordering so recent, project groups, and worktree groups derive from one ordering source while avoiding streaming-time thrash. The sidebar now uses a stabilized session snapshot, preserves structural identity for unchanged rows, reads live row status/details per session, and applies a one-shot sort bump on idle->busy instead of continuously resorting during activity. - Fix chat/input scroll instability by separating viewport-resize handling from message-growth handling, disabling conflicting native scroll anchoring, and stopping textarea autosize from collapsing on every growth keystroke. This removes the multiline typing jiggle during streaming and reduces unnecessary composer rerenders. - Also gate voice context wiring behind voice-mode enablement and codify the learned render/scroll/order anti-patterns in AGENTS.md so future changes avoid the same classes of regressions.
This commit is contained in:
@@ -293,25 +293,23 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
onMobilePanelSelection,
|
||||
onAgentPanelSelection,
|
||||
}) => {
|
||||
const {
|
||||
providers,
|
||||
currentProviderId,
|
||||
currentModelId,
|
||||
currentVariant,
|
||||
currentAgentName,
|
||||
settingsDefaultVariant,
|
||||
settingsDefaultAgent,
|
||||
setProvider,
|
||||
setSelectedProvider,
|
||||
setModel,
|
||||
setCurrentVariant,
|
||||
getCurrentModelVariants,
|
||||
setAgent,
|
||||
getCurrentProvider,
|
||||
getModelMetadata,
|
||||
getCurrentAgent,
|
||||
getVisibleAgents,
|
||||
} = useConfigStore();
|
||||
const providers = useConfigStore((state) => state.providers);
|
||||
const currentProviderId = useConfigStore((state) => state.currentProviderId);
|
||||
const currentModelId = useConfigStore((state) => state.currentModelId);
|
||||
const currentVariant = useConfigStore((state) => state.currentVariant);
|
||||
const currentAgentName = useConfigStore((state) => state.currentAgentName);
|
||||
const settingsDefaultVariant = useConfigStore((state) => state.settingsDefaultVariant);
|
||||
const settingsDefaultAgent = useConfigStore((state) => state.settingsDefaultAgent);
|
||||
const setProvider = useConfigStore((state) => state.setProvider);
|
||||
const setSelectedProvider = useConfigStore((state) => state.setSelectedProvider);
|
||||
const setModel = useConfigStore((state) => state.setModel);
|
||||
const setCurrentVariant = useConfigStore((state) => state.setCurrentVariant);
|
||||
const getCurrentModelVariants = useConfigStore((state) => state.getCurrentModelVariants);
|
||||
const setAgent = useConfigStore((state) => state.setAgent);
|
||||
const getCurrentProvider = useConfigStore((state) => state.getCurrentProvider);
|
||||
const getModelMetadata = useConfigStore((state) => state.getModelMetadata);
|
||||
const getCurrentAgent = useConfigStore((state) => state.getCurrentAgent);
|
||||
const getVisibleAgents = useConfigStore((state) => state.getVisibleAgents);
|
||||
|
||||
// Use visible agents (excludes hidden internal agents)
|
||||
const agents = getVisibleAgents();
|
||||
@@ -321,15 +319,13 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
const getDirectoryForSession = useSessionUIStore((s) => s.getDirectoryForSession);
|
||||
const sync = useSync();
|
||||
|
||||
const {
|
||||
getSessionModelSelection,
|
||||
saveSessionModelSelection,
|
||||
saveSessionAgentSelection,
|
||||
saveAgentModelForSession,
|
||||
getAgentModelForSession,
|
||||
saveAgentModelVariantForSession,
|
||||
getAgentModelVariantForSession,
|
||||
} = useSelectionStore();
|
||||
const getSessionModelSelection = useSelectionStore((state) => state.getSessionModelSelection);
|
||||
const saveSessionModelSelection = useSelectionStore((state) => state.saveSessionModelSelection);
|
||||
const saveSessionAgentSelection = useSelectionStore((state) => state.saveSessionAgentSelection);
|
||||
const saveAgentModelForSession = useSelectionStore((state) => state.saveAgentModelForSession);
|
||||
const getAgentModelForSession = useSelectionStore((state) => state.getAgentModelForSession);
|
||||
const saveAgentModelVariantForSession = useSelectionStore((state) => state.saveAgentModelVariantForSession);
|
||||
const getAgentModelVariantForSession = useSelectionStore((state) => state.getAgentModelVariantForSession);
|
||||
|
||||
const contextHydrated = useContextStore((state) => state.hasHydrated);
|
||||
|
||||
@@ -355,19 +351,17 @@ export const ModelControls: React.FC<ModelControlsProps> = ({
|
||||
? (sessionSavedAgentName || stickySessionAgentName || currentAgentName)
|
||||
: currentAgentName;
|
||||
|
||||
const {
|
||||
toggleFavoriteModel,
|
||||
isFavoriteModel,
|
||||
collapsedModelProviders,
|
||||
toggleModelProviderCollapsed,
|
||||
addRecentModel,
|
||||
addRecentAgent,
|
||||
addRecentEffort,
|
||||
isModelSelectorOpen,
|
||||
setModelSelectorOpen,
|
||||
setSettingsDialogOpen,
|
||||
setSettingsPage,
|
||||
} = useUIStore();
|
||||
const toggleFavoriteModel = useUIStore((state) => state.toggleFavoriteModel);
|
||||
const isFavoriteModel = useUIStore((state) => state.isFavoriteModel);
|
||||
const collapsedModelProviders = useUIStore((state) => state.collapsedModelProviders);
|
||||
const toggleModelProviderCollapsed = useUIStore((state) => state.toggleModelProviderCollapsed);
|
||||
const addRecentModel = useUIStore((state) => state.addRecentModel);
|
||||
const addRecentAgent = useUIStore((state) => state.addRecentAgent);
|
||||
const addRecentEffort = useUIStore((state) => state.addRecentEffort);
|
||||
const isModelSelectorOpen = useUIStore((state) => state.isModelSelectorOpen);
|
||||
const setModelSelectorOpen = useUIStore((state) => state.setModelSelectorOpen);
|
||||
const setSettingsDialogOpen = useUIStore((state) => state.setSettingsDialogOpen);
|
||||
const setSettingsPage = useUIStore((state) => state.setSettingsPage);
|
||||
const hiddenModels = useUIStore((state) => state.hiddenModels);
|
||||
const collapsedProviderSet = React.useMemo(
|
||||
() => new Set(collapsedModelProviders.map((providerId) => providerId.trim()).filter(Boolean)),
|
||||
|
||||
Reference in New Issue
Block a user