Skip to content

WhatsApp adapter adds visible backslashes before literal tildes #908

Closed

Description

@luksch42

Bug Description

In @chat-adapter/whatsapp@4.39.0, outgoing Markdown containing a literal tilde gets an extra backslash. For example, (~80 % easy) is delivered as (\~80 % easy), with the backslash visible in WhatsApp.

The original model output contains no backslash. This reproduces directly in the adapter’s formatter without an LLM or network request.

Steps to Reproduce

  1. Use @chat-adapter/whatsapp@4.39.0 with chat@4.37.0 (our project pins chat via an override).
  2. Run the minimal code sample below with Bun.
  3. Observe that the formatter returns (\~80 % easy) instead of (~80 % easy).
  4. Sending { markdown: "(~80 % easy)" } uses the same converter and includes the unwanted backslash in the outgoing message.

Expected Behavior

The formatter should return (~80 % easy) unchanged. Literal text should arrive without serializer-added Markdown escapes, while supported formatting still converts to WhatsApp syntax. Intentional backslashes and code content should remain intact.

Actual Behavior

The formatter returns (\~80 % easy). The added backslash remains visible in the delivered WhatsApp message.

This also affects multiple tildes: ~45 min, Pace ~6:29/km becomes \~45 min, Pace \~6:29/km.

Code Sample

import { WhatsAppAdapter } from "@chat-adapter/whatsapp";
import { ConsoleLogger, parseMarkdown } from "chat";

const adapter = new WhatsAppAdapter({
  accessToken: "test",
  appSecret: "test",
  phoneNumberId: "test",
  verifyToken: "test",
  userName: "test",
  logger: new ConsoleLogger("silent"),
});

console.log(adapter.renderFormatted(parseMarkdown("(~80 % easy)")));
// Expected: (~80 % easy)
// Actual:   (\~80 % easy)

Chat SDK Version

chat@4.37.0; @chat-adapter/whatsapp@4.39.0

Node.js Version

Not used for reproduction — Bun 1.4.0

Platform Adapter

WhatsApp

Operating System

macOS

Additional Context

The issue appears to originate in packages/adapter-whatsapp/src/markdown.ts:

  1. WhatsAppFormatConverter.fromAst() calls the shared stringifyMarkdown() helper.
  2. That helper uses remark-stringify with remark-gfm. Its strikethrough serializer escapes literal ~ characters.
  3. toWhatsAppFormat() converts bold and strikethrough markers but leaves the Markdown escapes intact.

The whole-string regex conversions also modify formatting markers inside code: **literal** in a fenced code block becomes *literal*.

Activity

  1. v01dst commented on Sep 6, 2026

    @v01dst

    Hi! I'd like to pick this up — could you assign me?

    Plan: prevent remark-stringify from escaping literal tildes in non-strikethrough text (likely a custom serializer option or post-serialization handling), keep intentional escapes and code blocks intact, and add regression tests for single/multiple tildes plus code content.

  2. luksch42 commented on Sep 6, 2026

    @luksch42
    ContributorAuthor

    Pr is open :)

  3. added a commit that references this issue on Oct 7, 2026
    b879ddd
  4. added a commit that references this issue on Oct 19, 2026
    a32470e
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