fix(desktop): surface compaction-archived messages in transcript reads (#80680) - #83757
Closed
zuowen7 wants to merge 2 commits into
Closed
fix(desktop): surface compaction-archived messages in transcript reads (#80680)#83757zuowen7 wants to merge 2 commits into
zuowen7 wants to merge 2 commits into
Conversation
zuowen7
force-pushed
the
fix/80680-include-compacted-display-history
branch
from
August 11, 2026 07:54
93a2c0b to
454dbb2
Compare
zuowen7
force-pushed
the
fix/80680-include-compacted-display-history
branch
from
August 11, 2026 08:11
454dbb2 to
28ca92d
Compare
…ed (NousResearch#80680) Dedupe key now includes tool_call_id/tool_calls/tool_name: compaction copies carry those fields verbatim, so identical tool messages across generations still collapse, while distinct tool calls sharing role/content/timestamp are never merged. Add endpoint-level coverage for the desktop's real read path (limit + order=latest + include_compacted=true).
Contributor
|
Thank you for this fix! It was salvaged into #86595 (cherry-picked onto current main with your authorship preserved in the commit history) and is now merged. Closing this PR since the work has landed. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Fixes #80680 — after in-place context compaction, earlier turns of a session become unreachable in Hermes Desktop: the transcript silently ends at the compaction boundary, "Show earlier messages" disappears, and no UI path recovers the history.
Root cause:
SessionDB.get_messages()defaults to active rows only (AND active = 1). In-place compaction archives earlier turns asactive=0, compacted=1rows — durable display history, not soft-deleted rows — but the desktop transcript read (getLatestSessionMessages→GET /api/sessions/{id}/messages) never asked for them. The UI exhausts its active-only array, the window reportsolderAvailable=false, and the control disappears even though older durable history exists.Real-world evidence (independent Windows reproduction in the issue thread): a session with
message_count=58held 509 rows — 451 of themactive=0, compacted=1and invisible.Related Issue
Fixes #80680
Type of Change
Changes Made
hermes_state.py—SessionDB.get_messages()gainsinclude_compacted: bool = False: when set, the read coversactive = 1 OR compacted = 1. Soft-deleted Undo/Rewind rows (active=0, compacted=0) stay excluded — that remains the job ofinclude_inactive(audit/debug reads), so the naive broadening the issue warns about is avoided.hermes_cli/web_routers/sessions.py—GET /api/sessions/{id}/messagesexposesinclude_compacted(defaultfalse; dashboard default view unchanged).apps/desktop/src/hermes.ts— desktop transcript loaders (getLatestSessionMessages,getAllSessionMessages) opt in, restoring the full display history.Note: enabling
includeCompactedongetAllSessionMessagesis a deliberate side effect — exports/artifact generation now include archived (compacted) display history, deduplicated, instead of live rows only. This matches the transcript view; if a caller ever needs live-only rows again it can passincludeCompacted: false.Deduplication across compaction epochs: each compaction epoch copies the protected tail into the new generation, so the same logical message exists as several rows with identical
role/content/timestamp(verified on a real state.db: one message appeared 4× across generations, 322 duplicate rows in a single session).include_compactedreads the full display set, dedupes on(role, content, timestamp)preferring the live row then the newest generation, and only then applies paging — so offset pages can never surface a duplicate. Genuine repeats with different timestamps are preserved.Rotating-compression lineage reconstruction (parent sessions) and server-authoritative
has_moreare intentionally out of scope — this is the minimal fix for the in-place compaction boundary, which is the observed failure mode.Relationship to the existing resume display lineage:
session.resumealready serves a display transcript viaget_resume_conversations/get_ancestor_display_prefix— but that reads rotating-compression ancestors (session_id IN (ancestors…) AND active = 1), i.e. earlier turns stored in parent sessions. It does not readactive=0, compacted=1rows, which is the in-place compaction half of the same problem. This PR is complementary: the REST transcript endpoint (the desktop's primary display path) now surfaces the in-place-archived rows the resume lineage never covered. The dedupe strategy here (prefer live row, then newest generation) matches the ancestor/tip dedupe#65919applied to the resume path.How to Test
pytest tests/hermes_state/test_get_messages_include_compacted.py -q→ 9 passed (default-read regression guard, archived rows surfaced, soft-deleted rows excluded,include_inactivesemantics unchanged,latestpaging,limit/offsetpaging, dedupe across generations).pytest tests/hermes_cli/test_web_server.py -q -k "compacted"→ 2 passed (endpoint default hides,include_compacted=truesurfaces archived rows in insertion order).active=0, compacted=1) behind 58 live rows —include_compacted=truereturns the full display history deduplicated (on a 1,100-row session: 1,026 raw rows → 704 logical messages).Note on the full suite: on a machine whose default DB path is a real Hermes home (like this dev machine),
tests/hermes_state/test_live_db_isolation_guard.pyand a few environment-dependent tests fail identically with and without this change (verified viagit stashcomparison) — they are unrelated pre-existing environment failures.Checklist
Code
fix(scope):,feat(scope):, etc.)pytestsuites and they pass (see How to Test; full-suite caveat documented above)Documentation & Housekeeping
docs/, docstrings) — docstrings for the new parameter cover the semantics — or N/Acli-config.yaml.exampleif I added/changed config keys — N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — N/AScreenshots / Logs
Real state.db evidence (from the #80680 thread):