Reconcile Slack report feature with dev merge

Dev refactored slack_thread_reply to async and already added
post_slack_top_level_message_with_ts; drop the duplicate definition
and await the tool in the feature's tests.

Refs: #82
This commit is contained in:
amoussa1229 2026-06-30 21:07:56 +00:00
parent b9702adfc5
commit 4d407b98a3
2 changed files with 6 additions and 57 deletions

View file

@ -444,57 +444,6 @@ async def post_slack_thread_reply(channel_id: str, thread_ts: str, text: str) ->
return message_ts is not None
async def post_slack_top_level_message_with_ts(
channel_id: str,
text: str,
*,
unfurl_links: bool = True,
unfurl_media: bool = True,
blocks: list[dict[str, Any]] | None = None,
) -> tuple[str | None, str | None]:
"""Post a fresh top-level message to a channel and return its ts and error."""
if not SLACK_BOT_TOKEN:
return None, "missing_slack_bot_token"
payload: dict[str, Any] = {
"channel": channel_id,
"text": text,
"unfurl_links": unfurl_links,
"unfurl_media": unfurl_media,
}
if blocks:
payload["blocks"] = blocks
async with httpx.AsyncClient() as http_client:
try:
response = await http_client.post(
f"{SLACK_API_BASE_URL}/chat.postMessage",
headers=_slack_headers(),
json=payload,
)
if response.status_code == 429:
retry_after = response.headers.get("Retry-After")
logger.warning("Slack chat.postMessage rate limited (retry-after=%s)", retry_after)
if retry_after:
return None, f"rate_limited: {retry_after}"
return None, "rate_limited"
response.raise_for_status()
data = response.json()
if not data.get("ok"):
error = data.get("error")
logger.warning("Slack chat.postMessage failed: %s", error)
if error == "ratelimited":
return None, "rate_limited"
return None, error
message_ts = data.get("ts")
if isinstance(message_ts, str) and message_ts:
return message_ts, None
return None, None
except httpx.HTTPError as exc:
logger.exception("Slack chat.postMessage request failed")
return None, f"http_error: {type(exc).__name__}"
async def post_slack_ephemeral_message(
channel_id: str, user_id: str, text: str, thread_ts: str | None = None
) -> bool:

View file

@ -175,16 +175,16 @@ def _channel_only_config() -> dict[str, Any]:
return {"configurable": {"slack_thread": {"channel_id": "C9"}}}
def test_slack_thread_reply_requires_channel_id(monkeypatch: pytest.MonkeyPatch) -> None:
async def test_slack_thread_reply_requires_channel_id(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(slack_reply_tool, "get_config", lambda: {"configurable": {}})
result = slack_reply_tool.slack_thread_reply("hello")
result = await slack_reply_tool.slack_thread_reply("hello")
assert result["success"] is False
assert result["error"] == "Missing slack_thread.channel_id in config"
def test_slack_thread_reply_posts_top_level_when_no_thread_ts(
async def test_slack_thread_reply_posts_top_level_when_no_thread_ts(
monkeypatch: pytest.MonkeyPatch,
) -> None:
captured: dict[str, Any] = {}
@ -205,14 +205,14 @@ def test_slack_thread_reply_posts_top_level_when_no_thread_ts(
monkeypatch.setattr(slack_reply_tool, "post_slack_top_level_message_with_ts", fake_top_level)
monkeypatch.setattr(slack_reply_tool, "post_slack_thread_reply_with_ts", fail_thread_reply)
result = slack_reply_tool.slack_thread_reply("Scheduled report")
result = await slack_reply_tool.slack_thread_reply("Scheduled report")
assert result == {"success": True}
assert captured["channel_id"] == "C9"
assert captured["text"] == "Scheduled report"
def test_slack_thread_reply_top_level_surfaces_not_in_channel(
async def test_slack_thread_reply_top_level_surfaces_not_in_channel(
monkeypatch: pytest.MonkeyPatch,
) -> None:
async def fake_top_level(
@ -226,7 +226,7 @@ def test_slack_thread_reply_top_level_surfaces_not_in_channel(
monkeypatch.setattr(slack_reply_tool, "get_config", _channel_only_config)
monkeypatch.setattr(slack_reply_tool, "post_slack_top_level_message_with_ts", fake_top_level)
result = slack_reply_tool.slack_thread_reply("Scheduled report")
result = await slack_reply_tool.slack_thread_reply("Scheduled report")
assert result["success"] is False
assert result["slack_error"] == "not_in_channel"