feat(gateway): private notice delivery and Slack format_message fixes

Adds platform-level private notice delivery abstraction so operational
messages (e.g. sethome prompt) can be sent ephemerally on Slack when
configured with `slack.notice_delivery: private`.

Changes:
- gateway/config.py: _normalize_notice_delivery() + GatewayConfig.get_notice_delivery()
  with per-platform config bridging
- gateway/platforms/base.py: send_private_notice() default implementation
  (falls through to send())
- gateway/platforms/slack.py: send_private_notice() via chat_postEphemeral
- gateway/run.py: _deliver_platform_notice() helper replaces direct
  adapter.send() for the sethome notice, with private→public fallback
- gateway/platforms/slack.py: app_mention handler now forwards to
  _handle_slack_message (safe due to ts-based dedup) instead of no-op pass,
  fixing edge-case Slack configs where mentions arrive only as app_mention
- gateway/platforms/slack.py format_message: negative lookbehind prevents
  markdown images (![]()) from becoming broken Slack links; italic regex
  now requires non-whitespace boundaries so 'a * b * c' stays literal

Based on PR #9340 by @probepark.
This commit is contained in:
probepark 2026-05-01 09:07:39 +05:30 committed by kshitij
parent 7cda0e5224
commit 0ab2d752ff
7 changed files with 269 additions and 25 deletions

View file

@ -213,6 +213,26 @@ class TestGatewayConfigRoundtrip:
restored = GatewayConfig.from_dict({"always_log_local": "false"})
assert restored.always_log_local is False
def test_get_notice_delivery_defaults_to_public(self):
config = GatewayConfig(
platforms={Platform.SLACK: PlatformConfig(enabled=True, token="***")}
)
assert config.get_notice_delivery(Platform.SLACK) == "public"
def test_get_notice_delivery_honors_platform_override(self):
config = GatewayConfig(
platforms={
Platform.SLACK: PlatformConfig(
enabled=True,
token="***",
extra={"notice_delivery": "private"},
),
}
)
assert config.get_notice_delivery(Platform.SLACK) == "private"
class TestLoadGatewayConfig:
def test_bridges_quick_commands_from_config_yaml(self, tmp_path, monkeypatch):
@ -457,6 +477,22 @@ class TestLoadGatewayConfig:
assert config.platforms[Platform.TELEGRAM].extra["disable_link_previews"] is True
def test_bridges_notice_delivery_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(
"slack:\n"
" notice_delivery: private\n",
encoding="utf-8",
)
monkeypatch.setenv("HERMES_HOME", str(hermes_home))
config = load_gateway_config()
assert config.get_notice_delivery(Platform.SLACK) == "private"
def test_bridges_telegram_proxy_url_from_config_yaml(self, tmp_path, monkeypatch):
hermes_home = tmp_path / ".hermes"
hermes_home.mkdir()