mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-27 17:58:07 +00:00
feat(slack): bridge slack.ignored_channels through the YAML→env config path
Follow-up to the #51899 pick, folding in the config-bridge half of the competing PR #46925 (@bhanusharma, earliest submitter for the ignored-channel gate): - _apply_yaml_config: translate config.yaml slack.ignored_channels into SLACK_IGNORED_CHANNELS (list or CSV), env-var-wins like every other bridged Slack key. - SlackAdapter._slack_ignored_channels / gateway.run's _slack_ignored_channels_from_gateway_config: fall back to the SLACK_IGNORED_CHANNELS env var when PlatformConfig.extra carries no value, so top-level slack: blocks (which flow through the env bridge, not extra) are honored at both the adapter and runner gates. - conftest: force-clear SLACK_ALLOWED_CHANNELS / SLACK_IGNORED_CHANNELS / SLACK_DISABLE_DMS between tests (config-loader side-effect leak class). - Tests: env-bridge translation + precedence in test_config.py, env fallback + extra-wins in test_slack_runner_ignored_channels.py. Credit: #46925 by @bhanusharma proposed the same gate with the YAML→env bridge; #51899 (picked as the base) carries the wider outbound/runner coverage. Closes #46925 as consolidated here with first-submitter credit.
This commit is contained in:
parent
0a5d8a16fc
commit
da131aef3a
5 changed files with 72 additions and 1 deletions
|
|
@ -966,6 +966,11 @@ def _slack_ignored_channels_from_gateway_config(config: Any) -> set[str]:
|
|||
raw = None
|
||||
if platform_cfg is not None:
|
||||
raw = getattr(platform_cfg, "extra", {}).get("ignored_channels")
|
||||
if raw is None:
|
||||
# Top-level ``slack.ignored_channels`` config flows through the
|
||||
# plugin's YAML→env bridge (SLACK_IGNORED_CHANNELS) rather than
|
||||
# PlatformConfig.extra — honor it here too (#46925).
|
||||
raw = os.getenv("SLACK_IGNORED_CHANNELS") or None
|
||||
return _csv_or_list_to_set(raw)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -8915,6 +8915,12 @@ def _apply_yaml_config(yaml_cfg: dict, slack_cfg: dict) -> dict | None:
|
|||
if isinstance(ac, list):
|
||||
ac = ",".join(str(v) for v in ac)
|
||||
os.environ["SLACK_ALLOWED_CHANNELS"] = str(ac)
|
||||
# ignored_channels: blacklist channels where Slack must never respond.
|
||||
ic = slack_cfg.get("ignored_channels")
|
||||
if ic is not None and not os.getenv("SLACK_IGNORED_CHANNELS"):
|
||||
if isinstance(ic, list):
|
||||
ic = ",".join(str(v) for v in ic)
|
||||
os.environ["SLACK_IGNORED_CHANNELS"] = str(ic)
|
||||
return None # all settings flow through env; nothing to merge into extras
|
||||
|
||||
|
||||
|
|
@ -8952,7 +8958,8 @@ def register(ctx) -> None:
|
|||
# YAML→env config bridge — owns the translation of config.yaml slack:
|
||||
# keys (require_mention, strict_mention, ignore_other_user_mentions,
|
||||
# thread_require_mention, allow_bots, free_response_channels,
|
||||
# reactions, disable_dms, allowed_channels) into SLACK_* env vars that
|
||||
# reactions, disable_dms, allowed_channels, ignored_channels) into
|
||||
# SLACK_* env vars that
|
||||
# the adapter reads via os.getenv(). Replaces the
|
||||
# hardcoded block in gateway/config.py. Hook contract: #24849.
|
||||
apply_yaml_config_fn=_apply_yaml_config,
|
||||
|
|
|
|||
|
|
@ -321,6 +321,9 @@ _HERMES_BEHAVIORAL_VARS = frozenset({
|
|||
"SLACK_IGNORE_OTHER_USER_MENTIONS",
|
||||
"SLACK_REQUIRE_MENTION_CHANNELS",
|
||||
"SLACK_FREE_RESPONSE_CHANNELS",
|
||||
"SLACK_ALLOWED_CHANNELS",
|
||||
"SLACK_IGNORED_CHANNELS",
|
||||
"SLACK_DISABLE_DMS",
|
||||
"SLACK_ALLOW_BOTS",
|
||||
"SLACK_REACTIONS",
|
||||
"DISCORD_REQUIRE_MENTION",
|
||||
|
|
|
|||
|
|
@ -592,6 +592,42 @@ class TestLoadGatewayConfig:
|
|||
|
||||
assert os.getenv("SLACK_DISABLE_DMS") == "true"
|
||||
|
||||
def test_slack_ignored_channels_config_sets_env_bridge(self, tmp_path, monkeypatch):
|
||||
hermes_home = tmp_path / ".hermes"
|
||||
hermes_home.mkdir()
|
||||
(hermes_home / "config.yaml").write_text(
|
||||
"slack:\n"
|
||||
" ignored_channels:\n"
|
||||
" - C0123456789\n"
|
||||
" - C0987654321\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
monkeypatch.setenv("HERMES_HOME", str(hermes_home))
|
||||
monkeypatch.delenv("SLACK_IGNORED_CHANNELS", raising=False)
|
||||
|
||||
load_gateway_config()
|
||||
|
||||
assert os.getenv("SLACK_IGNORED_CHANNELS") == "C0123456789,C0987654321"
|
||||
|
||||
def test_slack_ignored_channels_env_takes_precedence(self, tmp_path, monkeypatch):
|
||||
"""An explicit SLACK_IGNORED_CHANNELS env var must not be overwritten
|
||||
by the config.yaml bridge."""
|
||||
hermes_home = tmp_path / ".hermes"
|
||||
hermes_home.mkdir()
|
||||
(hermes_home / "config.yaml").write_text(
|
||||
"slack:\n"
|
||||
" ignored_channels: C_FROM_YAML\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
monkeypatch.setenv("HERMES_HOME", str(hermes_home))
|
||||
monkeypatch.setenv("SLACK_IGNORED_CHANNELS", "C_FROM_ENV")
|
||||
|
||||
load_gateway_config()
|
||||
|
||||
assert os.getenv("SLACK_IGNORED_CHANNELS") == "C_FROM_ENV"
|
||||
|
||||
def test_typing_status_text_from_toplevel_platform_block(self, tmp_path, monkeypatch):
|
||||
"""A top-level ``slack:`` block reaches PlatformConfig via the
|
||||
shared-key bridge (bridged into extra, then the from_dict extra
|
||||
|
|
|
|||
|
|
@ -114,3 +114,23 @@ async def test_platform_notice_suppressed_for_slack_ignored_channel():
|
|||
|
||||
adapter.send.assert_not_called()
|
||||
adapter.send_private_notice.assert_not_called()
|
||||
|
||||
|
||||
def test_slack_ignored_channels_env_bridge_fallback(monkeypatch):
|
||||
"""SLACK_IGNORED_CHANNELS (set by the plugin's YAML→env bridge) is
|
||||
honored when PlatformConfig.extra carries no ignored_channels (#46925)."""
|
||||
monkeypatch.setenv("SLACK_IGNORED_CHANNELS", "C_ENV1, C_ENV2")
|
||||
config = _config_with_slack_extra({})
|
||||
|
||||
assert _slack_ignored_channels_from_gateway_config(config) == {"C_ENV1", "C_ENV2"}
|
||||
assert _is_slack_ignored_channel(config, "C_ENV1")
|
||||
assert not _is_slack_ignored_channel(config, "C_OTHER")
|
||||
|
||||
|
||||
def test_slack_ignored_channels_extra_wins_over_env(monkeypatch):
|
||||
"""Explicit PlatformConfig.extra config takes precedence over the env
|
||||
bridge fallback."""
|
||||
monkeypatch.setenv("SLACK_IGNORED_CHANNELS", "C_ENV")
|
||||
config = _config_with_slack_extra({"ignored_channels": ["C_CFG"]})
|
||||
|
||||
assert _slack_ignored_channels_from_gateway_config(config) == {"C_CFG"}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue