fix(slack): preserve thread parent context when posted by a bot#12561
Closed
Satoshi-agi wants to merge 1 commit into
Closed
fix(slack): preserve thread parent context when posted by a bot#12561Satoshi-agi wants to merge 1 commit into
Satoshi-agi wants to merge 1 commit into
Conversation
…arent
The Slack thread-context fetcher used to drop every message with a
bot_id, which silently erased the thread parent whenever a cron job (or
any other bot) had posted it. As a result, replies to a cron-posted
summary lost all context and the agent answered as if from a blank
thread.
Changes:
1. gateway/platforms/slack.py::_fetch_thread_context
- Keep the thread parent even when it was posted by a bot
(e.g. cron summaries, third-party integrations).
- Only skip *our own* prior bot replies to avoid circular context,
matching the per-workspace bot user id via _team_bot_user_ids so
multi-workspace deployments stay correct.
- Keep non-self bot children (useful third-party context).
2. gateway/platforms/slack.py::_handle_slack_message
- Populate MessageEvent.reply_to_text for thread replies (parity
with Telegram/Discord/Feishu/WeCom). gateway.run uses this field
to inject a [Replying to: "..."] prefix when the parent is not
already in the session history, which is exactly the scenario
triggered by cron-generated thread parents.
- New helper _fetch_thread_parent_text reuses the existing thread-
context cache (and its 60s TTL) to avoid duplicate
conversations.replies calls; falls back to a cheap limit=1 fetch
when the cache is cold.
Tests:
- Updated TestSlackThreadContext::test_skips_bot_messages to reflect
the new behaviour (self-bot child dropped, third-party bot kept).
- Added:
* test_fetch_thread_context_includes_bot_parent
* test_fetch_thread_context_excludes_self_bot_replies
* test_fetch_thread_context_multi_workspace
* test_fetch_thread_context_current_ts_excluded (regression guard)
* test_fetch_thread_parent_text_from_cache
* test_slack_reply_to_text_set_on_thread_reply
* test_slack_reply_to_text_none_for_top_level_message
Full Slack suite: 176 passed (was 169).
Collaborator
|
Likely duplicate of #12527 — same root cause: _fetch_thread_context() filters all bot messages instead of just self-bot replies. |
Contributor
|
Merged via #16200 — your commit was cherry-picked onto current main with your authorship preserved (e8b1fdc). Thanks for the thorough fix — the multi-workspace self-bot identification via |
This was referenced Apr 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When a cron job posts a message to Slack and the user replies in the thread, Hermes previously lost the parent message context and responded with "I don't have the previous context".
Root Cause
gateway/platforms/slack.py::_fetch_thread_context()unconditionally filtered out any message withbot_id, including the thread parent. Cron-posted messages carrybot_id, so the parent was silently dropped andcontext_partsended up empty._handle_slack_message()never populatedMessageEvent.reply_to_text, sogateway/run.py's shared[Replying to: "..."]injection path (which already works on Telegram/Discord/Feishu/WeCom) was dead code for Slack.Fix
_fetch_thread_context(): keep bot-posted parents. Only skip our own prior bot replies (circular-context guard) using per-workspace_team_bot_user_ids.get(team)with_bot_user_idfallback — so multi-workspace deployments stay correct. Non-self bot children (e.g. other integrations) are preserved as useful context._handle_slack_message(): populateMessageEvent.reply_to_texton thread replies, parity with Telegram/Discord. A new_fetch_thread_parent_text()helper reuses the existing 60s TTL thread cache and only falls back to a cheapconversations.replies(limit=1, inclusive=True)call on cache miss — so no additional API pressure.Tests (+7 new, 1 updated)
test_fetch_thread_context_includes_bot_parent— cron-posted parent surfaces with[thread parent]prefixtest_fetch_thread_context_excludes_self_bot_replies— self-bot child excluded, other-bot parent + user children kepttest_fetch_thread_context_multi_workspace— per-workspace self-bot identificationtest_fetch_thread_context_current_ts_excluded— regression guardtest_fetch_thread_parent_text_from_cache— cache reuse, no duplicate API calltest_slack_reply_to_text_set_on_thread_reply— end-to-endreply_to_textpopulated for thread-reply DMtest_slack_reply_to_text_none_for_top_level_message— top-level DM doesn't setreply_to_texttest_skips_bot_messagesto match corrected behaviorTest Results
main(pre-existing flaky tests untouched)Impact
Slack adapter only. No changes to session persistence, prompt caching, or other platforms.