Skip to content

fix(slack): comprehensive mrkdwn formatting for send, edit, and tool paths#3715

Closed
dashed wants to merge 7 commits into
NousResearch:mainfrom
dashed:fix/slack-mrkdwn-formatting
Closed

fix(slack): comprehensive mrkdwn formatting for send, edit, and tool paths#3715
dashed wants to merge 7 commits into
NousResearch:mainfrom
dashed:fix/slack-mrkdwn-formatting

Conversation

@dashed

@dashed dashed commented Mar 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Normalizes markdown-to-Slack-mrkdwn conversion across all message delivery paths (gateway send, streaming edit, tool-layer direct send). Fixes 6 bugs found during audit against the Slack mrkdwn spec.

Bugs fixed

  • Blockquote markers escaped> at line start was escaped to >, breaking blockquote rendering. Now protected with placeholders before escaping.
  • edit_message() sent raw markdown — streamed/edited messages showed literal **bold** and [links](url). Now calls format_message() before chat_update().
  • ***bold italic*** produced invalid mrkdwn — triple-star was consumed by the bold regex, producing **text**. Added dedicated triple-star step producing *_text_*.
  • HTML entity double-escaping — pre-escaped & became &. Added unescape-before-escape to make the operation idempotent.
  • URLs with parentheses truncated — Wikipedia-style links like Foo_(bar) were cut short. Replaced URL regex with balanced-parentheses matching.
  • Step comment numbering — duplicate step numbers after inserting new steps. Renumbered 1-13.

Other changes

  • Explicitly set mrkdwn: True on chat.postMessage payloads
  • Protect existing Slack entities (<@user>, <#channel>, <!here>, <!subteam^...>, <!date^...>) from escaping
  • Handle CommonMark angle-bracket link syntax [text](<url>)
  • Use idiomatic reversed(dict) instead of reversed(list(dict.keys()))

Test coverage

  • 47 unit tests in TestFormatMessage covering all formatting conversions, entity preservation, edge cases
  • 4 unit tests in TestEditMessage for edit formatting
  • 8 e2e tests in TestEditMessageStreamingPipeline simulating streaming edits
  • 7 e2e tests in TestMessageSplitting for the gateway send path
  • 5 e2e tests in TestSendToPlatformChunking for the tool-layer send path

140 tests pass, 0 failures.

Test plan

uv run --extra dev --extra messaging pytest tests/gateway/test_slack.py tests/tools/test_send_message_tool.py -v
  • All unit tests for format_message() pass
  • All e2e tests for send, edit, and tool paths pass
  • Existing tests unaffected (no regressions)
  • Reviewed against Slack mrkdwn spec

@dashed dashed marked this pull request as ready for review March 29, 2026 12:56
@dashed dashed force-pushed the fix/slack-mrkdwn-formatting branch 3 times, most recently from cefa270 to ad1074d Compare April 4, 2026 17:28
dashed and others added 7 commits April 7, 2026 07:36
Blockquote `>` prefixes at line start were being escaped to `&gt;` by
the control character escaping step, breaking Slack blockquote rendering.
Protect them with placeholders before escaping, matching how entities
and code blocks are already handled. Renumber step comments to be
sequential (1-12). Add unit and e2e tests for blockquote formatting.
…dits

edit_message() was passing raw markdown content to chat_update(), causing
streamed and edited Slack messages to display literal **bold**, [links](url),
and ## headers instead of rendered mrkdwn. Call format_message() before
sending, matching the pattern used by send() and TelegramAdapter.edit_message().
Add unit and e2e tests covering the edit formatting pipeline.
The bold regex was consuming ***text*** and producing **text** (invalid
Slack mrkdwn) because the inner *text* was stashed behind a placeholder
before the italic pass could see it. Add a dedicated triple-star step
before bold conversion that produces *_text_* (Slack bold wrapping
italic). Add unit and e2e tests for bold+italic across send, edit, and
tool paths.
Input already containing &amp;, &lt;, or &gt; was being double-escaped
(e.g. &amp; → &amp;amp;). Unescape known HTML entities before
re-escaping to make the operation idempotent. Add unit and e2e tests
verifying pre-escaped content survives send, edit, and tool paths.
…kdwn tests

Fix link regex to support one level of balanced parentheses in URLs
(e.g. Wikipedia links). Add comprehensive test coverage for Slack entity
preservation (<!channel>, <!everyone>, <!subteam^...>, <!date^...>,
<#C...>), code-only messages, multiline mixed formatting, asterisk
lists, bold-in-link labels, ampersand-in-URL query strings, and emoji
shortcode passthrough.
…tion

Python 3.8+ supports reversed() directly on dicts. Remove unnecessary
list() materialization of placeholder keys.
@dashed dashed force-pushed the fix/slack-mrkdwn-formatting branch from ad1074d to e60fe92 Compare April 7, 2026 11:41
teknium1 pushed a commit that referenced this pull request Apr 9, 2026
Fixes blockquote > escaping, edit_message raw markdown, ***bold italic***
handling, HTML entity double-escaping (&amp;amp;), Wikipedia URL parens
truncation, and step numbering format. Also adds format_message to the
tool-layer _send_to_platform for consistent formatting across all
delivery paths.

Changes:
- Protect Slack entities (<@user>, <https://...|label>, <!here>) from
  escaping passes
- Protect blockquote > markers before HTML entity escaping
- Unescape-before-escape for idempotent HTML entity handling
- ***bold italic*** → *_text_* conversion (before **bold** pass)
- URL regex upgraded to handle balanced parentheses
- mrkdwn:True flag on chat_postMessage payloads
- format_message applied in edit_message and send_message_tool
- 52 new tests (format, edit, streaming, splitting, tool chunking)
- Use reversed(dict) idiom for placeholder restoration

Based on PR #3715 by dashed, cherry-picked onto current main.
teknium1 pushed a commit that referenced this pull request Apr 9, 2026
Fixes blockquote > escaping, edit_message raw markdown, ***bold italic***
handling, HTML entity double-escaping (&amp;amp;), Wikipedia URL parens
truncation, and step numbering format. Also adds format_message to the
tool-layer _send_to_platform for consistent formatting across all
delivery paths.

Changes:
- Protect Slack entities (<@user>, <https://...|label>, <!here>) from
  escaping passes
- Protect blockquote > markers before HTML entity escaping
- Unescape-before-escape for idempotent HTML entity handling
- ***bold italic*** → *_text_* conversion (before **bold** pass)
- URL regex upgraded to handle balanced parentheses
- mrkdwn:True flag on chat_postMessage payloads
- format_message applied in edit_message and send_message_tool
- 52 new tests (format, edit, streaming, splitting, tool chunking)
- Use reversed(dict) idiom for placeholder restoration

Based on PR #3715 by dashed, cherry-picked onto current main.
@teknium1

teknium1 commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

Merged via PR #6809 as part of a consolidated Slack adapter improvement. Your contribution was all 7 commits cherry-picked. Your authorship is preserved in git history. Thank you @dashed for your work on this!

@teknium1 teknium1 closed this Apr 9, 2026
Tommyeds pushed a commit to Tommyeds/hermes-agent that referenced this pull request Apr 12, 2026
Fixes blockquote > escaping, edit_message raw markdown, ***bold italic***
handling, HTML entity double-escaping (&amp;amp;), Wikipedia URL parens
truncation, and step numbering format. Also adds format_message to the
tool-layer _send_to_platform for consistent formatting across all
delivery paths.

Changes:
- Protect Slack entities (<@user>, <https://...|label>, <!here>) from
  escaping passes
- Protect blockquote > markers before HTML entity escaping
- Unescape-before-escape for idempotent HTML entity handling
- ***bold italic*** → *_text_* conversion (before **bold** pass)
- URL regex upgraded to handle balanced parentheses
- mrkdwn:True flag on chat_postMessage payloads
- format_message applied in edit_message and send_message_tool
- 52 new tests (format, edit, streaming, splitting, tool chunking)
- Use reversed(dict) idiom for placeholder restoration

Based on PR NousResearch#3715 by dashed, cherry-picked onto current main.
angelburgosrosado pushed a commit to angelburgosrosado/hermes-agent that referenced this pull request Apr 28, 2026
Fixes blockquote > escaping, edit_message raw markdown, ***bold italic***
handling, HTML entity double-escaping (&amp;amp;), Wikipedia URL parens
truncation, and step numbering format. Also adds format_message to the
tool-layer _send_to_platform for consistent formatting across all
delivery paths.

Changes:
- Protect Slack entities (<@user>, <https://...|label>, <!here>) from
  escaping passes
- Protect blockquote > markers before HTML entity escaping
- Unescape-before-escape for idempotent HTML entity handling
- ***bold italic*** → *_text_* conversion (before **bold** pass)
- URL regex upgraded to handle balanced parentheses
- mrkdwn:True flag on chat_postMessage payloads
- format_message applied in edit_message and send_message_tool
- 52 new tests (format, edit, streaming, splitting, tool chunking)
- Use reversed(dict) idiom for placeholder restoration

Based on PR NousResearch#3715 by dashed, cherry-picked onto current main.
ulasbilgen pushed a commit to ulasbilgen/hermes-adhd-agent that referenced this pull request May 1, 2026
Fixes blockquote > escaping, edit_message raw markdown, ***bold italic***
handling, HTML entity double-escaping (&amp;amp;), Wikipedia URL parens
truncation, and step numbering format. Also adds format_message to the
tool-layer _send_to_platform for consistent formatting across all
delivery paths.

Changes:
- Protect Slack entities (<@user>, <https://...|label>, <!here>) from
  escaping passes
- Protect blockquote > markers before HTML entity escaping
- Unescape-before-escape for idempotent HTML entity handling
- ***bold italic*** → *_text_* conversion (before **bold** pass)
- URL regex upgraded to handle balanced parentheses
- mrkdwn:True flag on chat_postMessage payloads
- format_message applied in edit_message and send_message_tool
- 52 new tests (format, edit, streaming, splitting, tool chunking)
- Use reversed(dict) idiom for placeholder restoration

Based on PR NousResearch#3715 by dashed, cherry-picked onto current main.
02356abc pushed a commit to 02356abc/hermes-agent that referenced this pull request May 14, 2026
Fixes blockquote > escaping, edit_message raw markdown, ***bold italic***
handling, HTML entity double-escaping (&amp;amp;), Wikipedia URL parens
truncation, and step numbering format. Also adds format_message to the
tool-layer _send_to_platform for consistent formatting across all
delivery paths.

Changes:
- Protect Slack entities (<@user>, <https://...|label>, <!here>) from
  escaping passes
- Protect blockquote > markers before HTML entity escaping
- Unescape-before-escape for idempotent HTML entity handling
- ***bold italic*** → *_text_* conversion (before **bold** pass)
- URL regex upgraded to handle balanced parentheses
- mrkdwn:True flag on chat_postMessage payloads
- format_message applied in edit_message and send_message_tool
- 52 new tests (format, edit, streaming, splitting, tool chunking)
- Use reversed(dict) idiom for placeholder restoration

Based on PR NousResearch#3715 by dashed, cherry-picked onto current main.
olympus-terminal pushed a commit to olympus-terminal/hermes-agent that referenced this pull request May 16, 2026
Fixes blockquote > escaping, edit_message raw markdown, ***bold italic***
handling, HTML entity double-escaping (&amp;amp;), Wikipedia URL parens
truncation, and step numbering format. Also adds format_message to the
tool-layer _send_to_platform for consistent formatting across all
delivery paths.

Changes:
- Protect Slack entities (<@user>, <https://...|label>, <!here>) from
  escaping passes
- Protect blockquote > markers before HTML entity escaping
- Unescape-before-escape for idempotent HTML entity handling
- ***bold italic*** → *_text_* conversion (before **bold** pass)
- URL regex upgraded to handle balanced parentheses
- mrkdwn:True flag on chat_postMessage payloads
- format_message applied in edit_message and send_message_tool
- 52 new tests (format, edit, streaming, splitting, tool chunking)
- Use reversed(dict) idiom for placeholder restoration

Based on PR NousResearch#3715 by dashed, cherry-picked onto current main.
gweeteve pushed a commit to gweeteve/hermes-agent that referenced this pull request Jun 2, 2026
Fixes blockquote > escaping, edit_message raw markdown, ***bold italic***
handling, HTML entity double-escaping (&amp;amp;), Wikipedia URL parens
truncation, and step numbering format. Also adds format_message to the
tool-layer _send_to_platform for consistent formatting across all
delivery paths.

Changes:
- Protect Slack entities (<@user>, <https://...|label>, <!here>) from
  escaping passes
- Protect blockquote > markers before HTML entity escaping
- Unescape-before-escape for idempotent HTML entity handling
- ***bold italic*** → *_text_* conversion (before **bold** pass)
- URL regex upgraded to handle balanced parentheses
- mrkdwn:True flag on chat_postMessage payloads
- format_message applied in edit_message and send_message_tool
- 52 new tests (format, edit, streaming, splitting, tool chunking)
- Use reversed(dict) idiom for placeholder restoration

Based on PR NousResearch#3715 by dashed, cherry-picked onto current main.
Egavasyug pushed a commit to Egavasyug/hermes-agent that referenced this pull request Jun 10, 2026
Fixes blockquote > escaping, edit_message raw markdown, ***bold italic***
handling, HTML entity double-escaping (&amp;amp;), Wikipedia URL parens
truncation, and step numbering format. Also adds format_message to the
tool-layer _send_to_platform for consistent formatting across all
delivery paths.

Changes:
- Protect Slack entities (<@user>, <https://...|label>, <!here>) from
  escaping passes
- Protect blockquote > markers before HTML entity escaping
- Unescape-before-escape for idempotent HTML entity handling
- ***bold italic*** → *_text_* conversion (before **bold** pass)
- URL regex upgraded to handle balanced parentheses
- mrkdwn:True flag on chat_postMessage payloads
- format_message applied in edit_message and send_message_tool
- 52 new tests (format, edit, streaming, splitting, tool chunking)
- Use reversed(dict) idiom for placeholder restoration

Based on PR NousResearch#3715 by dashed, cherry-picked onto current main.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants