fix(gateway): strip language tag from Slack fenced code blocks - #21085
Closed
z23 wants to merge 1 commit into
Closed
fix(gateway): strip language tag from Slack fenced code blocks#21085z23 wants to merge 1 commit into
z23 wants to merge 1 commit into
Conversation
Contributor
|
Thanks for the focused regression coverage. The underlying issue remains on current main: Problems
Suggested changes
Automated hermes-sweeper review. |
z23
force-pushed
the
fix/slack-code-block-language-tag
branch
from
July 15, 2026 11:46
0a7b71c to
0550ec0
Compare
Contributor
Author
|
Ported to current
|
z23
force-pushed
the
fix/slack-code-block-language-tag
branch
from
July 15, 2026 12:55
0550ec0 to
eebd3cd
Compare
Slack's mrkdwn does not strip the optional language tag from fenced code blocks like GitHub-flavored markdown does — it renders ```text\nfoo\n``` as a code block whose literal first line is "text". The agent emitted ```text fences around raw command output, which surfaced "text" as the first line of every such block. Drop the tag from the opening fence in format_message() before stashing the block behind a placeholder. Stripping only fires for a genuine opening fence — a ``` at the start of a line, tagged with a single token (no spaces or backticks) — and the original line ending is preserved. The fence-protection regex deliberately matches loosely, so a mid-line ``` (e.g. an inline ```span``` wrapping across a newline) can be grouped as an "opening fence" whose first line is real content; differential fuzzing against the pre-change formatter (40k generated messages) confirms the only behavioral delta is the tag strip itself. The Block Kit renderer is unaffected: render_blocks() intercepts fences itself before mrkdwn_fn is applied, so this only changes the mrkdwn surfaces that still go through format_message() — the plain-text fallback field (notifications, search indexing, accessibility), slash-command ephemeral replies, and standalone cron delivery. Originally written against gateway/platforms/slack.py; ported to plugins/platforms/slack/adapter.py after the adapter migration in 5600105. Manually verified against a live Slack workspace (pre-migration adapter; the ```text case strips identically) — code blocks no longer carry a literal "text" first line.
z23
force-pushed
the
fix/slack-code-block-language-tag
branch
from
July 16, 2026 12:27
eebd3cd to
72eb1fa
Compare
Contributor
|
Merged via #70191 — your commit was cherry-picked/reapplied onto current main with your authorship preserved in git history: your language-tag stripping was cherry-picked with a line-start guard. Thanks for the contribution! |
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.
Summary
Slack's
mrkdwndoes not strip the optional language tag from fenced code blocks the way GitHub-flavored markdown does — it renders the tag as a literal first line of the rendered code block. When the agent emitted```textfences around raw command output (a common LLM habit), every such block in Slack arrived looking like:format_message()"protects" fenced code blocks by stashing them verbatim behind a placeholder, so the language tag survived all the way tochat_postMessage. This PR drops the tag from the opening fence before stashing.Why this is still relevant now that Block Kit rendering is on main
The Block Kit
markdownrendering path (#8552 / #19108) is onmain, but it does not cover this:render_blocks()intercepts fenced code itself (intorich_text_preformatted) and never routes fences throughformat_message(), whileformat_message()remains the producer of every surface that is still plain mrkdwn:response_urlpath);chat.postMessagewithout the in-process adapter);text.Without this fix, all of those surfaces still leak the literal
textline.Changes
plugins/platforms/slack/adapter.pyformat_message()now strips the language tag from the opening fence inside the code-block protection step. Stripping requires a line-start fence and a single-token tag; the original line ending is preserved.tests/gateway/test_slack.py```textcase mirroring the bug, bare/single-line fences left untouched, tags with trailing spaces, CRLF fences (tagged and untagged), mid-line```spans (multi-word and single-token), and back-to-back fences.Test plan
scripts/run_tests.sh tests/gateway/test_slack.py tests/gateway/test_slack_block_kit.py tests/gateway/test_slack_block_kit_adapter.py— 283 passed, 0 failedtests/gateway/run — only pre-existing failures unrelated to this change (WeCom optional XML dependency, a startup-restart race test), reproduced identically on pristinemainmain'sformat_messagevs this branch): no deviation beyond the intended single-token tag strip on line-start fences```textcase is identical): messages from the agent containing```text\n…\n```no longer render a literaltextline at the top of the code blockformat_message()ruff checkclean on both filesTested on
Related: #8552, #19108