Skip to content

Slack: bulleted lists and special mentions are lost #956

Description

@szachariah-tl

Bug Description

For an inbound message the adapter builds message.formatted from event.text alone (this.formatConverter.toAst(text) in parseSlackMessage). For messages typed in Slack's composer, event.text is a lossy rendering of the message, and the structure is in event.blocks as a rich_text block. The adapter reads event.blocks to collect link URLs (extractLinks) and, in 4.40.0, to build tables from table / data_table blocks, but not for the message body. Two kinds of content are lost:

  • Lists. A bulleted list made with the composer arrives in event.text as lines starting with , with and four spaces for a nested item. Neither is markdown list syntax, so the result is one paragraph of literal bullet characters. There is no list node, and the nesting indent is dropped on stringifyMarkdown. event.blocks carries the same list as rich_text_list elements with style and indent.
  • Special mentions. <!here>, <!channel>, <!everyone>, and <!subteam^S…|@handle> are not converted by slackMrkdwnToMarkdown. A message containing one parses to an mdast html node, and the raw token appears in both message.text and the markdown. event.blocks carries them as broadcast and usergroup elements.

Steps to Reproduce

  1. In Slack, use the composer's bulleted-list button to send the bot a list with one nested item, followed by a line containing @here and a user-group mention.
  2. Read message.formatted, message.text, and stringifyMarkdown(message.formatted) in the handler, or run the code sample below, which passes an event of that shape to adapter.parseMessage.

Expected Behavior

  • message.formatted contains a list node with two listItem children, the second holding a nested list. stringifyMarkdown gives * one\n* two\n * nested.
  • Special mentions become readable text such as @here and @devs, consistent with how <@U…|name> becomes @name, and the message does not parse to an html node.

Actual Behavior

Output of the code sample on 4.40.0:

nodes   : ["paragraph","html"]
text    : "Steps:\n• one\n• two\n◦ nested\n\n<!here> and <!subteam^S0123456789|@devs>"
markdown: "Steps:\n• one\n• two\n◦ nested\n\n<!here> and <!subteam^S0123456789|@devs>\n"

4.30.0 gives the same nodes and markdown.

Code Sample

import { createSlackAdapter } from "@chat-adapter/slack";
import { stringifyMarkdown } from "chat";

const adapter = createSlackAdapter({ botToken: "xoxb-test", signingSecret: "test" });
const section = (text: string) => ({ type: "rich_text_section", elements: [{ type: "text", text }] });

const message = adapter.parseMessage({
  type: "message",
  channel: "D0123456789",
  channel_type: "im",
  user: "U0123456789",
  username: "jane",
  ts: "1726600000.000100",
  text: "Steps:\n• one\n• two\n    ◦ nested\n<!here> and <!subteam^S0123456789|@devs>",
  blocks: [
    {
      type: "rich_text",
      elements: [
        section("Steps:"),
        { type: "rich_text_list", style: "bullet", indent: 0, elements: [section("one"), section("two")] },
        { type: "rich_text_list", style: "bullet", indent: 1, elements: [section("nested")] },
        {
          type: "rich_text_section",
          elements: [
            { type: "broadcast", range: "here" },
            { type: "text", text: " and " },
            { type: "usergroup", usergroup_id: "S0123456789" },
          ],
        },
      ],
    },
  ],
});

console.log("nodes   :", JSON.stringify(message.formatted.children.map((c) => c.type)));
console.log("text    :", JSON.stringify(message.text));
console.log("markdown:", JSON.stringify(stringifyMarkdown(message.formatted)));

Chat SDK Version

4.30.0

Node.js Version

22.21.1

Platform Adapter

Microsoft Teams, Slack

Operating System

Linux

Additional Context

No response

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions