mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-10-20 05:15:31 +00:00
fix(slack): guard against empty text in chat.postMessage
Slack API returns `no_text` error when `chat.postMessage` is called with empty or whitespace-only text. This happens when cron delivery posts a response before the agent produces content (e.g. malformed turn before [SILENT]). Add early-return guards in both code paths: - `_standalone_send()`: out-of-process cron delivery via Web API - `send()`: in-process gateway adapter Both paths now skip the API call and return success when the formatted message is empty or whitespace-only. Fixes #52663
This commit is contained in:
parent
c13af09177
commit
a2d8b4b1f6
2 changed files with 76 additions and 0 deletions
|
|
@ -1566,6 +1566,11 @@ class SlackAdapter(BasePlatformAdapter):
|
|||
# Convert standard markdown → Slack mrkdwn
|
||||
formatted = self.format_message(content)
|
||||
|
||||
# Guard against empty/whitespace-only messages — Slack API
|
||||
# returns ``no_text`` for chat.postMessage with blank text.
|
||||
if not formatted or not formatted.strip():
|
||||
return SendResult(success=True)
|
||||
|
||||
# Split long messages, preserving code block boundaries
|
||||
chunks = self.truncate_message(formatted, self.MAX_MESSAGE_LENGTH)
|
||||
|
||||
|
|
@ -5203,6 +5208,14 @@ async def _standalone_send(
|
|||
exc_info=True,
|
||||
)
|
||||
|
||||
if not formatted or not formatted.strip():
|
||||
logger.debug("[Slack] _standalone_send: skipping empty/whitespace message")
|
||||
return {
|
||||
"success": True,
|
||||
"platform": "slack",
|
||||
"skipped": "empty_text",
|
||||
}
|
||||
|
||||
try:
|
||||
import aiohttp
|
||||
except ImportError:
|
||||
|
|
|
|||
|
|
@ -4071,6 +4071,69 @@ class TestMessageSplitting:
|
|||
assert "<https://en.wikipedia.org/wiki/Foo_(bar)|Foo>" in kwargs["text"]
|
||||
|
||||
|
||||
class TestEmptyTextGuard:
|
||||
"""Guard against Slack ``no_text`` errors when content is empty/whitespace."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_send_skips_empty_string(self, adapter):
|
||||
"""Empty content must not call chat_postMessage."""
|
||||
adapter._app.client.chat_postMessage = AsyncMock(return_value={"ts": "ts1"})
|
||||
result = await adapter.send("C123", "")
|
||||
assert result.success is True
|
||||
adapter._app.client.chat_postMessage.assert_not_called()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_send_skips_whitespace_only(self, adapter):
|
||||
"""Whitespace-only content must not call chat_postMessage."""
|
||||
adapter._app.client.chat_postMessage = AsyncMock(return_value={"ts": "ts1"})
|
||||
result = await adapter.send("C123", " \n\t ")
|
||||
assert result.success is True
|
||||
adapter._app.client.chat_postMessage.assert_not_called()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_standalone_send_skips_empty(self, monkeypatch):
|
||||
"""_standalone_send returns success without HTTP call on empty text."""
|
||||
from plugins.platforms.slack.adapter import _standalone_send
|
||||
from types import SimpleNamespace
|
||||
|
||||
pconfig = SimpleNamespace(token="xoxb-test", extra={})
|
||||
|
||||
# Patch aiohttp so the import succeeds, but it should never be used.
|
||||
mock_session = MagicMock()
|
||||
mock_session.__aenter__ = AsyncMock(return_value=mock_session)
|
||||
mock_session.__aexit__ = AsyncMock(return_value=False)
|
||||
monkeypatch.setattr(
|
||||
"plugins.platforms.slack.adapter.aiohttp",
|
||||
MagicMock(ClientSession=MagicMock(return_value=mock_session)),
|
||||
)
|
||||
|
||||
result = await _standalone_send(pconfig, "C123", "")
|
||||
assert result.get("success") is True
|
||||
assert result.get("skipped") == "empty_text"
|
||||
mock_session.post.assert_not_called()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_standalone_send_skips_whitespace(self, monkeypatch):
|
||||
"""_standalone_send returns success without HTTP call on whitespace."""
|
||||
from plugins.platforms.slack.adapter import _standalone_send
|
||||
from types import SimpleNamespace
|
||||
|
||||
pconfig = SimpleNamespace(token="xoxb-test", extra={})
|
||||
|
||||
mock_session = MagicMock()
|
||||
mock_session.__aenter__ = AsyncMock(return_value=mock_session)
|
||||
mock_session.__aexit__ = AsyncMock(return_value=False)
|
||||
monkeypatch.setattr(
|
||||
"plugins.platforms.slack.adapter.aiohttp",
|
||||
MagicMock(ClientSession=MagicMock(return_value=mock_session)),
|
||||
)
|
||||
|
||||
result = await _standalone_send(pconfig, "C123", " \n ")
|
||||
assert result.get("success") is True
|
||||
assert result.get("skipped") == "empty_text"
|
||||
mock_session.post.assert_not_called()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# TestReplyBroadcast
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue