{"repo":"NousResearch/hermes-agent","public_id":"49307","display_label":"Context compression summary duplication and accuracy bugs","summary":"These issues and fixes relate to bugs in context compression where the latest user message gets triplicated and historical tasks are not correctly framed in fallback summaries. Multiple fix attempts target the same core compression summary generation problems.","subsystem":"agent","counts":{"members":4,"open_issues":0,"open_issues_distinct":0,"open_prs":0,"closed_issues":1,"merged_prs":1,"attempt_prs":2},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":49986,"merged_at":"2026-06-21T06:19:27+00:00"},"resolution":{"state":"unresolved","by":null},"freshness":{"state":"verified","last_verified_at":"2026-06-21T06:19:27+00:00","is_stale":false},"grouping":{"backbone":"STRUCTURAL_SPANNING","link_density":0.5},"fix_edges":[{"issue_number":49307,"pr_number":49986,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false,"pr_merged_at":"2026-06-21T06:19:27+00:00"}],"members":[{"kind":"issue","number":49307,"title":"Context compression causes answer repetition + new instruction loss (Bug B: critical)","url":null,"state":"closed"},{"kind":"pr","number":49347,"title":"fix(agent): stop deterministic fallback summary from triplicating the latest user ask (#49307)","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#49986","number":49986}],"category":"merged_via","implication":"superseded"},"merged":false},{"kind":"pr","number":49381,"title":"fix(agent): frame historical tasks as resolved in compression summary (#49307)","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#49986","number":49986}],"category":"merged_via","implication":"superseded"},"merged":false},{"kind":"pr","number":49986,"title":"fix(compression): stop fallback summary triplicating the latest user ask (#49307)","url":null,"state":"merged","close_reason":{"category":"merged"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["agent/context_compressor.py","tests/agent/test_context_compressor.py"],"fix_hunks":[{"file":"agent/context_compressor.py","hunks":["@@ -1253,7 +1253,10 @@ def _bullets(items: list[str], limit: int = 8) -> str:\n Unknown from deterministic fallback. Inspect current repository/session state if needed.\n \n {HISTORICAL_IN_PROGRESS_HEADING}\n-{active_task}\n+Unknown from deterministic fallback — the latest user ask is recorded once under\n+\"{HISTORICAL_TASK_HEADING}\" above as historical context only. Do NOT treat it as an\n+unfulfilled instruction to re-answer; verify current state and continue from the\n+protected recent messages after this summary.\n \n ## Blocked\n {_bullets(blockers, limit=5)}","@@ -1265,7 +1268,9 @@ def _bullets(items: list[str], limit: int = 8) -> str:\n None recoverable from deterministic fallback.\n \n {HISTORICAL_PENDING_ASKS_HEADING}\n-{active_task}\n+None recoverable from deterministic fallback. (The latest user ask is preserved once\n+under \"{HISTORICAL_TASK_HEADING}\" as historical context — it is NOT necessarily\n+outstanding.)\n \n ## Relevant Files\n {_bullets(relevant_files, limit=12)}"]},{"file":"tests/agent/test_context_compressor.py","hunks":["@@ -170,6 +170,40 @@ def test_summary_failure_uses_deterministic_fallback_with_recovered_context(self\n         assert c._last_summary_fallback_used is True\n         assert c._last_summary_dropped_count == 3\n \n+    def test_fallback_summary_does_not_triplicate_latest_user_ask(self):\n+        \"\"\"Regression for #49307: the deterministic fallback summary used to\n+        render the latest user ask verbatim under THREE headings (Task\n+        Snapshot, In-Progress, Pending Asks). The model then re-answered it\n+        and buried the genuinely-new post-compaction turn (answer repetition +\n+        new-instruction loss). The latest ask must appear ONCE, as historical\n+        context only — never re-presented as unfulfilled in-progress/pending\n+        work.\n+        \"\"\"\n+        with patch(\"agent.context_compressor.get_model_context_length\", return_value=100000):\n+            c = ContextCompressor(model=\"test/model\", quiet_mode=True)\n+\n+        unique_ask = \"PLEASE_COMPUTE_THE_ARITHMETIC_CHAIN_XYZ\"\n+        turns = [\n+            {\"role\": \"user\", \"content\": unique_ask},\n+            {\"role\": \"assistant\", \"content\": \"working on it\"},\n+        ]\n+        summary = c._build_static_fallback_summary(turns, reason=\"provider down\")\n+\n+        # The triplication bug rendered the SAME ``active_task`` line —\n+        # formatted as ``User asked: '<ask>'`` — verbatim under three\n+        # headings (Task Snapshot, In-Progress, Pending Asks), making the\n+        # model treat an already-handled ask as unresolved work and re-answer\n+        # it. That exact formatted line must now appear at most ONCE (only as\n+        # the historical Task Snapshot record). The raw ask text may still\n+        # appear elsewhere (e.g. the \"Last Dropped Turns\" verbatim transcript),\n+        # but never re-labeled as in-progress/pending work.\n+        active_task_line = f\"User asked: {unique_ask!r}\"\n+        count = summary.count(active_task_line)\n+        assert count <= 1, (\n+            f\"active_task line should appear at most once (was triplicated in \"\n+            f\"#49307), found {count}x:\\n{summary}\"\n+        )\n+\n     def test_compression_increments_count(self, compressor):\n         msgs = self._make_messages(10)\n         # Default config (abort_on_summary_failure=False) — fallback path\n"]}]}],"trust":{"default_tier":"verified","includes_suggested":false}}