From 52d2fd0196614da3bb1e271ff504d988b760118c Mon Sep 17 00:00:00 2001 From: Kieran Klukas Date: Sat, 22 Aug 2026 10:16:54 -0400 Subject: [PATCH] feat: measure size of results --- src/client/app.css | 12 +++++++++--- src/client/app.js | 14 +++++++++++++- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/client/app.css b/src/client/app.css index e872e7b..3efb13e 100644 --- a/src/client/app.css +++ b/src/client/app.css @@ -1003,11 +1003,17 @@ body.selecting #selectBtn { the difference, and the bottom of the conversation is unreachable until a reload re-measures everything. - The growing turn is always the last one, so the last one is never skipped. - Older turns are static by the time they leave the viewport, which is the + The growing turn is USUALLY the last one, so the last one is never skipped. + The exception is a run that keeps going: its next message takes over as the + last turn while the previous one still has tools out, and their results land + documents in a turn that is now neither last nor generating. app.js marks any + turn it is still writing into `.live` (see assistantTurn). + + Everything else is static by the time it leaves the viewport, which is the case content-visibility is actually good at. */ .turn:last-child, -.turn.generating { +.turn.generating, +.turn.live { content-visibility: visible; } .turn:first-child { diff --git a/src/client/app.js b/src/client/app.js index 5d82cb2..5363c5f 100644 --- a/src/client/app.js +++ b/src/client/app.js @@ -842,7 +842,19 @@ import { mountSidebar } from "./sidebar.js"; } function assistantTurn(messageId) { - if (msgs[messageId]) return msgs[messageId]; + var have = msgs[messageId]; + if (have) { + // Every event for a turn arrives through here, which makes this the one + // place that knows a turn is still changing. A run's later messages push + // an earlier turn off `:last-child` while its tools are still out, and a + // tool result lands fifteen document cards in it — growth a SKIPPED turn + // never re-measures, which shortens `scrollHeight` and puts the end of the + // thread out of reach. Marking it keeps it measured for the rest of the + // session; history loads below stay skippable, which is where skipping + // earns its keep. + if (!bulkLoading) have.turn.classList.add("live"); + return have; + } var t = makeTurn("Assistant", "generating"); var rec = { turn: t, -- 2.51.2