From 0bfe19ba179e21849a8b74eee066d388b41d2e72 Mon Sep 17 00:00:00 2001 From: quen0xi Date: Fri, 29 May 2026 13:45:20 +0300 Subject: [PATCH] fix(gateway): merge nested gateway.platforms configuration block --- gateway/config.py | 20 +++++++++--- tests/gateway/test_config.py | 63 ++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/gateway/config.py b/gateway/config.py index d8ed3ebe8..83b9b912f 100644 --- a/gateway/config.py +++ b/gateway/config.py @@ -779,15 +779,21 @@ def load_gateway_config() -> GatewayConfig: "pair", ) - # Merge platforms section from config.yaml into gw_data so that - # nested keys like platforms.webhook.extra.routes are loaded. - yaml_platforms = yaml_cfg.get("platforms") + # Merge platform config into gw_data so runtime-only settings under + # ``gateway.platforms`` are loaded the same way as top-level + # ``platforms``. Merge nested first so top-level config keeps + # precedence, matching the existing gateway.streaming fallback. + gateway_cfg = yaml_cfg.get("gateway") + gateway_platforms = gateway_cfg.get("platforms") if isinstance(gateway_cfg, dict) else None platforms_data = gw_data.setdefault("platforms", {}) if not isinstance(platforms_data, dict): platforms_data = {} gw_data["platforms"] = platforms_data - if isinstance(yaml_platforms, dict): - for plat_name, plat_block in yaml_platforms.items(): + + def _merge_platform_map(source_platforms: Any) -> None: + if not isinstance(source_platforms, dict): + return + for plat_name, plat_block in source_platforms.items(): if not isinstance(plat_block, dict): continue existing = platforms_data.get(plat_name, {}) @@ -801,6 +807,10 @@ def load_gateway_config() -> GatewayConfig: if merged_extra: merged["extra"] = merged_extra platforms_data[plat_name] = merged + + _merge_platform_map(gateway_platforms) + _merge_platform_map(yaml_cfg.get("platforms")) + if platforms_data: gw_data["platforms"] = platforms_data # Iterate built-in platforms plus any registered plugin platforms # so plugin authors get the same shared-key bridging (#24836). diff --git a/tests/gateway/test_config.py b/tests/gateway/test_config.py index da7673011..d336f54a9 100644 --- a/tests/gateway/test_config.py +++ b/tests/gateway/test_config.py @@ -361,6 +361,69 @@ class TestLoadGatewayConfig: assert config.platforms[Platform.API_SERVER].enabled is False assert Platform.API_SERVER not in config.get_connected_platforms() + def test_bridges_nested_gateway_platforms_from_config_yaml(self, tmp_path, monkeypatch): + hermes_home = tmp_path / ".hermes" + hermes_home.mkdir() + config_path = hermes_home / "config.yaml" + config_path.write_text( + "gateway:\n" + " platforms:\n" + " telegram:\n" + " enabled: true\n" + " token: nested-token\n" + " home_channel:\n" + " platform: telegram\n" + " chat_id: \"123\"\n" + " name: Nested Home\n" + " extra:\n" + " reply_prefix: nested\n", + encoding="utf-8", + ) + + monkeypatch.setenv("HERMES_HOME", str(hermes_home)) + + config = load_gateway_config() + + telegram = config.platforms[Platform.TELEGRAM] + assert telegram.enabled is True + assert telegram.token == "nested-token" + assert telegram.home_channel == HomeChannel( + platform=Platform.TELEGRAM, + chat_id="123", + name="Nested Home", + ) + assert telegram.extra["reply_prefix"] == "nested" + + def test_top_level_platforms_override_nested_gateway_platforms(self, tmp_path, monkeypatch): + hermes_home = tmp_path / ".hermes" + hermes_home.mkdir() + config_path = hermes_home / "config.yaml" + config_path.write_text( + "gateway:\n" + " platforms:\n" + " telegram:\n" + " enabled: false\n" + " token: nested-token\n" + " extra:\n" + " reply_prefix: nested\n" + "platforms:\n" + " telegram:\n" + " enabled: true\n" + " token: top-token\n" + " extra:\n" + " reply_prefix: top\n", + encoding="utf-8", + ) + + monkeypatch.setenv("HERMES_HOME", str(hermes_home)) + + config = load_gateway_config() + + telegram = config.platforms[Platform.TELEGRAM] + assert telegram.enabled is True + assert telegram.token == "top-token" + assert telegram.extra["reply_prefix"] == "top" + def test_bridges_quoted_false_session_notify_from_config_yaml(self, tmp_path, monkeypatch): hermes_home = tmp_path / ".hermes" hermes_home.mkdir()