mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-21 16:18:55 +00:00
fix: exempt persist-disabled review forks from the session-scoped tripwire
Background-review forks share the live parent's session_id for prompt-cache warmth but are _persist_disabled — they can never write to the transcript. Without this, every review fork on an active session would (a) trip a false cross-agent overlap warning against the parent's real turn, sending the #64934 route investigation the wrong way, and (b) pop the parent's in-flight slot at its own persist, making a real overlap right after a review go unreported. Both legs now skip persist-disabled agents symmetrically. +2 tests.
This commit is contained in:
parent
e4ec9e8bc8
commit
14add28785
2 changed files with 50 additions and 7 deletions
|
|
@ -410,8 +410,13 @@ def note_turn_start(agent, turn_id: str):
|
|||
# Cross-agent leg: same session_id in flight under a different agent
|
||||
# object means two routing keys resolve to one durable session — the
|
||||
# busy guard (keyed by routing key) cannot see this overlap at all.
|
||||
# Persist-disabled agents (background-review forks) deliberately share
|
||||
# the live parent's session_id for prompt-cache warmth but can never
|
||||
# write to the transcript — they must not register here (would warn a
|
||||
# false overlap against the parent's real turn) nor pop the parent's
|
||||
# slot at their persist (note_turn_persisted skips them symmetrically).
|
||||
session_id = getattr(agent, "session_id", None)
|
||||
if session_id:
|
||||
if session_id and not getattr(agent, "_persist_disabled", False):
|
||||
now = time.time()
|
||||
with _INFLIGHT_TURNS_LOCK:
|
||||
entry = _INFLIGHT_TURNS_BY_SESSION.get(session_id)
|
||||
|
|
@ -443,12 +448,17 @@ def note_turn_persisted(agent):
|
|||
and the tripwire under-reports instead of double-reporting. A diagnostic
|
||||
must never be noisier than the defect it hunts."""
|
||||
agent._inflight_turn_id = None
|
||||
session_id = getattr(agent, "_inflight_turn_session_id", None) or getattr(
|
||||
agent, "session_id", None
|
||||
)
|
||||
if session_id:
|
||||
with _INFLIGHT_TURNS_LOCK:
|
||||
_INFLIGHT_TURNS_BY_SESSION.pop(session_id, None)
|
||||
# Symmetric with note_turn_start's cross-agent leg: persist-disabled
|
||||
# forks never registered a session slot, and their persist funnel still
|
||||
# runs — popping here would steal the live parent turn's slot and make
|
||||
# the tripwire under-report the real overlap it exists to catch.
|
||||
if not getattr(agent, "_persist_disabled", False):
|
||||
session_id = getattr(agent, "_inflight_turn_session_id", None) or getattr(
|
||||
agent, "session_id", None
|
||||
)
|
||||
if session_id:
|
||||
with _INFLIGHT_TURNS_LOCK:
|
||||
_INFLIGHT_TURNS_BY_SESSION.pop(session_id, None)
|
||||
agent._inflight_turn_session_id = None
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -144,3 +144,36 @@ def test_crashed_cross_agent_turn_warns_once_then_recovers(caplog):
|
|||
note_turn_persisted(agent_b)
|
||||
note_turn_start(agent_c, "s1:t3:cccc") # clean again
|
||||
assert len(caplog.records) == 1
|
||||
|
||||
|
||||
def test_persist_disabled_fork_neither_registers_nor_warns(caplog):
|
||||
"""Background-review forks share the live parent's session_id for
|
||||
prompt-cache warmth but are _persist_disabled — they can never write
|
||||
to the transcript, so they must not trip the cross-agent warning
|
||||
against the parent's real in-flight turn (in either direction)."""
|
||||
parent, fork = _FakeAgent(), _FakeAgent()
|
||||
fork._persist_disabled = True
|
||||
with caplog.at_level(logging.WARNING, logger="agent.agent_runtime_helpers"):
|
||||
note_turn_start(parent, "s1:t1:aaaa") # real turn in flight
|
||||
assert note_turn_start(fork, "s1:tr:ffff") is None # fork: silent
|
||||
note_turn_persisted(fork) # fork's funnel still runs
|
||||
# Reverse order on the next cycle: fork in flight, then real turn.
|
||||
note_turn_persisted(parent)
|
||||
note_turn_start(fork, "s1:tr:gggg")
|
||||
assert note_turn_start(parent, "s1:t2:bbbb") is None
|
||||
assert not caplog.records
|
||||
|
||||
|
||||
def test_persist_disabled_fork_persist_does_not_steal_parent_slot(caplog):
|
||||
"""The fork's persist funnel still runs; it must not pop the parent's
|
||||
session slot, or a real cross-agent overlap right after a review fork
|
||||
would go unreported."""
|
||||
parent, fork, intruder = _FakeAgent(), _FakeAgent(), _FakeAgent()
|
||||
fork._persist_disabled = True
|
||||
with caplog.at_level(logging.WARNING, logger="agent.agent_runtime_helpers"):
|
||||
note_turn_start(parent, "s1:t1:aaaa") # real turn holds the slot
|
||||
note_turn_start(fork, "s1:tr:ffff")
|
||||
note_turn_persisted(fork) # must NOT release s1
|
||||
prev = note_turn_start(intruder, "s1:t2:bbbb")
|
||||
assert prev == "s1:t1:aaaa"
|
||||
assert len(caplog.records) == 1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue