fix: scrub only the current turn's assistant message by identity in after_agent gate

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
MervinPraisonandClaude Opus 5.5 committed 2026-10-29 00:04:26 +00:00
1 parent 1d4e8f36fb
commit 7591488090
2 files changed
+25 -5

No files matched your search

@@ -2088,12 +2088,17 @@ class ToolExecutionMixin:
else:
return response
if final != response and isinstance(response, str):
# Match by content, not position: a concurrent turn may have
# appended a newer assistant message after this one.
# Prefer this turn's own messages (by identity) so a concurrent
# turn with identical text is never touched; fall back to a
# content match over shared history for untracked callers.
from .memory_mixin import _active_turn_owned
owned = _active_turn_owned.get() or []
with self._history_lock:
for msg in reversed(self.chat_history):
if (isinstance(msg, dict) and msg.get("role") == "assistant"
and msg.get("content") == response):
for candidates in (owned, self.chat_history):
msg = next((m for m in reversed(candidates)
if isinstance(m, dict) and m.get("role") == "assistant"
and m.get("content") == response), None)
if msg is not None:
msg["content"] = final
break
return final
@@ -132,6 +132,21 @@ class TestAgentAfterAgentEnforcement:
assert all(SECRET not in str(m.get("content")) for m in agent.chat_history)
assert agent.chat_history[-1]["content"] == "concurrent reply"
def test_block_scrubs_own_turn_not_identical_concurrent_turn(self):
agent = _agent(RaiseBlockPlugin())
own = {"role": "assistant", "content": f"SSN {SECRET}"}
# A concurrent (untracked here) turn appends an identical answer later.
other = {"role": "assistant", "content": f"SSN {SECRET}"}
token = agent._begin_turn_tracking()
try:
agent._append_to_chat_history(own)
agent.chat_history.append(other)
out = agent._trigger_after_agent_hook("q", f"SSN {SECRET}", time.time())
finally:
agent._end_turn_tracking(token)
assert own["content"] == out
assert other["content"] == f"SSN {SECRET}"
class EmailRedactPlugin(Plugin):
@property