Keeping the conversation log fast as it grows: paging, day headers, and a per-message cap
The ⌘L conversation log rendered all of its (up to 800) merged turns at once via react-markdown, and read the whole transcript file into memory each open — fine now, a real scaling problem for a daily driver where one session's transcript is already 31 MB. Added the standard, low-risk handling the user asked for: render only the recent 60 turns with a 'load older' control, group by date (Today / Yesterday / a date), and cap each message's text on the backend so one giant turn can't bloat the payload or the DOM.
The concern (the user's, and it's right)
The conversation log accumulates fast. As-is, read_transcript capped at the recent 800 turns with a truncated flag — that stops an unbounded explosion, but nothing more: no paging, no day grouping, no virtualization. So LogPanel mounted all 800 merged turns through react-markdown at once, and the backend read the whole transcript file (one real session is already 31 MB) into memory on every open. Honest verdict: "stopped it from exploding," not "handles scale." It will get heavy.
The fix (what the user asked for: day / paging)
Chose paging + date headers over full react-window virtualization — it's the literal ask, lower-risk (no variable-height measuring of markdown), and verifiable:
- Paging —
LogPanelrenders only the most recent 60 turns; a centered "↑ Load N older" button reveals 80 more at a time. A huge session never mounts thousands of markdown blocks at once. - Day headers — a Today / Yesterday / date divider when the date changes between turns, so long logs are navigable, not an undifferentiated wall.
- Per-message cap (backend) — each turn's text is truncated to ~8 000 chars with a
*(truncated — N chars)*marker, so one giant turn can't bloat the payload or a single DOM node. (My own long responses are exactly this risk.)
Honest status + what's deferred
- This is the render-side scaling fix. The backend still does
read_to_stringof the full file each open — fast in Rust (sub-100 ms) but not free; a true tail / incremental read (parse only the recent turns without slurping 31 MB) is the next step, deferred because it needs restructuring the turn-segmentation. - No virtualization yet — paging caps the DOM instead, which is enough until sessions get truly enormous;
react-windowis the eventual upgrade. - Blind-built — the paging/day-header layout needs eyes on the running app to confirm it reads well.