Skip to content

fix(cli): sync session_id after context compression to prevent orphaned sessions#3529

Open
dieutx wants to merge 1 commit intoNousResearch:mainfrom
dieutx:fix/session-id-desync-after-compression
Open

fix(cli): sync session_id after context compression to prevent orphaned sessions#3529
dieutx wants to merge 1 commit intoNousResearch:mainfrom
dieutx:fix/session-id-desync-after-compression

Conversation

@dieutx
Copy link
Copy Markdown
Contributor

@dieutx dieutx commented Mar 28, 2026

Summary

After context compression fires (auto or /compress), the CLI's session_id desyncs from the agent's. The agent creates a child session in the DB, but the CLI never picks up the new ID. Subsequent /new or exit ends the wrong (already-ended parent) session, and the child session is orphaned forever.

Reproduce

Tested on hermes v0.4.0 with GPT-5.4:

  1. Start hermes and send 4+ messages to build conversation context
  2. Type /compress — compression creates a child session on the agent
  3. Type /new — CLI ends the old parent session, not the child
  4. Exit and query the DB:
SELECT id, parent_session_id, ended_at FROM sessions WHERE parent_session_id IS NOT NULL;

Result:

Found 1 compression child session(s):
  20260328_213154_4944f2
    parent: 20260328_212826_76282a
    status: ORPHANED (no ended_at)

BUG CONFIRMED — orphaned child session found

The child session 20260328_213154_4944f2 created during compression was never ended. It stays open in the DB indefinitely, invisible to hermes sessions prune and accumulating stale entries over time.

Root Cause

_compress_context at run_agent.py:4950 ends the current session, creates a child session, and updates self.session_id on the agent. But the CLI holds its own self.session_id that's never synced:

  • _manual_compress at cli.py:4464 — no sync after _compress_context returns
  • Post-run_conversation handler at cli.py:5728 — no sync for auto-compression

So when /new calls end_session(self.session_id), it targets the parent session (already ended by compression), and the child session is never closed.

Fix

Manual compress — sync after compression succeeds:

if hasattr(self, '_session_db') and self.agent:
    self.session_id = self.agent.session_id

Auto compress — sync after run_conversation returns:

if self.agent and self.agent.session_id != self.session_id:
    self.session_id = self.agent.session_id

Tests

4 new tests: manual compress syncs, failure preserves original, auto compress syncs, no-compression is no-op.

4 passed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant