diff --git a/agent/relay_runtime.py b/agent/relay_runtime.py index 895308b322d..c999749d842 100644 --- a/agent/relay_runtime.py +++ b/agent/relay_runtime.py @@ -23,6 +23,7 @@ LOGICAL_LLM_SCOPE = "hermes.logical_llm_call" RUNTIME_SCHEMA_KEY = "hermes.relay.schema_version" RUNTIME_SCHEMA_VERSION = "hermes.relay.runtime.v1" RUNTIME_INSTANCE_KEY = "hermes.relay.runtime_instance" +_PROFILE_KEY_CACHE: dict[str, str] = {} @dataclass @@ -409,6 +410,9 @@ class RelayHostRegistry: create: bool = True, ) -> RelayHost | None: key = profile_key or current_profile_key() + host = self._hosts.get(key) + if host is not None or not create: + return host with self._lock: host = self._hosts.get(key) if host is not None or not create: @@ -823,7 +827,7 @@ def apply_tool_request_intercepts( """Return Relay-rewritten arguments at Hermes's authorization boundary.""" if not session_id: return args - runtime = get_runtime() + runtime = get_runtime(create=False) if runtime is None: return args return runtime.apply_tool_request_intercepts( @@ -930,7 +934,15 @@ def get_host( def current_profile_key() -> str: """Return the canonical profile identity used for runtime isolation.""" - return str(get_hermes_home().expanduser().resolve()) + home = get_hermes_home().expanduser() + if not home.is_absolute(): + return str(home.resolve()) + raw = str(home) + cached = _PROFILE_KEY_CACHE.get(raw) + if cached is not None: + return cached + resolved = str(home.resolve()) + return _PROFILE_KEY_CACHE.setdefault(raw, resolved) def _load_nemo_relay() -> Any: @@ -946,3 +958,4 @@ def _reset_for_tests() -> None: """Reset all profile-scoped Relay hosts for isolated tests.""" SESSION_COORDINATOR._reset_active_turns_for_tests() HOST_REGISTRY.shutdown_all() + _PROFILE_KEY_CACHE.clear() diff --git a/tests/hermes_cli/test_relay_shared_metrics_runtime.py b/tests/hermes_cli/test_relay_shared_metrics_runtime.py index 1ef5a18dd88..b0b7a6dbd26 100644 --- a/tests/hermes_cli/test_relay_shared_metrics_runtime.py +++ b/tests/hermes_cli/test_relay_shared_metrics_runtime.py @@ -498,6 +498,75 @@ def test_direct_runtime_is_disabled_by_default(tmp_path, monkeypatch): relay_runtime._reset_for_tests() +def test_tool_intercept_bypass_does_not_create_relay_host(monkeypatch): + relay_runtime._reset_for_tests() + imports = [] + + def load_relay(): + imports.append("nemo_relay") + raise AssertionError("disabled helper created Relay host") + + monkeypatch.setattr(relay_runtime, "_load_nemo_relay", load_relay) + args = {"command": "true"} + + assert ( + relay_runtime.apply_tool_request_intercepts( + session_id="s1", + tool_name="terminal", + args=args, + ) + is args + ) + assert relay_runtime.get_host(create=False) is None + assert imports == [] + + +def test_profile_key_caches_absolute_path_resolution(monkeypatch): + relay_runtime._reset_for_tests() + + class Home: + def __init__(self): + self.resolve_calls = 0 + + def expanduser(self): + return self + + def is_absolute(self): + return True + + def resolve(self): + self.resolve_calls += 1 + return self + + def __str__(self): + return "/profiles/cached" + + home = Home() + monkeypatch.setattr(relay_runtime, "get_hermes_home", lambda: home) + + assert relay_runtime.current_profile_key() == "/profiles/cached" + assert relay_runtime.current_profile_key() == "/profiles/cached" + assert home.resolve_calls == 1 + + +def test_host_registry_reads_existing_host_without_lock(): + registry = relay_runtime.RelayHostRegistry() + host = relay_runtime.NoopRelayRuntime("profile", "test") + registry._hosts["profile"] = host + + class UnexpectedLock: + def __enter__(self): + raise AssertionError("registry read acquired the write lock") + + def __exit__(self, *_args): + return False + + registry._lock = UnexpectedLock() + + assert registry.for_profile("profile", create=False) is host + assert registry.for_profile("missing", create=False) is None + + def test_core_runtime_is_fail_open_without_a_published_binding(monkeypatch, caplog): relay_shared_metrics._reset_for_tests() relay_runtime._reset_for_tests()