From 7e8f50a14176e02b514631b0b04470acaadae32a Mon Sep 17 00:00:00 2001 From: yoma Date: Sun, 5 Jul 2026 01:51:26 +0800 Subject: [PATCH] fix(gateway): load display config from routed profile --- gateway/run.py | 13 +++++++-- tests/gateway/test_multiplex_phase0.py | 40 +++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/gateway/run.py b/gateway/run.py index 484e5d0bc2e..ade178629f1 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -1260,7 +1260,7 @@ _ensure_ssl_certs() sys.path.insert(0, str(Path(__file__).parent.parent)) # Resolve Hermes home directory (respects HERMES_HOME override) -from hermes_constants import get_hermes_home +from hermes_constants import get_hermes_home, get_hermes_home_override from utils import atomic_json_write, atomic_yaml_write, base_url_host_matches, is_truthy_value _hermes_home = get_hermes_home() @@ -2249,6 +2249,14 @@ def _teams_pipeline_plugin_enabled() -> bool: return "teams_pipeline" in enabled or "teams-pipeline" in enabled +def _gateway_config_home() -> Path: + """Return the Hermes home that gateway config reads should use.""" + override = get_hermes_home_override() + if override: + return Path(override) + return _hermes_home + + def _load_gateway_config() -> dict: """Load and parse ~/.hermes/config.yaml, returning {} on any error. @@ -2260,7 +2268,8 @@ def _load_gateway_config() -> dict: gateway honors administrator-pinned values — neither read_raw_config nor a direct yaml.safe_load carries the managed merge on its own. Fail-open. """ - config_path = _hermes_home / 'config.yaml' + config_home = _gateway_config_home() + config_path = config_home / 'config.yaml' raw: dict = {} used_canonical = False try: diff --git a/tests/gateway/test_multiplex_phase0.py b/tests/gateway/test_multiplex_phase0.py index 0297b08494c..798bca3a7d2 100644 --- a/tests/gateway/test_multiplex_phase0.py +++ b/tests/gateway/test_multiplex_phase0.py @@ -10,7 +10,9 @@ Covers the three Phase 0 deliverables: """ import pytest from unittest.mock import patch +import yaml +from hermes_constants import reset_hermes_home_override, set_hermes_home_override from gateway.config import GatewayConfig, Platform from gateway.session import SessionSource, SessionStore, build_session_key @@ -127,6 +129,43 @@ class TestMultiplexConfigFlag: cfg = GatewayConfig.from_dict(GatewayConfig(multiplex_profiles=True).to_dict()) assert cfg.multiplex_profiles is True + def test_gateway_config_loader_honors_profile_runtime_scope(self, tmp_path, monkeypatch): + """Multiplexed turns must resolve display settings from the routed profile.""" + import gateway.run as gateway_run + + root_home = tmp_path / "root" + profile_home = tmp_path / "profiles" / "quiet" + root_home.mkdir(parents=True) + profile_home.mkdir(parents=True) + + (root_home / "config.yaml").write_text( + yaml.safe_dump( + {"display": {"tool_progress": "all", "interim_assistant_messages": True}}, + sort_keys=False, + ), + encoding="utf-8", + ) + (profile_home / "config.yaml").write_text( + yaml.safe_dump( + {"display": {"tool_progress": False, "interim_assistant_messages": False}}, + sort_keys=False, + ), + encoding="utf-8", + ) + + monkeypatch.setattr(gateway_run, "_hermes_home", root_home) + + assert gateway_run._load_gateway_config()["display"]["tool_progress"] == "all" + + token = set_hermes_home_override(profile_home) + try: + scoped_config = gateway_run._load_gateway_config() + finally: + reset_hermes_home_override(token) + + assert scoped_config["display"]["tool_progress"] is False + assert scoped_config["display"]["interim_assistant_messages"] is False + class TestSessionStoreProfileResolution: """SessionStore._generate_session_key honors the flag: legacy namespace @@ -162,4 +201,3 @@ class TestSessionStoreProfileResolution: with patch("hermes_cli.profiles.get_active_profile_name", return_value="default"): assert store._generate_session_key(s) == "agent:main:telegram:dm:99" -