fix: keep pinned chat following final summaries

This commit is contained in:
Bohdan Triapitsyn
2026-05-25 02:13:00 +03:00
parent f6c76239c5
commit 8f45596c99
+11 -23
View File
@@ -122,8 +122,6 @@ export const useChatAutoFollow = ({
const [isFollowingProgrammatically, setIsFollowingProgrammatically] = React.useState(false); const [isFollowingProgrammatically, setIsFollowingProgrammatically] = React.useState(false);
const stateRef = React.useRef<AutoFollowState>('following'); const stateRef = React.useRef<AutoFollowState>('following');
const sessionWorkingRef = React.useRef(sessionIsWorking);
sessionWorkingRef.current = sessionIsWorking;
const sessionMessageCountRef = React.useRef(sessionMessageCount); const sessionMessageCountRef = React.useRef(sessionMessageCount);
sessionMessageCountRef.current = sessionMessageCount; sessionMessageCountRef.current = sessionMessageCount;
const currentSessionIdRef = React.useRef(currentSessionId); const currentSessionIdRef = React.useRef(currentSessionId);
@@ -189,7 +187,7 @@ export const useChatAutoFollow = ({
stopFollowLoop(); stopFollowLoop();
return; return;
} }
if (stateRef.current !== 'following' || !sessionWorkingRef.current) { if (stateRef.current !== 'following') {
stopFollowLoop(); stopFollowLoop();
return; return;
} }
@@ -224,7 +222,7 @@ export const useChatAutoFollow = ({
const startFollowLoop = React.useCallback(() => { const startFollowLoop = React.useCallback(() => {
if (typeof window === 'undefined') return; if (typeof window === 'undefined') return;
if (followRafRef.current !== null) return; if (followRafRef.current !== null) return;
if (stateRef.current !== 'following' || !sessionWorkingRef.current) return; if (stateRef.current !== 'following') return;
settledFramesRef.current = 0; settledFramesRef.current = 0;
setIsFollowingProgrammatically(true); setIsFollowingProgrammatically(true);
followRafRef.current = window.requestAnimationFrame(tickFollow); followRafRef.current = window.requestAnimationFrame(tickFollow);
@@ -293,17 +291,13 @@ export const useChatAutoFollow = ({
setStateValue('following'); setStateValue('following');
lastUserReleaseAtRef.current = 0; lastUserReleaseAtRef.current = 0;
if (!container) return; if (!container) return;
if (mode === 'smooth' && sessionWorkingRef.current) { if (mode === 'smooth') {
startFollowLoop(); startFollowLoop();
return; return;
} }
const target = Math.max(0, container.scrollHeight - container.clientHeight); const target = Math.max(0, container.scrollHeight - container.clientHeight);
writeScrollTopInstant(target); writeScrollTopInstant(target);
if (sessionWorkingRef.current) { startSettleBurst();
startFollowLoop();
} else {
startSettleBurst();
}
}, [setStateValue, startFollowLoop, startSettleBurst, writeScrollTopInstant]); }, [setStateValue, startFollowLoop, startSettleBurst, writeScrollTopInstant]);
const flushSave = React.useCallback(() => { const flushSave = React.useCallback(() => {
@@ -371,9 +365,7 @@ export const useChatAutoFollow = ({
lastUserReleaseAtRef.current = 0; lastUserReleaseAtRef.current = 0;
const target = Math.max(0, container.scrollHeight - container.clientHeight); const target = Math.max(0, container.scrollHeight - container.clientHeight);
writeScrollTopInstant(target); writeScrollTopInstant(target);
if (sessionWorkingRef.current) { startFollowLoop();
startFollowLoop();
}
startSettleBurst(); startSettleBurst();
return false; return false;
} }
@@ -413,12 +405,10 @@ export const useChatAutoFollow = ({
}, [currentSessionId, flushSave, markProgrammaticWrite, stopFollowLoop, stopSettleBurst]); }, [currentSessionId, flushSave, markProgrammaticWrite, stopFollowLoop, stopSettleBurst]);
React.useEffect(() => { React.useEffect(() => {
if (!sessionIsWorking) { if (sessionIsWorking && stateRef.current === 'following') {
stopFollowLoop();
} else if (stateRef.current === 'following') {
startFollowLoop(); startFollowLoop();
} }
}, [sessionIsWorking, startFollowLoop, stopFollowLoop]); }, [sessionIsWorking, startFollowLoop]);
// Replay a deferred restoreSnapshot once ChatViewport mounts. // Replay a deferred restoreSnapshot once ChatViewport mounts.
React.useEffect(() => { React.useEffect(() => {
@@ -471,9 +461,7 @@ export const useChatAutoFollow = ({
const inGrace = (now - lastUserReleaseAtRef.current) < REPIN_GRACE_AFTER_RELEASE_MS; const inGrace = (now - lastUserReleaseAtRef.current) < REPIN_GRACE_AFTER_RELEASE_MS;
if (stateRef.current === 'released' && isNearBottom(container, isMobile) && !inGrace) { if (stateRef.current === 'released' && isNearBottom(container, isMobile) && !inGrace) {
setStateValue('following'); setStateValue('following');
if (sessionWorkingRef.current) { startFollowLoop();
startFollowLoop();
}
} }
queueSave(); queueSave();
@@ -564,7 +552,7 @@ export const useChatAutoFollow = ({
const observer = new ResizeObserver(() => { const observer = new ResizeObserver(() => {
updateOverflowAndButton(); updateOverflowAndButton();
if (stateRef.current === 'following' && sessionWorkingRef.current) { if (stateRef.current === 'following') {
startFollowLoop(); startFollowLoop();
} }
}); });
@@ -583,7 +571,7 @@ export const useChatAutoFollow = ({
const notifyContentChange = React.useCallback((_reason?: ContentChangeReason) => { const notifyContentChange = React.useCallback((_reason?: ContentChangeReason) => {
void _reason; void _reason;
updateOverflowAndButton(); updateOverflowAndButton();
if (stateRef.current === 'following' && sessionWorkingRef.current) { if (stateRef.current === 'following') {
startFollowLoop(); startFollowLoop();
} }
}, [startFollowLoop, updateOverflowAndButton]); }, [startFollowLoop, updateOverflowAndButton]);
@@ -595,7 +583,7 @@ export const useChatAutoFollow = ({
if (cached) return cached; if (cached) return cached;
const kick = () => { const kick = () => {
if (stateRef.current === 'following' && sessionWorkingRef.current) { if (stateRef.current === 'following') {
startFollowLoop(); startFollowLoop();
} }
}; };