mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-31 19:16:29 +00:00
fix(compression): ignore assistant handoff summaries in tail anchor
Assistant-role compaction summaries were treated as the last visible assistant reply after head protection decayed. That pulled the tail boundary back to the summary itself and left zero new turns to summarize. Exclude internal context summaries from both the visible-reply search and the assistant fallback, mirroring the existing user-role summary exclusion.
This commit is contained in:
parent
9fa2906c18
commit
f4896015c1
2 changed files with 39 additions and 2 deletions
|
|
@ -2988,7 +2988,13 @@ This compaction should PRIORITISE preserving all information related to the focu
|
|||
indicators and aren't what the reporter means by "the output
|
||||
of the last message you sent" (#29824).
|
||||
|
||||
Falling back to the most recent assistant message of ANY kind
|
||||
Context-compaction handoff banners can also carry
|
||||
``role="assistant"``. They are internal continuity state, not a
|
||||
user-visible reply, so ignore them both as text-bearing anchors and
|
||||
as candidates for the fallback below. This mirrors the user-role
|
||||
summary exclusion in ``_find_last_user_message_idx``.
|
||||
|
||||
Falling back to the most recent non-summary assistant message of ANY kind
|
||||
only kicks in when no content-bearing assistant message exists
|
||||
in the compressible region — typically a fresh session that
|
||||
just started a multi-step tool sequence with no prior reply
|
||||
|
|
@ -2998,7 +3004,9 @@ This compaction should PRIORITISE preserving all information related to the focu
|
|||
last_any = -1
|
||||
for i in range(len(messages) - 1, head_end - 1, -1):
|
||||
msg = messages[i]
|
||||
if msg.get("role") != "assistant":
|
||||
if msg.get("role") != "assistant" or self._is_context_summary_content(
|
||||
msg.get("content")
|
||||
):
|
||||
continue
|
||||
if last_any < 0:
|
||||
last_any = i
|
||||
|
|
|
|||
|
|
@ -74,6 +74,35 @@ def compressor():
|
|||
|
||||
|
||||
class TestFindLastAssistantMessageIdx:
|
||||
def test_skips_assistant_role_context_summary_marker(self, compressor):
|
||||
"""A persisted assistant-role handoff is internal continuity state,
|
||||
not the last reply the user saw. Tool-call-only assistant messages
|
||||
after it must remain eligible for the fallback anchor."""
|
||||
from agent.context_compressor import SUMMARY_PREFIX
|
||||
|
||||
messages = [
|
||||
{"role": "assistant", "content": f"{SUMMARY_PREFIX}\nold handoff"},
|
||||
{"role": "user", "content": "continue the task"},
|
||||
{"role": "assistant", "content": None,
|
||||
"tool_calls": [{"function": {"name": "t",
|
||||
"arguments": "{}"}}]},
|
||||
{"role": "tool", "content": "result", "tool_call_id": "c1"},
|
||||
]
|
||||
assert compressor._find_last_assistant_message_idx(
|
||||
messages, head_end=0
|
||||
) == 2
|
||||
|
||||
def test_all_assistant_messages_are_summaries_returns_minus_one(self, compressor):
|
||||
from agent.context_compressor import SUMMARY_PREFIX
|
||||
|
||||
messages = [
|
||||
{"role": "assistant", "content": f"{SUMMARY_PREFIX}\nold handoff"},
|
||||
{"role": "user", "content": "continue the task"},
|
||||
]
|
||||
assert compressor._find_last_assistant_message_idx(
|
||||
messages, head_end=0
|
||||
) == -1
|
||||
|
||||
def test_finds_content_bearing_assistant(self, compressor):
|
||||
messages = [
|
||||
{"role": "system", "content": "sys"},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue