fix(slack): extract rich_text quotes/lists and link unfurl previews - #16213
Merged
Conversation
Slack's modern composer sends messages with a 'blocks' array that
contains rich_text elements. When a user forwards or quotes another
message, the quoted content shows up in the rich_text_quote children
of that array — and is NOT included in the plain 'text' field. The
agent saw only the lossy plain text and was blind to forwarded /
quoted content. Same story for link unfurl previews (Notion, docs,
GitHub, etc.) which Slack puts in the 'attachments' array.
Two fixes in the inbound handler:
1. _extract_text_from_slack_blocks walks rich_text / rich_text_quote /
rich_text_list / rich_text_preformatted trees and renders readable
text ('> quoted', '• bullet', code fences), dedupes against the
plain text field, and appends the extracted content so the agent
sees everything.
2. Link unfurl / attachment preview extraction reads title, url,
body, and footer from the 'attachments' array and appends a
'📎 [title](url)\n body\n _footer_' section per preview.
Skips is_msg_unfurl to avoid echoing our own Slack replies back.
Routing is careful not to trust augmented text: mention gating
(is_mentioned) and slash-command detection both run against the
original 'text' field, so forwarded content containing '<@bot>' or
'/deploy' in a quote can't trick the bot into responding in a
channel it shouldn't or classifying a normal message as a command.
Adjustment from original PR: dropped _serialize_slack_blocks_for_agent,
which inlined a redacted JSON dump of non-rich_text blocks (section,
accessory, actions, etc.) — the agent would see the raw Block Kit
structure for UI-heavy alerts. It added up to 6000 characters to the
prompt context on every qualifying message with no opt-out. The
rich_text extraction and attachment unfurls cover the common bug-fix
case (quoted/forwarded content + link previews) without the prefill
tax. If a user needs block inspection later, it can return as a
config opt-in.
Also updates the Slack platform notes in session.py to accurately
describe what the gateway inlines.
19 tasks
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.
Makes the agent see content Slack was already sending but the adapter was dropping. Two cases:
Forwarded/quoted content: Slack's modern composer embeds quotes, lists, and preformatted code in the
blocksarray asrich_text_quote/rich_text_list/rich_text_preformatted— NOT in the plaintextfield. Walking the rich_text tree and rendering as readable markdown (> quoted,• bullet, code fences) surfaces the full message to the agent.Link unfurl previews: Slack puts Notion/docs/GitHub/etc. preview cards in the
attachmentsarray with title, url, body, footer. Reading those and appending a📎 [title](url)\n body\n _footer_section per preview lets the agent see the page summaries that users and Slack clients already see inline.Routing safety
Mention gating and slash-command classification both read
original_text(the raw user field), not the augmented text. So a forwarded message that contains<@bot>in a quote can't trick the bot into responding in a channel it shouldn't, and a quoted/deploydoesn't turn a normal message into a command. Regression test for each.Adjustment from original PR
Dropped
_serialize_slack_blocks_for_agent— the original also inlined a redacted JSON dump of non-rich_text blocks (section / accessory / actions / buttons) so the agent could inspect UI-heavy alerts. That added up to 6000 characters of JSON into the prompt context on every qualifying message with no opt-out. The rich_text + attachments coverage here is the clear bug-fix; full block-payload inspection can come back later behind a config opt-in if a concrete use case shows up.Changes
gateway/platforms/slack.py:_extract_text_from_slack_blockshelper + inline call; link-unfurl extraction fromattachmentsarray; routing guard (original_text for mention + command detection).gateway/session.py: Slack platform notes updated to accurately describe what gets inlined.is_msg_unfurlskip, channel routing ignores mentions in quotes, quoted slash-command doesn't reclassify.Validation
tests/gateway/test_slack.py+test_session.py+test_slack_mention.py+test_slack_approval_buttons.py: 281 passed (3x green).Credits
Closes #11426