[eric] streaming: an open chat scrolled off screen downshifts to the 1Hz buffer and flushes the instant it returns (ENG-329)

This commit is contained in:
ciregenz
2026-08-16 21:47:33 -07:00
parent 2db49cc0e8
commit bc368ba2fd
@@ -452,6 +452,31 @@ const AgentChat: React.FC<AgentChatProps> = ({ sessionId: sessionIdProp, onClose
};
}, [id, isDraft, dispatch]);
// An OPEN chat whose card sits off screen still streamed at frame rate for nobody; downshift its
// socket to the 1Hz background buffer while invisible, and flush synchronously the moment it
// scrolls back in (the buffer's reopen contract), so a visible transcript is never behind.
useEffect(() => {
const el = scrollContainerRef.current;
if (!el || typeof IntersectionObserver === 'undefined') return undefined;
let hideTimer: ReturnType<typeof setTimeout> | null = null;
const io = new IntersectionObserver((entries) => {
const visible = entries.some((e) => e.isIntersecting);
if (visible) {
if (hideTimer) { clearTimeout(hideTimer); hideTimer = null; }
wsRef.current?.setBackgrounded(false);
} else if (!hideTimer) {
// 2s of hysteresis so a pan that clips the card for a beat never churns the mode.
hideTimer = setTimeout(() => { hideTimer = null; wsRef.current?.setBackgrounded(true); }, 2000);
}
}, { threshold: 0 });
io.observe(el);
return () => {
if (hideTimer) clearTimeout(hideTimer);
io.disconnect();
wsRef.current?.setBackgrounded(false);
};
}, [id]);
useEffect(() => {
if (initialContextApplied.current || !initialContextPaths?.length) return;
const timer = setTimeout(() => {