Skip to content

[Bug] Context Compaction + Session Split: compressed summary injected as valid history into new session #20293

@madao002

Description

@madao002

Describe the bug

When a conversation triggers Context Compaction followed by a Session Split, the compressed summary and its referenced original messages are incorrectly injected as valid conversation history into the newly created session, instead of being treated as background-only reference material.

Reproduction Steps

  1. Start a conversation in Session A — the model responds normally
  2. Continue the conversation until Context Compaction fires (after ~10+ messages depending on context limits)
    • The compressor generates a [CONTEXT COMPACTION — REFERENCE ONLY] summary message
    • Original messages are demoted below the --- END OF CONTEXT SUMMARY — respond to the message below, not the summary above --- separator
  3. Send another message to continue the conversation
  4. This second message triggers a Session Split (the agent decides to start a new session for the fresh topic)
  5. Bug: The new session contains the compressed summary AND the original pre-compression messages as if they were valid user/assistant exchanges — not as background reference

Actual Behavior

The new session's transcript looks like:

[0] USER: "hello"
[1] ASSISTANT: "Hi! How can I help you?"
[2] USER: "help me with X"
[3] ASSISTANT: "[CONTEXT COMPACTION — REFERENCE ONLY] Summary of [0]-[2]..."

Messages [0]–[2] are the compressed first-round exchanges. They appear as live conversation rather than historical context that was summarized.

Expected Behavior

When a Session Split occurs after Context Compaction, the new session should start clean — it should not inherit the compressed summary's referenced original messages as valid history.

Root Cause Hypothesis

Code Path

  1. gateway/run.py message handling (~line 12800): loads history from session transcript into agent_history
  2. agent/context_compressor.py SummarizerCompressor._compress():
    • Extracts leading messages → generates a [CONTEXT COMPACTION — REFERENCE ONLY] summary
    • Appends --- END OF CONTEXT SUMMARY — respond to the message below, not the summary above ---
    • Appends original messages after the separator
    • Rewrites the session transcript with the compressed version
  3. When the next message triggers a session split, gateway/run.py lines ~13157–13166 handle it:
if agent and session_key and hasattr(agent, 'session_id') and agent.session_id != session_id:
    _session_was_split = True
    logger.info("Session split detected: %s → %s (compression)", session_id, agent.session_id)
    entry = self.session_store._entries.get(session_key)
    if entry:
        entry.session_id = agent.session_id  # ← Problem: messages already written to old session
        self.session_store._save()

The entry.session_id update happens AFTER messages are persisted to the transcript. When context compression creates a split during the same turn:

  1. Compressed messages are written to the current entry.session_id (old session file)
  2. entry.session_id is updated only after the response is sent
  3. The new session thus inherits the compressed message chain as if it were valid history

Alternatively, the split logic may be inheriting a message range from the parent that includes the compressed block, without filtering out the REFERENCE ONLY region.

Environment

  • Hermes Agent: latest
  • OS: Ubuntu 24.04 (WSL)

Additional context

Session timeline from the triggering case:

  • Session B: first round (10:10 AM)
  • Session A: later same day, second round in same session
    • Messages [0]–[3]: first round (compressed)
    • Messages [N]–[M]: second round (triggered split)
  • Session C: split from Session A
    • Messages [0]–[3]: injected from Session A's first round as live history ← BUG

Key Code Locations

  • gateway/run.py line ~13157–13175: session split detection and history_offset handling
  • gateway/run.py line ~12800–12850: agent_history built from transcript
  • agent/context_compressor.py _compress(): summary generation logic

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High — major feature broken, no workaroundcomp/agentCore agent loop, run_agent.py, prompt buildertype/bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions