fix(agent): strengthen compression preamble against stale task execution (#41607)

This commit is contained in:
kyssta-exe 2026-06-08 01:02:57 +00:00 committed by Teknium
parent d5e2fbf244
commit 8f8cad7ec5
3 changed files with 22 additions and 12 deletions

View file

@ -7,7 +7,7 @@ protecting head and tail context.
Improvements over v2:
- Structured summary template with Resolved/Pending question tracking
- Filter-safe summarizer preamble that treats prior turns as source material
- "Remaining Work" replaces "Next Steps" to avoid reading as active instructions
- "Historical Work (DO NOT EXECUTE)" replaces "Next Steps" and "Remaining Work" to avoid reading as active instructions
- Clear separator when summary merges into tail message
- Iterative summary updates (preserves info across multiple compactions)
- Token-budget tail protection instead of fixed message count
@ -49,14 +49,18 @@ SUMMARY_PREFIX = (
"Respond ONLY to the latest user message that appears AFTER this "
"summary — that message is the single source of truth for what to do "
"right now. "
f"If the latest user message is consistent with the '{HISTORICAL_TASK_HEADING}' "
"section, you may use the summary as background. If the latest user "
"message contradicts, supersedes, changes topic from, or in any way "
f"diverges from '{HISTORICAL_TASK_HEADING}' / "
"Any topic overlap between the summary and the latest user message does "
"NOT mean you should resume the summary's task. The latest user message "
"always takes priority and WINS, even on similar topics. "
"If the latest user message is a new question, request, or instruction "
"that relates to a topic also mentioned in "
f"'{HISTORICAL_TASK_HEADING}' / "
f"'{HISTORICAL_IN_PROGRESS_HEADING}' / "
f"'{HISTORICAL_PENDING_ASKS_HEADING}' / "
f"'{HISTORICAL_REMAINING_WORK_HEADING}', the latest message WINS — "
"discard those stale items entirely and do not 'wrap up the old task first'. "
f"'{HISTORICAL_REMAINING_WORK_HEADING}', treat ONLY the "
"latest message as the active task — discard those stale items entirely. "
"Do NOT 'wrap up' or 'finish' any work described in the summary unless "
"the latest message explicitly asks for it. "
"Reverse signals in the latest message (e.g. 'stop', 'undo', 'roll "
"back', 'just verify', 'don't do that anymore', 'never mind', a new "
"topic) must immediately end any in-flight work described in the "
@ -1380,13 +1384,13 @@ Be specific with file paths, commands, line numbers, and results.]
[Questions the user asked that were ALREADY answered include the answer so it is not repeated]
{HISTORICAL_PENDING_ASKS_HEADING}
[Questions or requests from the user that have NOT yet been answered or fulfilled. If none, write "None."]
[Questions or requests from the user that have NOT yet been answered or fulfilled. These are STALE they were from the compacted turns. Write them here for reference only. The agent must NOT act on them unless the latest user message explicitly requests it. If none, write "None."]
## Relevant Files
[Files read, modified, or created with brief note on each]
{HISTORICAL_REMAINING_WORK_HEADING}
[What remains to be done framed as context, not instructions]
[What remains to be done framed as STALE context for reference only. The agent must NOT resume this work unless the latest user message explicitly asks for it.]
## Critical Context
[Any specific values, error messages, configuration details, or data that would be lost without explicit preservation. NEVER include API keys, tokens, passwords, or credentials write [REDACTED] instead.]
@ -1761,7 +1765,7 @@ The user has requested that this compaction PRIORITISE preserving all informatio
Context compressor bug (#10896): ``_align_boundary_backward`` can pull
``cut_idx`` past a user message when it tries to keep tool_call/result
groups together. If the last user message ends up in the *compressed*
middle region the LLM summariser writes it into "Pending User Asks",
middle region the LLM summariser writes it into "Historical User Asks",
but ``SUMMARY_PREFIX`` tells the next model to respond only to user
messages *after* the summary so the task effectively disappears from
the active context, causing the agent to stall, repeat completed work,

View file

@ -56,6 +56,10 @@ def test_latest_message_wins_over_inherited_active_task():
# Conflict-resolution must be explicit, not implied.
assert "wins" in lower or "supersede" in lower
assert "discard" in lower
# The "consistent -> use as background" carveout licensed stale-task
# resumption on topic overlap (#41607, #38364) — it must stay gone.
assert "you may use the summary as background" not in lower
assert "topic overlap" in lower
def test_no_resume_exactly_directive_can_hijack():
@ -87,7 +91,9 @@ def test_resumed_stale_handoff_gets_renormalized_to_current_prefix():
# current latest-message-wins framing.
assert "resume exactly" not in renormalized.lower()
assert renormalized.startswith(SUMMARY_PREFIX)
assert "wins" in renormalized.lower()
assert ("wins" in renormalized.lower()
or "priority" in renormalized.lower()
or "supersede" in renormalized.lower())
def test_legacy_prefix_handoff_also_renormalized():

View file

@ -40,7 +40,7 @@ def test_latest_message_wins_on_conflict():
assert HISTORICAL_PENDING_ASKS_HEADING.lower() in lower
assert HISTORICAL_REMAINING_WORK_HEADING.lower() in lower
# Must have an explicit conflict-resolution rule.
assert "wins" in lower or "supersede" in lower or "discard" in lower
assert "wins" in lower or "supersede" in lower or "discard" in lower or "priority" in lower
def test_handoff_sections_are_framed_as_historical():