| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
There was a problem hiding this comment.
This PR improves the desktop session timeline’s scroll stability and rendering performance for long, mixed-content conversations by migrating timeline virtualization to TanStack Virtual, tightening anchor/scroll preservation during history prepends, and moving streaming Markdown code highlighting off the main thread (while keeping code block DOM stable during streaming updates).
Changes:
Copilot reviewed 30 out of 31 changed files in this pull request and generated 3 comments.
Show a summary per file| File | Description |
|---|---|
| patches/virtua@0.49.1.patch | Removes the repo’s virtua patch now that the timeline moves away from virtua. |
| patches/@TanStack%2Fsolid-virtual@3.13.28.patch | Patches Solid Virtual to stabilize updates/reconciliation behavior for virtual items. |
| packages/ui/src/pierre/virtualizer.ts | Updates Pierre virtual metrics API usage (fileGap → spacing). |
| packages/ui/src/pierre/index.ts | Adjusts diff CSS variable overrides for Pierre 1.2 behavior. |
| packages/ui/src/context/marked.tsx | Exports OpenCodeTheme for reuse (worker init), plus minor theme updates. |
| packages/ui/src/components/scroll-view.tsx | Reworks thumb-drag scrolling math to avoid inverted motion during content height changes. |
| packages/ui/src/components/scroll-view.test.ts | Adds unit tests for the new thumb-drag scroll mapping/clamping. |
| packages/ui/src/components/message-part.tsx | Introduces onContentRendered plumbing to notify parent virtualizers when async-sized content finishes rendering. |
| packages/ui/src/components/markdown.tsx | Refactors Markdown rendering into keyed blocks; adds streaming code highlighting with stable code DOM and incremental token updates. |
| packages/ui/src/components/markdown.css | Adds margin normalization for block-wrapped Markdown rendering. |
| packages/ui/src/components/markdown-worker.ts | Adds worker lifecycle + request/response management for streaming code highlighting. |
| packages/ui/src/components/markdown-worker-protocol.ts | Defines the worker protocol and stable/unstable token accumulation logic. |
| packages/ui/src/components/markdown-worker-protocol.test.ts | Adds unit tests for worker token accumulation/reset semantics. |
| packages/ui/src/components/markdown-stream.ts | Adds block projection to avoid re-parsing frozen blocks and to stream code fences more efficiently. |
| packages/ui/src/components/markdown-stream.test.ts | Extends tests for new block/projection behavior and code-fence streaming. |
| packages/ui/src/components/markdown-shiki.worker.ts | Implements the Shiki tokenizer/highlighter inside a dedicated worker. |
| packages/ui/src/components/file.tsx | Updates Pierre virtual metrics usage (fileGap → spacing). |
| packages/ui/package.json | Adds @shikijs/stream; removes virtua dependency from UI workspace. |
| packages/app/src/pages/session/message-timeline.tsx | Rebuilds timeline virtualization with TanStack Virtual; adds prepend anchor capture/restore and async content measurement integration. |
| packages/app/src/pages/session/message-timeline.data.ts | Adds a TurnGap row type and refactors spacing logic away from frame padding flags. |
| packages/app/src/pages/session.tsx | Hooks history loader into timeline anchor capture/restore; adjusts autoscroll integration (including overflowAnchor: "none"). |
| packages/app/src/context/global-sync/event-reducer.ts | Fixes streaming text delta accumulation to start from existing part content instead of only the latest delta. |
| packages/app/src/context/global-sync/event-reducer.test.ts | Adds regression test ensuring delta accumulation initializes from current part text. |
| packages/app/package.json | Adds @tanstack/solid-virtual; removes virtua from app workspace dependencies. |
| packages/app/e2e/utils/mock-server.ts | Adds message delay hooks and SSE retry: support to help reproduce timing-sensitive timeline scenarios. |
| packages/app/e2e/smoke/session-timeline.spec.ts | Adds smoke test asserting visible message position is preserved while history is prepended; verifies bottom spacer behavior. |
| packages/app/e2e/regression/session-timeline-context-resize.spec.ts | Removes logging; tweaks sampling to capture post-paint overlap behavior. |
| packages/app/e2e/regression/session-timeline-collapse-state.spec.ts | Strengthens regression assertions around diff/tool row stability; adds sticky header alignment regression test. |
| package.json | Bumps @pierre/diffs to 1.2.10, shiki to 4.2.0; adds @shikijs/stream and @tanstack/solid-virtual; removes virtua; wires patch for Solid Virtual. |
| bunfig.toml | Expands minimumReleaseAgeExcludes to include Pierre packages (diffs/theming). |
| bun.lock | Updates lockfile for dependency bumps/removals and patched dependencies list. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Sorry, something went wrong.
| while (true) { | ||
| await input.loadMore(id) | ||
| input.onAfterLoad?.() | ||
| if (input.sessionID() !== id) return | ||
|
|
||
| const nextLoaded = input.loaded() |
| onBeforeElUpdated: (fromEl, toEl) => { | ||
| if ( | ||
| fromEl instanceof HTMLButtonElement && | ||
| toEl instanceof HTMLButtonElement && | ||
| fromEl.getAttribute("data-slot") === "markdown-copy-button" && | ||
| toEl.getAttribute("data-slot") === "markdown-copy-button" | ||
| ) { | ||
| return false | ||
| } |
| const code = existing?.querySelector("code") | ||
| if (code instanceof HTMLElement) { | ||
| code.className = `language-${block.language}` | ||
| const previous = renderedCodeTokens.get(next) | ||
| const reset = !previous || previous.language !== block.language || block.stable.length < previous.stableCount | ||
| const stableCount = reset ? 0 : previous.stableCount | ||
| const tail = [...block.stable.slice(stableCount), ...block.unstable] | ||
| const prior = reset ? [] : previous.unstable | ||
| const prefix = prior.findIndex((token, index) => !sameToken(token, tail[index])) | ||
| const keep = stableCount + (prefix < 0 ? Math.min(prior.length, tail.length) : prefix) | ||
| while (code.children.length > keep) code.lastElementChild?.remove() | ||
| tail.slice(keep - stableCount).map(createTokenSpan).forEach((span) => code.appendChild(span)) | ||
| renderedCodeTokens.set(next, { | ||
| language: block.language, | ||
| stableCount: block.stable.length, | ||
| unstable: block.unstable, | ||
| }) | ||
| return | ||
| } |
…rtual-session # Conflicts: # bun.lock # package.json
…rtual-session # Conflicts: # bun.lock # package.json
…thout flicker or scroll jumps
* upstream: (4536 commits) fix(opencode): sanitize OpenAI MCP tool schemas (anomalyco#32489) chore: update nix node_modules hashes fix(provider): pass apiKey to createUnified for Cloudflare AI Gateway (anomalyco#32052) chore: generate feat(app): make session timelines much faster AND without flicker or scroll jumps (anomalyco#32331) chore: update nix node_modules hashes chore: generate experiment: better web picker using @pierre/tree (anomalyco#31208) fix(mcp): default tool schema properties (anomalyco#32568) fix(web): persist docs language selection (anomalyco#32551) fix(tui): render move errors inline (anomalyco#32241) Revert "fix(mcp): type tool error content" fix(mcp): enable progress timeout resets (anomalyco#32477) fix(mcp): stop idle OAuth callback server (anomalyco#32245) chore: generate chore: update nix node_modules hashes fix(mcp): type tool error content fix(stats): align homepage model ranks fix(mcp): handle tool result errors (anomalyco#32244) fix(stats): rank model pages by week ...
| Back | FazBrowse Home | New Git URL |
Key results
Merge comparison
Summary
User-visible changes
Stability
Streaming
Architecture
session.tsx -> timeline/model.ts session synchronization, filtering, pagination policy -> timeline/message-timeline.tsx -> timeline/projection.ts reactive message-to-row projection and identity reuse -> timeline/rows.ts pure semantic row construction, keys, equalitymessage-timeline.tsx now owns browser presentation concerns only: TanStack Virtual, row rendering, measurement, gestures, sticky UI, and anchor registration.
Performance methodology
Performance results
MacBook Air: session tab switching
Native speed, median of five fresh browser contexts.
The earlier PR implementation measured approximately 330ms cold; the staged bottom-first mount reduced the current committed result to 54.2ms.
Windows: session tab switching
Native Chromium, no CPU slowdown, median of five fresh browser contexts.
MacBook Air: realistic busy streaming at 30x CPU stress
Exact pushed head 411847bb0, 320 heavy historical turns, provider-like fragments.
This heavier diagnostic fixture exceeds the old 1,000ms long-task assertion on both branches. The assertion is not claimed as a passing CI performance gate; the relative measurements and visual invariants are the comparison.
Windows: realistic busy streaming, native capped UX
360 provider-like fragments delivered in bursts of eight. No CPU slowdown.
At 40 turns, upstream produced 22 frames below 30 FPS, two frames below 20 FPS, and 53 dropped-frame equivalents. The PR produced zero for all three and applied all 360 fragments.
Windows: exploratory uncapped Chromium
--disable-frame-rate-limit --disable-gpu-vsync is retained only as secondary throughput evidence because rAF pacing remains machine/driver dependent.
The capped UX table is the authoritative Windows result.
Stability verification
Committed coverage
Ignored local diagnostics
These high-volume tests live under ignored packages/app/e2e/local/ and are intentionally not included in the PR diff.
Root causes fixed during validation
Dependencies and upstream work
Verification summary
Remaining performance headroom