Show pre-compaction conversation history in session view#63
Merged
Conversation
When Claude Code compacts a session it writes a compact_boundary entry (type:"system", subtype:"compact_boundary") with parentUuid:null and logicalParentUuid pointing to the last pre-compact message. This broke the live-chain walk — the backward traversal from the live tip stopped at the boundary because parentUuid was empty, leaving all pre-compact messages invisible in the UI. Changes: entry.rs - Add logical_parent_uuid field (from logicalParentUuid) so compact_boundary entries can carry the pre-compact chain link. - Add is_compact_summary field (from isCompactSummary) to identify the AI-generated summary user entry Claude Code injects after compaction. session.rs / resolve_live_chain_uuids - When the backward walk reaches an entry whose parentUuid is empty but logicalParentUuid is set, follow logicalParentUuid instead of stopping. This makes all pre-compaction messages part of the live chain, so they appear in the session view just before the compaction separator. - Handles multiple compactions correctly — each compact_boundary bridges to the previous chunk of pre-compact history. classify.rs - User entries with isCompactSummary:true are now classified as CompactMsg (rendered as a styled separator with the summary text) instead of appearing as a regular user turn alongside the real pre-compact messages they summarise. Tests added: 3 in entry.rs, 3 in session.rs, 2 in classify.rs
The compact summary content is a multi-paragraph AI-generated text. Rendering it inline as the separator label produced an unreadable wall of text. Fix: - Show 'Context compacted ▼' as the always-visible label (button) - Full summary text only appears in a scrollable box when the user clicks to expand - Export CompactSeparator from MessageList and import it in MessageDetail to avoid duplication - Add CSS for .compact-separator__label and .compact-separator__summary - Update test: assert label text and add expand/collapse test
- Add is_recap field to CompactMsg: true for away_summary entries (session recap on idle return), false for isCompactSummary/summary entries (actual compaction events) - Add ChunkType::Recap variant; convert.rs maps it to role:recap in DisplayMessage, keeping role:compact for actual compaction - Extend DisplayMessage role union to include recap - Replace CompactSeparator horizontal-line UI with message-style bubble rendering: compact shows Compacted Message label, recap shows Session Recap label — same CSS structure as user/claude messages - Remove CompactSeparator component; both compact and recap now go through MessageItem with message--compact CSS class - Update tests: assert is_recap flag in classify tests; replace separator DOM assertions with message bubble assertions
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
When a Claude Code session is compacted, the pre-compaction conversation history was invisible in the UI. This PR makes it visible, fixes the compact summary display, and gives each kind of compaction marker its own distinct label.
Changes
Show pre-compaction messages (
entry.rs,session.rs)logical_parent_uuidandis_compact_summaryfields to theEntrystructcompact_boundaryentries (written by Claude Code when compaction occurs) haveparentUuid: nullbut carrylogicalParentUuidpointing to the last pre-compact message —resolve_live_chain_uuidsnow follows this link instead of stopping, so all pre-compact messages are included in the session viewClassify compaction markers (
classify.rs,chunk.rs,convert.rs)isCompactSummary: trueuser entries (AI-generated summary injected after compaction) now produceCompactMsg { is_recap: false }→ChunkType::Compact→role: "compact"away_summarysystem entries (idle-return recap, previously also labelled "Context compacted") now produceCompactMsg { is_recap: true }→ChunkType::Recap→role: "recap"summaryentries also produceis_recap: falseChunkType::Recapvariant to propagate the distinction through the pipelineRender as message bubbles (
MessageItem.tsx,MessageList.tsx,MessageDetail.tsx,global.css)CompactSeparatorhorizontal-line component; both roles now render throughMessageItemusing the same CSS structure as user/claude messagesrole: "compact"→ label "Compacted Message", CSS classmessage--compactrole: "recap"→ label "Session Recap", CSS classmessage--compactmessage__role--compactcolour token and extendedDisplayMessagerole union to include"recap"Tests
classify.rs: added 3 tests forlogical_parent_uuidparsing; 3 tests foris_compact_summaryparsing; 3 session-chain tests (single, double, dead-branch compaction); updatedaway_summarytests to assertis_recap: true; updatedisCompactSummarytest to assertis_recap: falseMessageList.test.tsx: replaced separator DOM assertions with message-bubble assertions for bothcompactandrecaproles