Merge branch 'fix/janky-scroll-performance'

This commit is contained in:
Mohamed Boudra
2026-02-23 15:48:01 +07:00
3 changed files with 30 additions and 16 deletions
@@ -636,6 +636,14 @@ export function AgentStreamView({
] ]
); );
// Keep maintainVisibleContentPosition shape and values stable to avoid
// reconfiguring RN's internal anchoring logic during streaming transitions.
// We rely on our own follow-tail logic, so keep threshold at 0.
const maintainVisibleContentPosition = useMemo(
() => ({ minIndexForVisible: 0, autoscrollToTopThreshold: 0 }),
[]
);
// FlatList's ListHeaderComponent renders at the *bottom* when inverted. // FlatList's ListHeaderComponent renders at the *bottom* when inverted.
// Without explicit spacing, the newest "head" rows (like Thinking/Setup tool badges) // Without explicit spacing, the newest "head" rows (like Thinking/Setup tool badges)
// can butt up directly against the most recent stream item. // can butt up directly against the most recent stream item.
@@ -709,12 +717,7 @@ export function AgentStreamView({
ListEmptyComponent={listEmptyComponent} ListEmptyComponent={listEmptyComponent}
ListHeaderComponent={listHeaderComponent} ListHeaderComponent={listHeaderComponent}
extraData={flatListExtraData} extraData={flatListExtraData}
maintainVisibleContentPosition={ maintainVisibleContentPosition={maintainVisibleContentPosition}
// Disable when streaming and user is at bottom - we handle auto-scroll ourselves
agent.status === "running" && isNearBottom
? undefined
: { minIndexForVisible: 0, autoscrollToTopThreshold: 40 }
}
initialNumToRender={12} initialNumToRender={12}
windowSize={10} windowSize={10}
scrollEnabled={Platform.OS !== "web" || expandedInlineToolCallIds.size === 0} scrollEnabled={Platform.OS !== "web" || expandedInlineToolCallIds.size === 0}
+14 -8
View File
@@ -803,16 +803,22 @@ function SessionProviderInternal({
) { ) {
setAgentTimelineCursor(serverId, (prev) => { setAgentTimelineCursor(serverId, (prev) => {
const current = prev.get(agentId); const current = prev.get(agentId);
const next = new Map(prev); if (current && current.epoch === epoch) {
if (!current || current.epoch !== epoch) { // Fast-path: seq only extends the range during streaming.
next.set(agentId, { epoch, startSeq: seq, endSeq: seq }); // Skip the Map copy when nothing actually changes.
if (seq >= current.startSeq && seq <= current.endSeq) {
return prev;
}
const next = new Map(prev);
next.set(agentId, {
epoch,
startSeq: Math.min(current.startSeq, seq),
endSeq: Math.max(current.endSeq, seq),
});
return next; return next;
} }
next.set(agentId, { const next = new Map(prev);
epoch, next.set(agentId, { epoch, startSeq: seq, endSeq: seq });
startSeq: Math.min(current.startSeq, seq),
endSeq: Math.max(current.endSeq, seq),
});
return next; return next;
}); });
} }
+7 -2
View File
@@ -546,11 +546,15 @@ export const useSessionStore = create<SessionStore>()(
return prev; return prev;
} }
logSessionStoreUpdate("setFocusedAgentId", serverId, { agentId }); logSessionStoreUpdate("setFocusedAgentId", serverId, { agentId });
return { return {
...prev, ...prev,
sessions: { sessions: {
...prev.sessions, ...prev.sessions,
[serverId]: { ...session, focusedAgentId: agentId }, [serverId]: {
...session,
focusedAgentId: agentId,
},
}, },
}; };
}); });
@@ -563,7 +567,8 @@ export const useSessionStore = create<SessionStore>()(
if (!session) { if (!session) {
return prev; return prev;
} }
const nextMessages = typeof messages === "function" ? messages(session.messages) : messages; const nextMessages =
typeof messages === "function" ? messages(session.messages) : messages;
if (session.messages === nextMessages) { if (session.messages === nextMessages) {
return prev; return prev;
} }