mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-11-06 05:17:15 +00:00
fix(memory): don't count a hosted engine's prune as a withheld authority
Under plugins.isolation: host every engine method is a proxy, so the __func__ identity check in _prune_would_have_run read a hosted engine's inherited prune no-op as an override. With the gate armed, the suppression count went up every tool iteration and the "withheld" warning fired once, though nothing was withheld. The prune itself is still withheld at the call site in turn_preflight, so only the count and the log were wrong. A hosted engine is now not counted. That drops the count for a hosted engine that really overrides the hook too; telling the two apart needs the plugin host to report which class defines each method, which this branch leaves to the plugin-contract work. Suggested by @unsupportedpastels in the review of #149265.
This commit is contained in:
1 parent
95516763d5
commit
bfcbd08bee
2 files changed
+52
-1
No files matched your search
@@ -155,13 +155,17 @@ def _prune_would_have_run(compressor: Any, current_tokens: int) -> bool:
|
||||
The built-in answers via ``would_proactively_prune()``. An engine that overrides
|
||||
``prune_tool_results_only`` owns its trigger policy, so occupying the hook is the
|
||||
precondition; the inherited ABC no-op is not an authority. A raising predicate reads as
|
||||
"would have run": the call was withheld either way.
|
||||
"would have run": the call was withheld either way. A hosted engine (``plugins.isolation:
|
||||
host``) is not counted: its methods are all proxies, so an override can't be told from the no-op.
|
||||
"""
|
||||
from agent.context_engine import ContextEngine
|
||||
from hermes_cli.plugin_host import is_hosted_object
|
||||
|
||||
prune = getattr(compressor, "prune_tool_results_only", None)
|
||||
if not callable(prune) or getattr(prune, "__func__", None) is ContextEngine.prune_tool_results_only:
|
||||
return False
|
||||
if is_hosted_object(compressor):
|
||||
return False
|
||||
predicate = getattr(compressor, "would_proactively_prune", None)
|
||||
if not callable(predicate):
|
||||
return True
|
||||
|
||||
@@ -208,3 +208,50 @@ def test_engine_that_never_overrode_the_prune_hook_is_not_a_suppressed_authority
|
||||
|
||||
assert _prune_would_have_run(_InheritsTheDefault(), 400_000) is False
|
||||
assert _prune_would_have_run(_OccupiesTheHook(), 400_000) is True
|
||||
|
||||
|
||||
def _hosted(engine, home):
|
||||
"""The proxy the plugin host builds for ``engine`` under ``plugins.isolation: host``, without a
|
||||
host process: the host's requests go to the child runtime's own handlers in-process."""
|
||||
import itertools
|
||||
import threading
|
||||
from typing import Any, cast
|
||||
|
||||
from agent.context_engine import ContextEngine
|
||||
from hermes_cli.plugin_host import PluginHost
|
||||
from hermes_cli.plugin_host_child import HostRuntime
|
||||
|
||||
runtime = HostRuntime.__new__(HostRuntime)
|
||||
runtime.refs, runtime.owners = {}, {}
|
||||
runtime._ids, runtime._lock = itertools.count(1), threading.Lock()
|
||||
ref = runtime._describe_object("engine-plugin", engine)
|
||||
|
||||
def call(method, params, timeout=None):
|
||||
return getattr(runtime, f"op_{method}")(params)
|
||||
|
||||
host = PluginHost(SimpleNamespace(home_path=home, _plugins={}))
|
||||
host._channel = cast(Any, SimpleNamespace(call=call, closed_reason=None))
|
||||
return host._object_proxy(ref, ContextEngine)
|
||||
|
||||
|
||||
def test_hosted_engine_is_withheld_but_not_reported_as_a_suppressed_authority(tmp_path):
|
||||
"""Under ``plugins.isolation: host`` every engine method is a proxy, so identity can't tell the
|
||||
inherited no-op from an override. The armed gate still withholds the call; it just doesn't count
|
||||
a prune it can't prove would have run."""
|
||||
compress_only = _engine_stub()
|
||||
|
||||
class _OccupiesTheHook(compress_only):
|
||||
def __init__(self):
|
||||
self.calls = 0
|
||||
|
||||
def prune_tool_results_only(self, messages, current_tokens=None):
|
||||
self.calls += 1
|
||||
return list(messages), 1
|
||||
|
||||
messages = [{"role": "user", "content": "scan"}]
|
||||
agent, overriding = _agent(True), _OccupiesTheHook()
|
||||
|
||||
assert _proactive_tool_result_prune(agent, _hosted(compress_only(), tmp_path), messages, 400_000) is messages
|
||||
assert _proactive_tool_result_prune(agent, _hosted(overriding, tmp_path), messages, 400_000) is messages
|
||||
assert getattr(agent, "_checkpoint_gate_suppression_count", 0) == 0
|
||||
assert overriding.calls == 0
|
||||
Reference in new issue
Block a user