Conversation
Silent except: pass blocks in is_write_denied made path-resolution failures invisible when the guard was deciding whether a write target was denied. Add debug logging so operators can see which paths and Hermes dir lookups are being skipped without changing behavior.
When preflight context compression replaces the messages list with a compressed [summary, ...tail] structure, the current_turn_user_idx set earlier (line 567) becomes stale. This causes memory/plugin context injection to target the wrong message, potentially corrupting tool results or the summary message itself. The fix scans the compressed messages list to locate the current turn's user message and updates both current_turn_user_idx and agent._persist_user_message_idx to the correct position. This ensures that ephemeral context (memory prefetch, plugin hooks) is injected into the correct user message after compression events.
naqerl
left a comment
There was a problem hiding this comment.
If the for loop would not found any messge, the original issue persists. It makes sense to set indexes to None in this case.
Nice to have these tests:
- Mock compression and ensure that the index changed
- Mock compression which deletes all user's messages and ensure, that stale index is not present
Also agent/file_safety.py and agent/context_references.py changes are unrelated and present in the another PR. It will cause merge conflict, so they could be safely removed
Thanks for your time!
teknium1
left a comment
There was a problem hiding this comment.
Thanks for identifying the stale-index hazard; the premise still holds on current main.
Problems
- The target code moved in
54870847cb0f530105907b1a793531b8d0f03d78: preflight compression now replacesmessagesinagent/turn_context.py:450, returns the old index atagent/turn_context.py:575, andagent/conversation_loop.py:801still uses that index to choose the injection target. - The scan in this PR leaves both indexes stale if no matching user message remains (
agent/conversation_loop.py:690-692on the PR head). - Current main has additional message-replacing compaction paths at
agent/conversation_loop.py:1034,3143,3398,3621, and4798; this hunk would not cover them. - The diff has no regression coverage and includes unrelated logging edits in
agent/context_references.pyandagent/file_safety.py.
Suggested changes
- Move this into a shared rebinding helper, use it after each continuing compaction path, and clear both indexes when no current-turn user message survives.
- Add preflight and no-match regression tests, then split the unrelated logging edits.
Automated hermes-sweeper review.
| and _msg.get("content") == user_message): | ||
| current_turn_user_idx = _new_idx | ||
| agent._persist_user_message_idx = _new_idx | ||
| break |
There was a problem hiding this comment.
If the scan finds no matching user message, this leaves both indexes at their pre-compression values. Clear current_turn_user_idx and _persist_user_message_idx in that case so later injection and persistence cannot target a stale row.
|
Production evidence that this and #43552 are the same stale |
|
Thanks @moizogg for the first report of this class. The preflight case is already covered on main: |
Problem
When preflight context compression replaces the messages list with a compressed
[summary, ...tail]structure, thecurrent_turn_user_idxbecomes stale. This causes memory/plugin context injection to target the wrong message.Impact
pre_llm_callhooks may corrupt the summary messageFix
After compression completes, scan the compressed messages list from the end to locate the current turn's user message and update both
current_turn_user_idxandagent._persist_user_message_idxto the correct position.