Skip to content

fix(slack): read thread context from message attachments and blocks - #61261

Closed
xcompass wants to merge 1 commit into
NousResearch:mainfrom
ubc:fix/slack-thread-context-attachments
Closed

fix(slack): read thread context from message attachments and blocks#61261
xcompass wants to merge 1 commit into
NousResearch:mainfrom
ubc:fix/slack-thread-context-attachments

Conversation

@xcompass

@xcompass xcompass commented Jul 9, 2026

Copy link
Copy Markdown

Problem

When the bot is @mentioned mid-thread for the first time, _fetch_thread_context
fetches prior thread messages (conversations.replies) and prepends them as context —
but it reads only each message's plain text field:

msg_text = msg.get("text", "").strip()
if not msg_text:
    continue

Apps like Alertmanager, Grafana, PagerDuty, and CI bots post with an empty text
and the real content in legacy attachments or Block Kit blocks. Those messages
are dropped — so when such a message starts the thread (e.g. a firing alert), an agent
asked to investigate sees an empty thread and can only reply "What should I investigate?".

Observed on a real Alertmanager thread (details genericized):

sender text content
Alertmanager (bot) "" attachments[0][FIRING:1] KubeJobFailed cluster-01 batch-job-123456
user @bot investigate
bot "What should I investigate? …"

_fetch_thread_parent_text has the same gap.

Fix

When text is empty, fall back to:

  1. _extract_text_from_slack_blocks(msg["blocks"]) — already used for live incoming messages;
  2. a new _extract_text_from_slack_attachments(msg["attachments"]) helper that pulls
    pretext/title/text/fields (plus nested blocks), using the fallback string only
    when an attachment has nothing structured.

Applied in both _fetch_thread_context and _fetch_thread_parent_text. No behavior change
for messages that already have text.

Tests

New TestThreadContextAppMessages covers attachment-only (Alertmanager-style), blocks-only,
and truly-empty messages. tests/gateway/test_slack.py passes (incl. existing thread-context
tests) and ruff check is clean.

`_fetch_thread_context` and `_fetch_thread_parent_text` only read each
message's plain `text` field, so messages posted by apps (Alertmanager,
Grafana, PagerDuty, CI bots) — which carry their content in legacy
`attachments` or Block Kit `blocks` with an empty `text` — were dropped
entirely. When such a message *starts* a thread (e.g. an alert), a bot
mentioned mid-thread to investigate sees an empty thread and can only ask
"what should I investigate?".

Fall back to the existing `_extract_text_from_slack_blocks` and a new
`_extract_text_from_slack_attachments` helper when `text` is empty, so
app-posted alerts and notifications are visible in fetched thread history.

Adds TestThreadContextAppMessages (attachment-only, blocks-only, and
empty-message cases).
@alt-glitch alt-glitch added type/bug Something isn't working comp/gateway Gateway runner, session dispatch, delivery platform/slack Slack app adapter P2 Medium — degraded but workaround exists labels Jul 9, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Competing/related cluster for Slack bot-alert thread context: #33493 targets the now-relocated gateway/platforms/slack.py (_fetch_thread_context only, attachments[].text/fallback); this PR targets the current plugins/platforms/slack/adapter.py and is a superset — it adds Block Kit + a richer attachment extractor (pretext/title/fields/nested blocks) and covers _fetch_thread_parent_text too. #52219 is a sibling on a different code path (inbound message-text extraction, not fetched thread context). Not a duplicate; linking for reviewer comparison.

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for covering the fetched-thread path and the related parent-text path.

Problems

  • The Block Kit portion is incomplete: _extract_text_from_slack_blocks only processes rich_text blocks at plugins/platforms/slack/adapter.py:203-205, while the new fallback at plugins/platforms/slack/adapter.py:3833-3836 relies on it for every block payload. An empty-text standard section block is therefore still dropped. The added blocks test uses only rich_text at tests/gateway/test_slack.py:4255-4267.

Suggested changes

  • Render standard text-bearing Block Kit block types in this fetched-context fallback (or use an existing suitable sanitized representation) and add a section-block regression test.
  • Add a cold-cache _fetch_thread_parent_text attachment/block regression test; the current tests cover _fetch_thread_context only.

Automated hermes-sweeper review.

# ``text`` and the content in blocks/attachments — fall back so
# messages that started or populate the thread aren't dropped.
if not msg_text:
msg_text = _extract_text_from_slack_blocks(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_extract_text_from_slack_blocks currently renders only rich_text blocks (adapter.py:203-205). This leaves ordinary text-bearing section blocks empty here, so the message is still skipped. Please cover standard Block Kit text blocks as well and add a matching regression test.

@teknium1 teknium1 added sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 10, 2026
teknium1 pushed a commit that referenced this pull request Jul 22, 2026
Bot-posted alerts (Honeycomb, PagerDuty, Datadog, GitHub bot, etc.) carry
their actionable content — section text, button URLs — in Block Kit
blocks, while the plain text field holds only the alert title.
_fetch_thread_context and _fetch_thread_parent_text only read
msg.get('text'), so that content never reached the agent.

Add a _render_message_text helper that merges top-level text with
readable block content, section/header/context text, actionable URLs,
and (folded in from #61261 during conflict resolution) legacy
attachment fields, and use it for thread-context and parent-text
rendering.

Salvaged from #29541.
teknium1 pushed a commit that referenced this pull request Jul 22, 2026
Bot-posted alerts (Honeycomb, PagerDuty, Datadog, GitHub bot, etc.) carry
their actionable content — section text, button URLs — in Block Kit
blocks, while the plain text field holds only the alert title.
_fetch_thread_context and _fetch_thread_parent_text only read
msg.get('text'), so that content never reached the agent.

Add a _render_message_text helper that merges top-level text with
readable block content, section/header/context text, actionable URLs,
and (folded in from #61261 during conflict resolution) legacy
attachment fields, and use it for thread-context and parent-text
rendering.

Salvaged from #29541.
@teknium1

Copy link
Copy Markdown
Contributor

Merged via #69316 — your commit was cherry-picked onto current main with your authorship preserved in git history: your attachments+blocks thread-context fallback was cherry-picked directly.

Thanks for the contribution!

@teknium1 teknium1 closed this Jul 22, 2026
@xcompass
xcompass deleted the fix/slack-thread-context-attachments branch July 22, 2026 15:42
@xcompass

Copy link
Copy Markdown
Author

Thanks!

randlee pushed a commit to randlee/hermes-agent that referenced this pull request Aug 11, 2026
Bot-posted alerts (Honeycomb, PagerDuty, Datadog, GitHub bot, etc.) carry
their actionable content — section text, button URLs — in Block Kit
blocks, while the plain text field holds only the alert title.
_fetch_thread_context and _fetch_thread_parent_text only read
msg.get('text'), so that content never reached the agent.

Add a _render_message_text helper that merges top-level text with
readable block content, section/header/context text, actionable URLs,
and (folded in from NousResearch#61261 during conflict resolution) legacy
attachment fields, and use it for thread-context and parent-text
rendering.

Salvaged from NousResearch#29541.
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 sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants