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
- Use
@chat-adapter/whatsapp@4.39.0 with chat@4.37.0 (our project pins chat via an override).
- Run the minimal code sample below with Bun.
- Observe that the formatter returns
(\~80 % easy) instead of (~80 % easy).
- 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:
WhatsAppFormatConverter.fromAst() calls the shared stringifyMarkdown() helper.
- That helper uses
remark-stringify with remark-gfm. Its strikethrough serializer escapes literal ~ characters.
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*.
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
@chat-adapter/whatsapp@4.39.0withchat@4.37.0(our project pinschatvia an override).(\~80 % easy)instead of(~80 % easy).{ 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/kmbecomes\~45 min, Pace \~6:29/km.Code Sample
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:WhatsAppFormatConverter.fromAst()calls the sharedstringifyMarkdown()helper.remark-stringifywithremark-gfm. Its strikethrough serializer escapes literal~characters.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*.