mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-23 16:36:23 +00:00
The display_history_prefix calculation used by session.resume's _live_session_payload was display_history[:len(display) - len(raw)]. This assumed the model (repaired) history is always a suffix of the display history — i.e., repair_message_sequence only removes messages from the tail. That assumption broke when verification candidates (finish_reason=verification_required) were persisted to state.db (#65919): - repair collapses consecutive assistant messages, removing the verification candidate from the MODEL history - the candidate stays in the DISPLAY history (it's real persisted content) - the length gap (gap = len(display) - len(raw)) counts BOTH ancestor messages AND repair-removed tip messages - the prefix = display[:gap] grabs the first N display messages, which are tip messages (not ancestors) when there are no compression ancestors - _live_session_payload concatenates prefix + model_history, duplicating the first N messages On session 20260720_110036_a33889 (8 verification candidates), this duplicated the first 8 messages in every warm-cache session.activate response, producing visible duplicate user messages in the desktop. Fix: add SessionDB.get_ancestor_display_prefix() which returns ONLY genuine ancestor messages (rows where session_id != tip_session_id), identified at the row level before _rows_to_conversation strips session_id. Both resume paths (eager + deferred) now use this instead of the length-slice heuristic. Tests: - test_get_ancestor_display_prefix_single_session_returns_empty - test_get_ancestor_display_prefix_returns_ancestor_only_messages - Updated 12 mock DBs across test_protocol.py + test_tui_gateway_server.py - 848 passed (run_tests.sh), 0 regressions |
||
|---|---|---|
| .. | ||
| __init__.py | ||
| test_billing_rpc.py | ||
| test_codex_app_server_live_events.py | ||
| test_compaction_status.py | ||
| test_compute_host.py | ||
| test_compute_host_phase1.py | ||
| test_custom_provider_session_persistence.py | ||
| test_delegation_session_lifecycle.py | ||
| test_entry_sys_path.py | ||
| test_fast_session_scope.py | ||
| test_finalize_session_persist.py | ||
| test_gateway_owned_session_reap.py | ||
| test_goal_command.py | ||
| test_image_routing_stale_model.py | ||
| test_inline_rpc_gil_starvation.py | ||
| test_interim_assistant_callback.py | ||
| test_iso_certify_seam.py | ||
| test_make_agent_provider.py | ||
| test_mcp_late_refresh_thread_owner.py | ||
| test_moa_reference_emit.py | ||
| test_model_switch_marker_role.py | ||
| test_pet_generate_rpc.py | ||
| test_project_tree.py | ||
| test_projects_rpc.py | ||
| test_protocol.py | ||
| test_reasoning_config_per_model.py | ||
| test_reasoning_session_scope.py | ||
| test_render.py | ||
| test_review_summary_callback.py | ||
| test_session_platform_resolution.py | ||
| test_slash_worker_ansi.py | ||
| test_slash_worker_mcp_discovery.py | ||
| test_slash_worker_profile_home.py | ||
| test_slash_worker_sys_path.py | ||
| test_subagent_child_mirror.py | ||
| test_undo_command.py | ||
| test_wait_for_mcp_discovery.py | ||