mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-27 17:58:07 +00:00
Driving HER real instance (real profile, real transcripts, streams live)
via CDP instead of synthetic tiles finally exposed the remaining stall.
The timeline on a real 60-frame sash drag:
style recalc 2736ms | script 1027ms | layout 89ms
top callsite: pin @ fallback.tsx — 927ms
Two pin-to-bottom ResizeObservers (the bounded tool window's and the
reasoning preview's) pinned on EVERY resize delivery. A sash drag changes
every message's WIDTH once per frame, so each frame ran scrollTop write ->
scrollHeight read across every tool group: a forced write-read reflow
cascade that the render counters could never see (zero React involvement).
Both pins are now height-gated off the RO entry (reflow-free): only
content GROWTH pins. Width-only deliveries return immediately.
Measured on the live app, same drag, before -> after:
fps 11.5 -> 59-60
p95 101ms -> 18ms
slow>33 60/60 -> 1/60
Also in this batch (each was verified live before the next was attempted):
- thread/list: split messageSignature into STRUCTURAL (ids/roles — keys
boundaries + row identity) and WEIGHT (part counts — budget only), and
memoize groups + row JSX. A streamed part-append re-rendered every
turn's boundary via its resetKey prop; explain() measured 540-865
wasted Block renders per drag/stream sample, now {}.
- message-render-boundary: document the structural-only resetKey contract.
- tool/fallback: memoize ToolFallback's part object + ToolEntry/ToolTitle/
ToolGlyph (151 renders each, 100% wasted, on real transcripts).
- use-message-stream: ADAPTIVE flush floor — next flush waits 3x the
measured cost of the last one (33ms floor, 250ms cap), so multi-stream
load degrades text update rate instead of input latency.
- tree-split: preview sash drags with inline flex on the two seam
wrappers, committing the store ONCE on release (fixed-zone sides get
flexBasis only, so a hidden sidebar can't leave a phantom gap).
- debug/: perf-live LoAF long-frame attribution, explain() cascade walker
with changed-hook indices, diag-real-loop/key-latency/switch-trace
probes that drive the real app over CDP.
Typing during 2 live streams: keystroke->paint p50 3.3ms, p95 18.4ms,
zero frames over 33ms. Session switch p50 ~35ms settled; the remaining
~1.3s outlier tail is streaming-session switches (React work-loop, not
style/layout) — next target.
|
||
|---|---|---|
| .. | ||
| perf | ||
| .gitignore | ||
| after-pack.mjs | ||
| assert-dist-built.mjs | ||
| assert-dist-built.test.mjs | ||
| assert-root-install.mjs | ||
| before-build.mjs | ||
| before-pack.mjs | ||
| before-pack.test.mjs | ||
| bundle-electron-main.mjs | ||
| click-session.mjs | ||
| dev-mock.mjs | ||
| dev-no-hmr.mjs | ||
| diag-code-live.mjs | ||
| diag-drag-churn.mjs | ||
| diag-drag-trace.mjs | ||
| diag-jump.mjs | ||
| diag-key-latency.mjs | ||
| diag-live-state.mjs | ||
| diag-real-loop.mjs | ||
| diag-ro-storm.mjs | ||
| diag-scroll-reset.mjs | ||
| diag-sidebar-dom.mjs | ||
| diag-switch-trace.mjs | ||
| eval.mjs | ||
| gen-share-codes.ts | ||
| notarize-artifact.mjs | ||
| notarize.mjs | ||
| patch-electron-builder-mac-binary.mjs | ||
| probe-model-picker.mjs | ||
| probe-renderer.mjs | ||
| probe-thread.mjs | ||
| profile-model-picker.mjs | ||
| profile-typing-lag.md | ||
| rebuild-native.mjs | ||
| reload-renderer.mjs | ||
| reload.mjs | ||
| run-electron-builder.mjs | ||
| set-exe-identity.mjs | ||
| stage-native-deps.mjs | ||
| stage-native-deps.test.mjs | ||
| test-desktop.mjs | ||
| utils.mjs | ||
| write-build-stamp.mjs | ||
| write-build-stamp.test.mjs | ||