Skip to content

fix(slack): thread-parent context, multi-workspace cache key, Slack Connect files#16200

Merged
teknium1 merged 4 commits into
mainfrom
hermes/hermes-aa28dba4
Apr 26, 2026
Merged

fix(slack): thread-parent context, multi-workspace cache key, Slack Connect files#16200
teknium1 merged 4 commits into
mainfrom
hermes/hermes-aa28dba4

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Three independent Slack thread-context bugs fixed together.

Changes

1. Thread parent preserved when cron/bot posted it (@Satoshi-agi, #12561)
_fetch_thread_context unconditionally skipped any message with bot_id, dropping cron-posted thread parents. Now skips only our own prior bot replies (using per-workspace _team_bot_user_ids.get(team) for multi-workspace correctness) — the parent is preserved even if it was posted by a bot, and non-self bot children (alerts/webhooks) are kept as useful context. Also populates MessageEvent.reply_to_text on thread replies so gateway.run's shared [Replying to: "..."] injection works on Slack (parity with Telegram/Discord/Feishu/WeCom). New _fetch_thread_parent_text() reuses the thread-context cache; falls back to conversations.replies(limit=1, inclusive=True).

2. Multi-workspace cache correctness (@flobo3, #12502)
Thread-context cache key didn't include team_id. In multi-workspace Slack mode, a lookup from workspace B could receive stale context that was rendered with workspace A's bot identity and user-name resolution. Include team_id in the cache key for both _fetch_thread_context and _fetch_thread_parent_text.

3. Slack Connect attachments (@kunlabs, #11111)
Slack Connect channels return file objects with file_access="check_file_info" and no url_private_download — stub objects that require a files.info call to resolve. Previously the agent silently skipped them. Now calls files.info on any such stub, replaces it with the full object, and lets the existing download path continue.

Validation

Before After
Cron-posted thread parent Dropped from context Preserved
Thread reply across workspaces Stale context possible Correct per workspace
Slack Connect file Silently skipped Downloaded
test_slack.py + test_slack_approval_buttons.py + test_slack_mention.py n/a 198 passed

Credits

Also closes as already-fixed

Closes #2950
Closes #11095
Closes #12421

Satoshi-agi and others added 4 commits April 26, 2026 12:33
…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).
Slack Connect channels return file objects with file_access="check_file_info"
and no url_private_download field (see
https://docs.slack.dev/reference/objects/file-object/#slack_connect_files).
These stub objects must be resolved via files.info before download can
proceed. Without this the agent silently skips attachments posted in
Slack Connect channels.

Call files.info on every file whose file_access is check_file_info,
replace the stub with the full file object, and let the existing
download path continue. Warn and skip on files.info failures.

Closes #11095.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists platform/slack Slack app adapter type/bug Something isn't working

Projects

None yet

4 participants