Skip to content

Window Remote UI conversation history for iOS PWA stability - #176

Merged
firewalker06 merged 4 commits into
mainfrom
fizzy-226-conversation-tail-pagination
Sep 23, 2026
Merged

firewalker06 merged 4 commits into
mainfrom
fizzy-226-conversation-tail-pagination

Conversation

@firewalker06

Copy link
Copy Markdown
Owner

Fixes Fizzy #226.

Summary

  • window ordinary agent conversations to a bounded tail and page older blocks on demand
  • preserve full conversation metadata while avoiding a full-transcript digest on polling
  • prevent duplicate blocks when a live tail changes during older-page pagination
  • retain FRED’s bounded daily-session history without changing its conversation URL

Validation

  • bundle exec ruby test/remote_server_test.rb
  • bundle exec ruby test/remote_ui_conversation_loading_test.rb
  • node --check lib/hq/remote_ui/assets/app.js

Full bin/test and bin/remote-ui-smoke were started but their detached runs cannot persist in this managed environment, so rerun them in CI or a persistent shell before merge.

…(fizzy-226)

GET /agents/:key/conversation shipped the entire transcript in one JSON
payload with no cap, and the client rendered every block into the DOM in
one pass on view-open. For a finished agent with a 9.5MB raw.log / 1.8MB
memory.jsonl (1836 blocks), that is a ~1.1MB payload and ~37k DOM nodes on
open -- confirmed via an isolated fixture + real Chrome (mobile viewport,
4x CPU throttle): 36982 DOM nodes, 13.9MB JS heap, 3.09MB innerHTML before
this change. On iOS Safari's tighter per-tab memory ceiling this repeatedly
killed the WebKit content process (Fizzy #226).

Server: conversation_snapshot now defaults to the most recent 200 blocks
(capped at 2000 via ?limit=) and exposes the true total via
conversation_block_count/has_older so the revision/digest polling contract
is unchanged. Older pages are fetched with ?before=<blocks-already-loaded>,
a tail-relative cursor that stays correct even if new blocks land while
paging. The metadata digest is now a small fingerprint (total count + last
20 blocks) instead of SHA256(JSON.generate(full transcript)) on every poll
tick. Parsed blocks are cached per agent revision to avoid re-parsing
memory.jsonl on every request.

Client: tracks total/hasOlder separately from the rendered window so "N new
messages" math stays correct; adds a "Load older messages" control that
pages backward and preserves scroll position (primes the tail marker so the
existing sticky-to-bottom auto-scroll doesn't misfire on a prepend). FRED
(personal assistant) conversations still request the server's max window
since their reconciliation logic needs full session history and daily
sessions are bounded in practice.

After: 5620 DOM nodes, 6.6MB JS heap, 459KB innerHTML for the same fixture
-- confirmed in the same real-browser harness.

Added regression coverage in remote_server_test.rb proving a 500+ block
transcript stays windowed, pages contiguously, and metadata still reports
the true total.
@firewalker06
firewalker06 merged commit b7eb724 into main Sep 23, 2026
2 checks passed
@firewalker06
firewalker06 deleted the fizzy-226-conversation-tail-pagination branch September 23, 2026 15:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant