vercel / vercel/chat

Slack: bulleted lists and special mentions are lost

Open
#956 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
TypeScript
Stars
2.4k
Forks
314
Avg merge
1d 18h
Merged PRs (30d)
63

Description

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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at parseSlackMessage and slackMrkdwnToMarkdown, comparing how event.text is handled with the rich_text data in event.blocks; extractLinks shows the adapter already reads blocks. Run the supplied adapter.parseMessage example and verify that formatted contains the expected nested list, special mentions are readable, and stringifyMarkdown no longer emits literal bullets or an HTML node.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
75/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.