mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-03 17:27:37 +08:00
After a conversation gets compressed, run_agent's _compress_context ends the parent session and creates a continuation child with the same logical conversation. Every list affordance in the codebase (list_sessions_rich with its default include_children=False, plus the CLI/TUI/gateway/ACP surfaces on top of it) hid those children, and resume-by-ID on the old root landed on a dead parent with no messages. Fix: lineage-aware projection on the read path. - hermes_state.py::get_compression_tip(session_id) — walk the chain forward using parent.end_reason='compression' AND child.started_at >= parent.ended_at. The timing guard separates compression continuations from delegate subagents (which were created while the parent was still live) without needing a schema migration. - hermes_state.py::list_sessions_rich — new project_compression_tips flag (default True). For each compressed root in the result, replace surfaced fields (id, ended_at, end_reason, message_count, tool_call_count, title, last_active, preview, model, system_prompt) with the tip's values. Preserve the root's started_at so chronological ordering stays stable. Projected rows carry _lineage_root_id for downstream consumers. Pass False to get raw roots (admin/debug). - hermes_cli/main.py::_resolve_session_by_name_or_id — project forward after ID/title resolution, so users who remember an old root ID (from notes, or from exit summaries produced before the sibling Bug 1 fix) land on the live tip. All downstream callers of list_sessions_rich benefit automatically: - cli.py _list_recent_sessions (/resume, show_history affordance) - hermes_cli/main.py sessions list / sessions browse - tui_gateway session.list picker - gateway/run.py /resume titled session listing - tools/session_search_tool.py - acp_adapter/session.py Tests: 7 new in TestCompressionChainProjection covering full-chain walks, delegate-child exclusion, tip surfacing with lineage tracking, raw-root mode, chronological ordering, and broken-chain graceful fallback. Verified live: ran a real _compress_context on a live Gemini-backed session, confirmed the DB split, then verified - db.list_sessions_rich surfaces tip with _lineage_root_id set - hermes sessions list shows the tip, not the ended parent - _resolve_session_by_name_or_id(old_root_id) -> tip_id - _resolve_last_session -> tip_id Addresses #10373.