Skip to content

perf(state): batch compression-tip row fetch in list_sessions_rich (salvage #59077) - #77626

Merged
kshitijk4poor merged 3 commits into
NousResearch:mainfrom
kshitijk4poor:salvage/59077-batch-tip-rows
Aug 3, 2026
Merged

perf(state): batch compression-tip row fetch in list_sessions_rich (salvage #59077)#77626
kshitijk4poor merged 3 commits into
NousResearch:mainfrom
kshitijk4poor:salvage/59077-batch-tip-rows

Conversation

@kshitijk4poor

Copy link
Copy Markdown
Collaborator

Context

The session sidebar (desktop/web/TUI) lists sessions via list_sessions_rich. For every compression chain on the page it ran TWO extra queries per root (tip walk + tip-row fetch) — a classic N+1: a page with K compression roots cost 2K+1 queries. WHO benefits: anyone with long-running sessions that compress (heavy users have dozens of compression roots per page), on every sidebar refresh / "load more".

Measured impact

Synthetic DB, 200 sessions / 50 compression chains 3-deep, list_sessions_rich(project_compression_tips=True), alternating A/B runs, median of 5 x 3 rounds:

metric before after delta
SELECTs per page 201 152 K+1 instead of 2K+1 tip queries
enriched tip-row SELECTs 51 2 25x fewer
wall time 4.91-5.01 ms 4.43-4.52 ms ~10%

Honest caveat: on this synthetic (small, warm-cache) DB the wall-time win is modest because each per-root query was cheap; the query-count reduction is the durable win and grows with DB size and root count (the per-root graph walk in get_compression_tip remains — this batches only the tip-ROW fetch, which is the enriched/expensive half).

Provenance

Salvage of #59077 by @jasoisjaso (authorship preserved on the base commit; attribution mapping merged as #77600). The PR predates the compact_rows projection (#47437) — the salvage threads compact_rows through the new batch helper and reuses the schema-derived projection instead of the original hardcoded SELECT s.*. _get_session_rich_row is now a thin wrapper so the enriched SELECT lives in exactly one place. Follow-up commits: a guard test for the compact_rows threading (mutation-checked: reverting the threading fails it) and a simplify-pass fold chunking the IN clause at 900 ids (old SQLite builds cap bound variables at 999; limit=10000 callers exist in web_server).

Verification

  • 166 passed (tests/test_hermes_state.py, -p no:randomly), including the new batch-projection guards.
  • Mutation check: dropping the compact_rows threading turns the guard test RED.
  • Simplify pass: 1 finding (IN-clause bound) folded; REUSE/EFFICIENCY clean.
  • Adversarial: shared-tip dedup via set() verified; ordering stability preserved (projection falls through to the original row when the tip is absent).

Closes #59077.

jasoisjaso and others added 3 commits August 3, 2026 16:02
list_sessions_rich()'s compression-root projection called
_get_session_rich_row() once per root — a separate single-row query per
compression root on every session-list render. Resolve every tip id
first, then fetch all tip rows in one WHERE id IN (...) query via the
new _get_session_rich_rows_batch().

_get_session_rich_row() is now a thin wrapper over the batch method, so
the enriched SELECT (preview + last_active) lives in exactly one place —
future column changes (e.g. NousResearch#42196's include_system_prompt) only touch
one query.

get_compression_tip()'s chain walk is untouched; it's a genuine
per-session graph walk with branch/delegate-exclusion and race handling,
and batching it safely is out of scope here.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds two regression tests for the NousResearch#59077 batch: (1) _get_session_rich_rows_batch(compact_rows=True) uses the schema-derived compact projection (no system_prompt, git_branch/git_repo_root kept); (2) list_sessions_rich(compact_rows=True) threads compact_rows through the compression-tip projection call site. Mutation-checked: hardcoding compact_rows=False at the call site fails test 2.
Simplify-pass fold: SQLITE_MAX_VARIABLE_NUMBER is 999 on pre-3.32\nbuilds (which the repo still supports — the trigram-availability\nmachinery exists for exactly that class), and limit=10000\nlist_sessions_rich callers exist in web_server. Chunk inside the\nbatch helper — the single choke point — so no call site can overflow.
@kshitijk4poor
kshitijk4poor enabled auto-merge (rebase) August 3, 2026 11:59
@kshitijk4poor
kshitijk4poor merged commit 7db2827 into NousResearch:main Aug 3, 2026
35 checks passed
@alt-glitch alt-glitch added type/perf Performance improvement or optimization P3 Low — cosmetic, nice to have comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state labels Aug 3, 2026
@kshitijk4poor
kshitijk4poor deleted the salvage/59077-batch-tip-rows branch August 5, 2026 07:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P3 Low — cosmetic, nice to have sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/perf Performance improvement or optimization

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants