Files
hermes-agent/tests/hermes_cli/test_doctor_relay_plugins.py
emozilla 51aa249efd feat(relay): name the Relay plugin files in doctor and the startup log
Relay 0.9 discovers user and system plugins.toml files outside the Hermes
home, so an exporter or middleware can apply to every Hermes session without
any Hermes setting naming it. Hermes now says which files apply.

The startup line that reports an active plugin host lists the files the
activation loaded. `hermes doctor` gains a NeMo Relay Plugins section: it
resolves the same layers through Relay's validator, which loads no plugin
code and leaves the process-wide host alone, then lists each file, whether
anything is enabled, and any error or warning Relay reports. A configuration
Relay would reject counts as a doctor issue. Validation cannot load dynamic
plugins, so a warning marks the row without counting as an issue.

The docs give the user and system file locations for each platform and point
to `hermes doctor`.
2026-09-29 12:16:43 -04:00

51 lines
2.2 KiB
Python

"""``hermes doctor`` names the Relay plugin files the runtime actually loads.
Relay discovers user and system ``plugins.toml`` files outside the Hermes home, so doctor is the one
Hermes surface that shows a user which files apply. It must agree with what initialization loads.
"""
import pytest
from agent import relay_runtime
from hermes_cli.doctor_config import _check_relay_plugins
ENABLED_OBSERVABILITY = (
"version = 1\n\n[[components]]\nkind = \"observability\"\nenabled = true\n\n[components.config]\nversion = 4\n"
)
@pytest.mark.parametrize("explicit", [False, True], ids=["discovered", "explicit"])
def test_doctor_lists_the_files_the_runtime_loads(tmp_path, monkeypatch, capsys, explicit):
relay = pytest.importorskip("nemo_relay")
if getattr(relay, "_native", None) is None:
pytest.skip("NeMo Relay native binding is unavailable on this platform")
user_config = tmp_path / "xdg" / "nemo-relay" / "plugins.toml"
user_config.parent.mkdir(parents=True)
user_config.write_text(ENABLED_OBSERVABILITY, encoding="utf-8")
monkeypatch.setenv("XDG_CONFIG_HOME", str(tmp_path / "xdg"))
monkeypatch.setenv("ProgramData", str(tmp_path / "programdata"))
if explicit:
selected = tmp_path / "selected.toml"
selected.write_text(ENABLED_OBSERVABILITY, encoding="utf-8")
monkeypatch.setenv(relay_runtime.RELAY_PLUGINS_CONFIG_ENV, str(selected))
else:
monkeypatch.delenv(relay_runtime.RELAY_PLUGINS_CONFIG_ENV, raising=False)
_check_relay_plugins(False)
doctor_output = capsys.readouterr().out
relay_runtime._reset_for_tests()
host = relay_runtime.RelayRuntime(relay=relay, profile_key="profile")
try:
assert host._plugin_configuration_state is relay_runtime._RelayPluginConfigurationState.ACTIVE
loaded = relay_runtime._activation_config_paths(relay_runtime._PLUGIN_CONFIGURATION._activation)
finally:
host.shutdown()
relay_runtime._reset_for_tests()
assert (str(user_config) in loaded) is not explicit
assert "Relay plugins enabled" in doctor_output
assert all(path in doctor_output for path in loaded)
if explicit:
assert str(user_config) not in doctor_output