mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-24 16:54:43 +00:00
fix: harden salvaged preflight display rollback for test-double density
Follow-up to the #54805 cherry-pick (skill guard rules): - turn_context.py: snapshot_preflight_display_tokens gets a getattr+callable guard (SimpleNamespace compressor doubles / plugin context engines lack the ContextCompressor-only method) and the snapshot value is type-pinned to a real int (bool excluded) before arming the rollback — MagicMock compressors return truthy Mocks. - turn_finalizer.py: interrupted pinned 'is True', the _turn_received_provider_response read pinned 'is not True' (MagicMock auto-attrs are truthy), and the compressor rollback method call gets a getattr+callable guard. Rollback stays display-only: it never touches _ineffective_compression_count or any durable guard, and preserves the -1 post-compaction sentinel.
This commit is contained in:
parent
17a81ac89e
commit
66fdcfa3bd
2 changed files with 32 additions and 7 deletions
|
|
@ -720,9 +720,21 @@ def build_turn_context(
|
|||
tools=agent.tools or None,
|
||||
)
|
||||
_compressor = agent.context_compressor
|
||||
agent._turn_preflight_display_snapshot = (
|
||||
_compressor.snapshot_preflight_display_tokens()
|
||||
# getattr guard: minimal compressor doubles (SimpleNamespace in the
|
||||
# engine-preflight tests) and plugin context engines lack this
|
||||
# ContextCompressor-only method — absence means no snapshot, and the
|
||||
# finalizer's rollback stays disarmed for the turn (display-only).
|
||||
_snapshot_fn = getattr(
|
||||
_compressor, "snapshot_preflight_display_tokens", None
|
||||
)
|
||||
if callable(_snapshot_fn):
|
||||
_snapshot_val = _snapshot_fn()
|
||||
# Type pin: MagicMock compressors return truthy Mock objects —
|
||||
# only a real int snapshot may arm the interrupted-turn rollback.
|
||||
if isinstance(_snapshot_val, int) and not isinstance(
|
||||
_snapshot_val, bool
|
||||
):
|
||||
agent._turn_preflight_display_snapshot = _snapshot_val
|
||||
_defer_preflight = getattr(
|
||||
_compressor,
|
||||
"should_defer_preflight_to_real_usage",
|
||||
|
|
|
|||
|
|
@ -205,18 +205,31 @@ def finalize_turn(
|
|||
# request. Roll that estimate back only when an interrupt wins the race
|
||||
# before any successful provider response. Compaction state remains owned
|
||||
# by the real-usage/post-compaction path, including its ``-1`` sentinel.
|
||||
# Guard rules (test-double density on this path is high):
|
||||
# - snapshot is type-pinned to a real int — MagicMock agents auto-create
|
||||
# truthy Mock attributes that must never arm the rollback;
|
||||
# - the received-response flag is pinned to ``is not True`` — its real
|
||||
# domain is True/False, and only a literal True means a provider
|
||||
# response completed;
|
||||
# - the compressor method gets a getattr+callable guard — SimpleNamespace
|
||||
# compressor doubles and plugin context engines lack it.
|
||||
_preflight_snapshot = getattr(
|
||||
agent, "_turn_preflight_display_snapshot", None
|
||||
)
|
||||
if (
|
||||
interrupted
|
||||
and _preflight_snapshot is not None
|
||||
and not getattr(agent, "_turn_received_provider_response", False)
|
||||
interrupted is True
|
||||
and isinstance(_preflight_snapshot, int)
|
||||
and not isinstance(_preflight_snapshot, bool)
|
||||
and getattr(agent, "_turn_received_provider_response", False) is not True
|
||||
and getattr(agent, "context_compressor", None) is not None
|
||||
):
|
||||
agent.context_compressor.rollback_interrupted_preflight_display_tokens(
|
||||
_preflight_snapshot
|
||||
_rollback_fn = getattr(
|
||||
agent.context_compressor,
|
||||
"rollback_interrupted_preflight_display_tokens",
|
||||
None,
|
||||
)
|
||||
if callable(_rollback_fn):
|
||||
_rollback_fn(_preflight_snapshot)
|
||||
|
||||
# Post-loop cleanup must never lose the response. Trajectory save,
|
||||
# resource teardown, and session persistence all touch fallible
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue