diff --git a/gateway/config.py b/gateway/config.py index 613527a847..47c739e910 100644 --- a/gateway/config.py +++ b/gateway/config.py @@ -308,6 +308,16 @@ def load_gateway_config() -> GatewayConfig: if sr and isinstance(sr, dict): config.default_reset_policy = SessionResetPolicy.from_dict(sr) + # Bridge quick commands from config.yaml into gateway runtime config. + # config.yaml is the user-facing config source, so when present it + # should override gateway.json for this setting. + qc = yaml_cfg.get("quick_commands") + if qc is not None: + if isinstance(qc, dict): + config.quick_commands = qc + else: + logger.warning("Ignoring invalid quick_commands in config.yaml (expected mapping, got %s)", type(qc).__name__) + # Bridge discord settings from config.yaml to env vars # (env vars take precedence — only set if not already defined) discord_cfg = yaml_cfg.get("discord", {}) diff --git a/gateway/run.py b/gateway/run.py index 2e02a9b3af..a952c79c32 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -1017,6 +1017,8 @@ class GatewayRunner: quick_commands = self.config.get("quick_commands", {}) or {} else: quick_commands = getattr(self.config, "quick_commands", {}) or {} + if not isinstance(quick_commands, dict): + quick_commands = {} if command in quick_commands: qcmd = quick_commands[command] if qcmd.get("type") == "exec": diff --git a/tests/gateway/test_config.py b/tests/gateway/test_config.py index 8cbb739f0f..c604ee521c 100644 --- a/tests/gateway/test_config.py +++ b/tests/gateway/test_config.py @@ -6,6 +6,7 @@ from gateway.config import ( Platform, PlatformConfig, SessionResetPolicy, + load_gateway_config, ) @@ -89,15 +90,49 @@ class TestGatewayConfigRoundtrip: platforms={ Platform.TELEGRAM: PlatformConfig( enabled=True, - token="tok", + token="tok_123", home_channel=HomeChannel(Platform.TELEGRAM, "123", "Home"), ), }, reset_triggers=["/new"], + quick_commands={"limits": {"type": "exec", "command": "echo ok"}}, ) d = config.to_dict() restored = GatewayConfig.from_dict(d) assert Platform.TELEGRAM in restored.platforms - assert restored.platforms[Platform.TELEGRAM].token == "tok" + assert restored.platforms[Platform.TELEGRAM].token == "tok_123" assert restored.reset_triggers == ["/new"] + assert restored.quick_commands == {"limits": {"type": "exec", "command": "echo ok"}} + + +class TestLoadGatewayConfig: + def test_bridges_quick_commands_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( + "quick_commands:\n" + " limits:\n" + " type: exec\n" + " command: echo ok\n", + encoding="utf-8", + ) + + monkeypatch.setenv("HERMES_HOME", str(hermes_home)) + + config = load_gateway_config() + + assert config.quick_commands == {"limits": {"type": "exec", "command": "echo ok"}} + + def test_invalid_quick_commands_in_config_yaml_are_ignored(self, tmp_path, monkeypatch): + hermes_home = tmp_path / ".hermes" + hermes_home.mkdir() + config_path = hermes_home / "config.yaml" + config_path.write_text("quick_commands: not-a-mapping\n", encoding="utf-8") + + monkeypatch.setenv("HERMES_HOME", str(hermes_home)) + + config = load_gateway_config() + + assert config.quick_commands == {}