Skip to content

feat(slack): render agent bodies as native markdown blocks - #654

Open
yzxcj797 wants to merge 1 commit into
yc-software:mainfrom
yzxcj797:feat/slack-markdown-blocks-651
Open

feat(slack): render agent bodies as native markdown blocks#654
yzxcj797 wants to merge 1 commit into
yc-software:mainfrom
yzxcj797:feat/slack-markdown-blocks-651

Conversation

@yzxcj797

@yzxcj797 yzxcj797 commented Aug 21, 2026

Copy link
Copy Markdown

Summary

Implements the fix shape from #651 verbatim: every outbound agent body renders once into { text, blocks }text stays the existing toSlackMrkdwn fallback (notifications, mirrorSelfPost cache, older clients), and a single markdown block carries the raw Markdown, where lists, tables, fenced-code languages and CJK-flanked bold translate into native Slack elements instead of character-encoded approximations.

Implementation

  • renderSlackBody(md) in mrkdwn.ts returns both renderings; slackMarkdownBlocks wraps the raw Markdown. The block is emitted only when the body fits SLACK_MARKDOWN_BLOCK_BUDGET = 11,500 — Slack's 12,000 budget applies to the translated result cumulatively, so over-budget bodies fall back to today's text-only path, keeping Markdown-safe chunking (fences, table rows, ordered-list continuity) off the critical path per the issue's note 4.
  • All six agent-body sites render through it:
    • turn-handler.ts — the ack presenter and the turn reply (postReply already accepted blocks);
    • approvals.ts — both result paths; the non-remote card update resends the block (an update with no blocks clears them, per note 5), and postApprovalFollowup threads it; the agent-to-agent completion header is bolded ** for the block and stays * in the text fallback, since *x* is italic in Markdown (note 1);
    • deliveries.ts — both pollers; the channel poller's markdown block replaces its section-block body while the task-list section block survives alongside (per the "a section block sent alongside it survived" measurement), and the principal poller posts it directly.
  • The text fallback path is byte-identical to today, so test/slack-mrkdwn.test.ts's existing expectations are unchanged.

Testing

  • 4 new tests: the helper's contract (raw Markdown in the block, mrkdwn in text; over-budget and blank bodies fall back to text-only; the budget stays under the 12k cap) and a wiring contract asserting every one of the six sites threads the blocks. Differential: with the source changes stashed the suite fails to import; neighbors (slack-delivery, slack-approval-cards, slack-ack-emoji) are 72/72.
  • Note 6's live-scenario assertion (test/live-slack asserting lines) still applies to the text layer, which is unchanged; the native-list layer only appears through the block, which the live suite would need block-structure assertions for — left to that suite's maintainers since it requires a live workspace.

Fixes #651


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Every agent reply left Slack through toSlackMrkdwn posted as text, so
structure was encoded as characters: bullets were literal dots that
lost their hang-indent on wrap, ordered lists passed through as text,
GFM tables became aligned code blocks that misalign on CJK width, and
single-asterisk bold only rendered at half-width boundaries -- a
Chinese-language reply could not reliably use bold at all.

Each outbound body now renders once into { text, blocks }: text stays
the mrkdwn fallback for notifications, mirrors and older clients, and a
single markdown block carries the raw Markdown -- where lists, tables,
code languages and CJK-flanked bold translate into native elements.
Bodies over 11,500 chars (Slack's budget applies to the translated
result, cumulatively) fall back to today's text-only path, keeping
Markdown-safe chunking off the critical path.

All six agent-body sites render through it: the ack presenter and the
turn reply, both approval-result paths (the card update resends the
block, because an update with no blocks clears them), and both delivery
pollers -- the channel poller's markdown block replaces its section-
block body while the task-list section survives alongside. The agent-
to-agent completion header is bolded ** for the block and kept in
mrkdwn * form for the fallback, since *x* is italic in Markdown.

Fixes yc-software#651
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.

Slack replies are mrkdwn text, so lists have no structure and CJK bold prints asterisks

1 participant