From 366bfc3c76e9fd43ab5195f4a8670928f0440bc9 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Sun, 29 Mar 2026 21:53:28 -0700 Subject: [PATCH] fix(setup): auto-install matrix-nio during hermes setup (#3873) Setup previously only printed a manual install hint for matrix-nio, causing the gateway to crash with 'matrix-nio not installed' after configuring Matrix. Now auto-installs matrix-nio (or matrix-nio[e2e] when E2EE is enabled) using the same uv-first/pip-fallback pattern as Daytona and Modal backends. Also adds hermes-agent[matrix] to the [all] extra in pyproject.toml and a regression test to keep it there. Co-authored-by: Gutslabs Co-authored-by: cutepawss --- hermes_cli/setup.py | 32 ++++++++++++++++++++++++++++++-- pyproject.toml | 1 + tests/test_project_metadata.py | 18 ++++++++++++++++++ 3 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 tests/test_project_metadata.py diff --git a/hermes_cli/setup.py b/hermes_cli/setup.py index 63e85a662..35695144d 100644 --- a/hermes_cli/setup.py +++ b/hermes_cli/setup.py @@ -2709,10 +2709,38 @@ def setup_gateway(config: dict): if token or get_env_value("MATRIX_PASSWORD"): # E2EE print() - if prompt_yes_no("Enable end-to-end encryption (E2EE)?", False): + want_e2ee = prompt_yes_no("Enable end-to-end encryption (E2EE)?", False) + if want_e2ee: save_env_value("MATRIX_ENCRYPTION", "true") print_success("E2EE enabled") - print_info(" Requires: pip install 'matrix-nio[e2e]'") + + # Auto-install matrix-nio + matrix_pkg = "matrix-nio[e2e]" if want_e2ee else "matrix-nio" + try: + __import__("nio") + except ImportError: + print_info(f"Installing {matrix_pkg}...") + import subprocess + + uv_bin = shutil.which("uv") + if uv_bin: + result = subprocess.run( + [uv_bin, "pip", "install", "--python", sys.executable, matrix_pkg], + capture_output=True, + text=True, + ) + else: + result = subprocess.run( + [sys.executable, "-m", "pip", "install", matrix_pkg], + capture_output=True, + text=True, + ) + if result.returncode == 0: + print_success(f"{matrix_pkg} installed") + else: + print_warning(f"Install failed — run manually: pip install '{matrix_pkg}'") + if result.stderr: + print_info(f" Error: {result.stderr.strip().splitlines()[-1]}") # Allowed users print() diff --git a/pyproject.toml b/pyproject.toml index ac410ff75..38974e328 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,6 +71,7 @@ all = [ "hermes-agent[modal]", "hermes-agent[daytona]", "hermes-agent[messaging]", + "hermes-agent[matrix]", "hermes-agent[cron]", "hermes-agent[cli]", "hermes-agent[dev]", diff --git a/tests/test_project_metadata.py b/tests/test_project_metadata.py new file mode 100644 index 000000000..1a377f5f5 --- /dev/null +++ b/tests/test_project_metadata.py @@ -0,0 +1,18 @@ +"""Regression tests for packaging metadata in pyproject.toml.""" + +from pathlib import Path +import tomllib + + +def _load_optional_dependencies(): + pyproject_path = Path(__file__).resolve().parents[1] / "pyproject.toml" + with pyproject_path.open("rb") as handle: + project = tomllib.load(handle)["project"] + return project["optional-dependencies"] + + +def test_all_extra_includes_matrix_dependency(): + optional_dependencies = _load_optional_dependencies() + + assert "matrix" in optional_dependencies + assert "hermes-agent[matrix]" in optional_dependencies["all"]