mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-03 02:11:48 +00:00
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.
67 lines
2.2 KiB
Python
67 lines
2.2 KiB
Python
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
import pytest
|
|
|
|
from gateway.config import GatewayConfig, Platform, PlatformConfig
|
|
from gateway.platforms.base import SendResult
|
|
from gateway.run import GatewayRunner
|
|
from gateway.session import SessionSource
|
|
|
|
|
|
def _make_source() -> SessionSource:
|
|
return SessionSource(
|
|
platform=Platform.SLACK,
|
|
chat_id="C123",
|
|
chat_type="channel",
|
|
user_id="U123",
|
|
thread_id="111.222",
|
|
)
|
|
|
|
|
|
def _make_runner(extra=None):
|
|
runner = object.__new__(GatewayRunner)
|
|
runner.config = GatewayConfig(
|
|
platforms={
|
|
Platform.SLACK: PlatformConfig(enabled=True, token="***", extra=extra or {})
|
|
}
|
|
)
|
|
adapter = MagicMock()
|
|
adapter.send = AsyncMock(return_value=SendResult(success=True, message_id="public-1"))
|
|
adapter.send_private_notice = AsyncMock(return_value=SendResult(success=True, message_id="private-1"))
|
|
runner.adapters = {Platform.SLACK: adapter}
|
|
return runner, adapter
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_deliver_platform_notice_uses_private_delivery_when_configured():
|
|
runner, adapter = _make_runner(extra={"notice_delivery": "private"})
|
|
|
|
await runner._deliver_platform_notice(_make_source(), "hello")
|
|
|
|
adapter.send_private_notice.assert_awaited_once_with(
|
|
"C123",
|
|
"U123",
|
|
"hello",
|
|
metadata={"thread_id": "111.222"},
|
|
)
|
|
adapter.send.assert_not_awaited()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_deliver_platform_notice_falls_back_to_public_when_private_fails():
|
|
runner, adapter = _make_runner(extra={"notice_delivery": "private"})
|
|
adapter.send_private_notice = AsyncMock(return_value=SendResult(success=False, error="nope"))
|
|
|
|
await runner._deliver_platform_notice(_make_source(), "hello")
|
|
|
|
adapter.send.assert_awaited_once_with("C123", "hello", metadata={"thread_id": "111.222"})
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_deliver_platform_notice_uses_public_delivery_by_default():
|
|
runner, adapter = _make_runner()
|
|
|
|
await runner._deliver_platform_notice(_make_source(), "hello")
|
|
|
|
adapter.send.assert_awaited_once_with("C123", "hello", metadata={"thread_id": "111.222"})
|
|
adapter.send_private_notice.assert_not_awaited()
|